Arc Forumnew | comments | leaders | submitlogin
Show us your Arc code
17 points by parenthesis 6140 days ago | 28 comments
Post interesting little functions and macros for others to learn from, and/or improve on.


12 points by icemaze 6140 days ago | link

This one is my personal favorite:

  (mac >> body
    `(let it ,(car body)
       ,(if (cdr body) `(>> ,@(cdr body))
            'it)))
It works a little bit like CL's let* but is anaphoric and it's much easier to read. It's a pipeline: each expression is evaluated and it is bound to the result for the next expression to use. Example:

  (>> '(1 2 3 4 5)
      (keep odd it)     ; -> (1 3 5)
      (map [* 4 _] it)  ; -> (4 12 20)
      (cons 6 it)       ; -> (6 6 14 22)
      (reduce + it))    ; -> 42
It's very convenient sometimes. Plus, since most of Arc's functions have their main argument at the end (thanks devteam!) it could be modified so that it appends "it" to every expression in the body. This depends on how it's used in the real world.

-----

5 points by noahlt 6140 days ago | link

Am I missing something, or is this just an easier way to write:

  (reduce + (cons 6 (map [* 4 _] (keep odd '(1 2 3 4 5)))))

-----

3 points by icemaze 6140 days ago | link

You are right: it just improves readability.

-----

1 point by ehird 6138 days ago | link

Ridiculous:

    (def ablast (l)
      (if (no (cdr l))
          nil
          (cons (car l) (ablast (cdr l)))))

    (def replc (x y l)
      (if (atom l) (if (is x l) y l)
          (no l) nil
          (is x (car l)) (cons y (replc x y (cdr l)))
          (acons (car l)) (cons (replc x y (car l)) (replc x y (cdr l)))
          (cons (car l) (replc x y (cdr l)))))

    (mac imp body
      (if (no body) nil
          (replc 'it `(imp ,@(ablast body)) (last body))))

-----

3 points by sjs 6140 days ago | link

I'm still digging through the source, haven't done any coding yet. But...

There is a function called 'isnt' I did not see mentioned in the tutorial.

  arc> (isnt 1 2)
  t
Also an 'empty' function that's true for nil, empty lists and strings.

There's subseq, which is sort of like nthcdr but works on lists and strings (any sequence), and takes the seq before the n.

  arc> (subseq "uh, hello world" 4)
  "hello world"
  arc> (subseq (coerce "uh, hello world" 'cons) 4 9)
  (#\h #\e #\l #\l #\o)
'last' gets you the last value in a cons.

  arc> (last '(fee fie foe fum))
  fum
'adjoin' inserts a value into a set, unless already present.

  arc> (adjoin '(1 2) '((5 3) (1 2) (7 4)))
  '((5 3) (1 2) (7 4))
  arc> (adjoin 1 '(2 3 4))
  (1 2 3 4)
'consif' conses a value if it's not nil.

  arc> (consif 'sugar '(coffee cream))
  (sugar coffee cream)
  arc> (consif nil '(coffee milk))
  (coffee milk)
The complement of 'when', pg snuck 'unless' into the arc.arc excerpt at the end.

Make sure you read *.arc after the tutorial to really get a feel for the language.

-----

4 points by rkts 6140 days ago | link

I translated into Arc a little program I wrote a few months ago to compare the distribution of characters in Qwerty vs. Dvorak by hands, fingers, etc. It currently outputs text; the next step of course is to output HTML.

http://benstoker.com/code/lytcmp.arc

http://benstoker.com/code/lcex.txt

Getting the program to work was a bitch as there doesn't seem to be any debugging support at all. Nevertheless, I'm extremely pleased with the language itself.

The utility at the beginning reflects the only serious issue I ran into: objs don't seem to be able refer to themselves. I had to write a new obj macro that binds the current object to 'this'.

Also, although it's not a serious problem, I'd love to be able to refer to obj fields with a simpler syntax, e.g. x.foo instead of (x 'foo). In particular, that quote before the field name is kind of a wart.

-----

5 points by simonb 6140 days ago | link

From another thread:

  (def strip (lst str)
    (rem [some _ lst] str))
  
  arc> (strip "abc" "aghbcdt")
  "ghdt"
  arc> (strip "" "aghbcdt")
  "aghbcdt"
  arc> (strip () "aghbcdt")
  "aghbcdt"
  arc> (strip '(#\a #\t) "aghbcdt")
  "ghbcd"

-----

1 point by simonb 6139 days ago | link

A tail recursive map1:

  (def map1 (f xs (o acc))
    (if (no xs) 
        acc
        (map1 f (cdr xs) (cons (f (car xs)) acc))))
Inspired by andf and orf (one predicate applied many operands):

  (def orl (f)
    (fn xs (some f xs)))

  (def andl (f)
    (fn xs (all f xs)))
It would be interesting to see which is the more common case and change built-in predicates to except multiple operands accordingly.

-----

3 points by chaos 6140 days ago | link

Because I'm reddit-damaged:

    (def unfold (f x)
      (let res (f x)
        (if res
            (cons (car res) (unfold f (cdr res)))
            ())))

    (def romanize (i)
      (let r '((M 1000)(CM 900)(D 500)(CD 400)(C 100)(L 50)(XL 40)(X 10)(IX 9)(V 5)(IV 4)(I 1))
        (unfold 
         (fn ((i . ((r n) . rst)))
             (if (is i 0)
                   ()
                 (>= i n)
                   (cons r (cons (- i n) `((,r ,n) . ,rst)))
                   (cons "" (cons i rst))))
         (cons i r))))
    (apply string (romanize 999))

-----

1 point by parenthesis 6139 days ago | link

  (def prime (n)
    (if (~isa n 'int) nil
        (< (= n (truncate n)) 2) nil
        (is n 2) t
        (multiple n 2) nil
        (with (div 3
               lim (truncate (sqrt n))
               result t)
          (while (and (or (~multiple n div)
                          (= result nil))
                      (< div lim))
            (++ div 2))
          result)))

-----

1 point by parenthesis 6137 days ago | link

-- Actually, spot the bug!

-----

5 points by rcoder 6140 days ago | link

For those who want a slightly less-complete webapp to use as a sample:

  (= fortune-bin-path* "/usr/games/fortune" page-title* "Read My Fortune")

  (def make-fortune-cookie ()
    (tostring (system fortune-bin-path*)))

  (defop fortune req
    (whitepage
      (tag h1 (link page-title* "fortune"))
      (br 2)
      (tag pre (pr (make-fortune-cookie)))
      (br 2)
      (tag small
        (link "[made with arc]" "http://arclanguage.org/"))))

-----

1 point by albertcardona 6140 days ago | link

For illustration, would you mind explaining how to connect this code to a web server.

-----

2 points by rcoder 6140 days ago | link

You don't have to connect it. Copy the above into a file called 'fortune.arc' inside your Arc source code directory, then type the following from an Arc REPL:

  (load "fortune.arc")
  (asv)
The 'asv' function spawns the built-in web server, as shown in the blog example.

-----

1 point by albertcardona 6137 days ago | link

Sometimes the program fails with the error below, on clicking on the link. A blank webpage is shown. After F5 (refresh), all back to normal.

Looks to me, that the system call fails because 'fortune' returns -1.

  date: 1202019843: No such file or directory
  make-string: expects argument of type <non-negative exact integer>; given -1

  === context ===
  subseq
  memodate
  srvlog
  gs899
  handle-request-thread

-----

2 points by mdemare 6140 days ago | link

List monad in Arc:

    (def list-monad (seq . fns)
      (each f fns 
        (= seq (apply join (map f seq))))
        seq)

    (list-monad '(1 2 3 4 5) 
      [list (- _ 1) _] 
      [list (* 2 _) _])

-----

6 points by parenthesis 6140 days ago | link

With this you can do things like (s ls -l) or (s clear) or (s mzscheme -m -f as.scm) etc..

  (mac s args
  `(system ,(apply string (map [string _ " "] args))))

-----

2 points by chaos 6139 days ago | link

Maybe I'm the last one to notice withs as let* replacement, maybe not.

Simulated Annealing: http://dpaste.com/hold/33337/

-----

1 point by offby1 6139 days ago | link

This is a tad bigger than "little", but I'm fond of it: http://polyglot-anagrams.googlecode.com/svn/trunk/arc/

-----

3 points by sjs 6140 days ago | link

Standard stuff...

    (= sum [apply + _])
    (= prod [apply * _])
I went to create a range function, but it was already there. It's like python's range:

    arc> (range 37 42)
    (37 38 39 40 41 42)
There's also intersperse, familiar to Haskell coders, but only works on conses.

    arc> (intersperse 0 '(42 21 7 1))
    (42 0 21 0 7 0 1)
There is much more in arc.arc.

-----

3 points by fallintothis 6140 days ago | link

range is useful, though I kept making the goof-up of trying to pass only one arg as in Python. So, I went ahead and changed it:

  (let orig range
    (def range (x (o y))
      (if y
          (orig x y)
          (orig 0 x)))) ;could be (orig 0 (- x 1)) to be even more Python-like
Come to think of it, you could instead do something like this to be the most like Python (whether or not that's a good thing):

  (def range (start (o end) (o step 1))
    (let test (if (positive step) >= <=)
      (when (no end)
        (= end start 
           start 0))
      (if (test start end)
          nil
          (cons start (range (+ start step) end step)))))

  arc> (range 10)
  (0 1 2 3 4 5 6 7 8 9)
  arc> (range 10 1)
  nil
  arc> (range 1 10)
  (1 2 3 4 5 6 7 8 9)
  arc> (range 1 10 2)
  (1 3 5 7 9)
  arc> (range 1 10 -2)
  nil
  arc> (range 10 1 -2)
  (10 8 6 4 2)
  arc> (range 10 1 -1)
  (10 9 8 7 6 5 4 3 2)
This same idea of having the "step" parameter maps nicely into subseq syntax in Python, as I noted in this thread: http://www.arclanguage.org/item?id=479

-----

1 point by icemaze 6139 days ago | link

Everybody seems to be in love with the step parameter. Would it be such an improvement over (for instance):

  (reverse (range 10)), or
  (map [* 2 _] (range 5)) ?
Do python guys use it that often?

-----

1 point by Xichekolas 6139 days ago | link

Yeah I'd much rather compose functions than have extra parameters to remember... but I'm not a Python guy either.

-----

1 point by apgwoz 6139 days ago | link

It's pretty inefficient to use reverse, if instead you can add an extra parameter, though I guess it's often negligible.

-----

1 point by mk 6139 days ago | link

I think this is right.

  arc> (def quadratic (a b c)
             (= minus-b (- 0 b))
             (= radical (sqrt (- (* b b) (* 4 a c))))
             (= divisor (* 2 a))
             (= root1 (/ (+ minus-b radical) divisor))
             (= root2 (/ (- minus-b radical) divisor))
             (cons root1 root2))

-----

4 points by aidenn0 6140 days ago | link

Playing around with strings-as-sequences I wrote the obligatory rot13:

  (def rot13 (s)
    (with (a (coerce #\a 'int))
     (map [coerce (+ a (mod (- (coerce _ 'int) a 13) 26)) 'char] s)))

-----

2 points by abstractbill 6140 days ago | link

Pretty obvious, but I couldn't live without dolist:

  (mac dolist ((iter seq) . body)
       `(map (fn (,iter)
                 ,@body)
             ,seq))

-----

7 points by pg 6140 days ago | link

I think each is what you want.

-----