Arc Forumnew | comments | leaders | submitlogin
Arc for Ruby programmers
5 points by lojic 6140 days ago | 8 comments
I realize there's already a thread for posting snippets of Arc code, but I thought it would be nice to have some language oriented threads. So if you have snippets of Ruby code that you've translated to Arc (one liners or larger), please submit a comment with the Ruby & Arc versions.

I'll start with a snippet that began life as Logo on Brian Harvey's home page, and was then translated to 13 or so languages here:

http://lojic.com/blog/2007/08/31/logo-ruby-javascript/

In Ruby, it was:

  def choices menu, sofar=[]
    if menu.empty?
      puts sofar.join(' ')
    else
      menu[0].each {|item| choices(menu[1..-1], sofar + [item]) }
    end
  end
  choices [['small', 'medium', 'large'],
    ['vanilla', 'ultra chocolate', 'lychee', 'rum raisin', 'ginger'],
    ['cone', 'cup']]
My first draft in Arc is:

  ; Join elements of lst separated by sep into a string
  ; (must be a better way to do this)
  (def joinstr (lst (o sep " "))
    (if lst
      (string (car lst) (apply string (map [string sep _] (cdr lst))))
      ""))

  ; Cartesian product of elements of menu
  (def choices (menu (o result '()))
    (if menu
      (each x (car menu) 
        (choices (cdr menu) (cons x result)))
      (prn (joinstr:rev result))))

  (choices (list
    (list "small" "medium" "large") 
    (list "vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger")
    (list "cone" "cup")))


2 points by fallintothis 6140 days ago | link

I think you're looking for prall, defined in arc.arc:

  (def prall (elts (o init "") (o sep ", "))
    (when elts
      (pr init (car elts))
      (map [pr sep _] (cdr elts))
      elts))
Then, you save a function and choices becomes more like:

  (def choices (menu (o result '()))
    (if menu
        (each x (car menu)
          (choices (cdr menu) (cons x result)))
        (prall (rev result) "\n" #\space)))
If having that newline at the beginning of the output is killing you, then you could also use it inside of a do:

  (def choices (menu (o result '()))
    (if menu
      (each x (car menu) 
        (choices (cdr menu) (cons x result)))
      (do (prall (rev result) "" " ") (prn))))

-----

3 points by lojic 6140 days ago | link

Cool. I also just discovered that apparently Arc#join is CL#append, so I could use join instead of cons and skip the rev.

-----

3 points by lojic 6140 days ago | link

  ; Cartesian product of elements of menu
  (def choices (menu (o result '()))
    (if menu
      (each x (car menu)
        (choices (cdr menu) (join result (list x)))) 
      (prall result "\n" " ")))     

  (choices (list
    (list "small" "medium" "large")
    (list "vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger")
    (list "cone" "cup")))

-----

2 points by fallintothis 6140 days ago | link

Ah, I was wondering why append wasn't working, haha. Now I recall reading the source about how Robert Morris thought it was better to overload + for join -- which still seems to work, by the way.

Also, come to think of a nit-picky issue, optional args will default to nil = '(), so you could just as well say:

  (def choices (menu (o result))
    (if menu
        (each x (car menu)
          (choices (cdr menu) (+ result (list x))))
        (prall result "\n" " ")))
Not that it matters all that much.

One artifact I notice is that, since it returns nil but is only printing a newline at the beginning, the printout ends with "large ginger cupnil". I suppose, to avoid that in the repl, you could slap a (prn) at the end of the function definition or use the aforementioned (do ...) block. I got to thinking it might also be nice to have a prnall, but then I noticed that this is just prn:

  (def choices (menu (o result))
    (if menu
        (each x (car menu)
          (choices (cdr menu) (+ result (list x))))
        (apply prn (intersperse " " result))))
Though this could be cleaner with prnall:

  (def prnall args
    (do1 (apply prall args) (prn)))
At any rate, all these thoughts are very pedantic -- but then, so am I.

-----

4 points by chrisdone 6140 days ago | link

  (choices '(("small" "medium" "large") 
             ("vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger")
             ("cone" "cup")))

-----

1 point by lojic 6140 days ago | link

Thanks. I can't remember my motivation for the more verbose form way back when - probably misguided.

-----

1 point by povman 6140 days ago | link

(Basically) the same program in Haskell (sans a couple of import statements):

  choices [] sofar = putStrLn (intercalate " " sofar)
  choices menu sofar = forM_ (head menu) (\item -> choices (tail menu) (item:sofar))
  main = choices [["small", "medium", "large"], ["vanilla", "ultra chocolate", "lychee", "rum raisin", "ginger"], ["cone", "cup"]] []
bring on the converts!

-----

1 point by bOR_ 6139 days ago | link

(( Working on translating a small model I was building from ruby to arc, but as I'm a lisp newb it's taking some time. Will post it here in time coming. ))

-----