Arc Forumnew | comments | leaders | submitlogin
4 points by vsingh 5904 days ago | link | parent

Here's my Arc solution:

    (mappend [awhen (pfft _) (list (yo-mama (cons _ it)))] whatever)
The implementation of mappend in arc.arc is currently very inefficient, but it could easily be fixed to bring this code on par with the LOOP version.


3 points by kennytilton 5903 days ago | link

See my point? Even in this incredibly simple iterative task you are forced into a clever trick leveraging how append works and then totally artificially taking each thing you want to collect and wrapping it in a list of one.

Looked at another way, you are not really going out and getting lists of variable length and then appending them, you are just using this trick to avoid collecting nils.

In this case the issue is not efficiency, it is that the loop DSL provides a more natural way for the developer to express themself. Now scale this to a loop that does three things at once, perhaps partitioning a list into several while counting or summing something else and the non-loop version explodes in complexity exponentially while the loop version gracefully grows linearally. (Say that three times fast.)

-----

3 points by vsingh 5903 days ago | link

I got a little carried away with being clever in that version. But look at the canonical Arc version:

   (rev:accum collect
      (each y whatever
         (awhen (pfft y) (collect (yo-mama (cons y it))))))
This version is pretty straightforward in expressing my intent.

As for the scaling issue, I'm still thinking about your other example. I'm not sure it's a good thing that Loop allows more and more to be tacked on. Subroutines in imperative-style languages like C++ have the same agglutinative property, and we're all familiar with the results of that.

-----

1 point by kennytilton 5903 days ago | link

Where on earth in your intent was reversal? Either the semantic or the run-time cost (ie, now you have introduced an efficiency issue that was not there with mappend/list.

You cannot win this fight, find a white flag, run it up. Why can you not win? Because loop the DSL was written with the most common iterative design patterns in mind, and hard-coded to make them both more succinct, more efficient, and to play well with other iterative patterns we occasionally want to run merged as one iteration.

This is what DSLs are for! Read On Lisp. We build the language up to our requirements. Loop is about iteration, and Lisp stands for list-processing. 2+2 left as an exercise. :)

-----

3 points by vsingh 5903 days ago | link

I suppose I ought to have written it like this the first time:

   (w/collect
      (each y whatever
         (awhen (pfft y) (collect (yo-mama (cons y it))))))
'w/collect' being the first new operator to result from our discussion.

-----

1 point by kennytilton 5903 days ago | link

"w/collect' being the first new operator to result from our discussion."

Oh. Where can I find w/collect? And do you mean it has been added to Official Arc? I must be missing out on the action.

-----

4 points by almkglor 5902 days ago | link

It's not on the arc-wiki. However I can certainly imagine how it would look like as a naive implementation:

  (mac w/collect body
    `(rev:accum collect ,@body))
Here's a slightly more optimized form which removes the need to reverse and adds only one additional variable to the environment built by accum:

  (mac w/collect body
    (w/uniq (hd tl)
      `(let (,hd ,tl collect) nil
          (= collect
            (fn (x)
              (if hd (do (= (cdr tl) (cons x nil)) (= tl (cdr tl)))
                      (do (= hd (cons x nil)) (= tl hd)))
               x))
          ,@body
          ,hd)))

-----