Arc Forumnew | comments | leaders | submit | vsingh's commentslogin
2 points by vsingh 4153 days ago | link | parent | on: Two arithmetic ideas

This seems very complicated, and confusing. Unless your code is heavily math-oriented, it doesn't seem like a win. Even in that case, you would lose the ability to easily move and factor subexpressions, one of the things I prize most in Lisp.

I also foresee problems with code that looks like infix but doesn't actually have the operator precedence rules of infix, especially with the interaction between (1) and (2). We really don't need to lose more spaceships. ;)


2 points by vsingh 4398 days ago | link | parent | on: Chalk one up for Arc

Ha! That's fantastic. Nice to see you're still around here, too. I've been taking a break from Arc for a while (job search, recently completed). I'm still working on something related to our little LOOP tiff a while back. Just you wait, it's gonna be great! :)


2 points by vsingh 4461 days ago | link | parent | on: much much better arc logo

I still like the one with the 5 dots better.


1 point by vsingh 4480 days ago | link | parent | on: Special Forms objects on arc git

Can you provide an instance in which this is useful?


1 point by vsingh 4485 days ago | link | parent | on: First Class Special Forms?

Macros are source-code transformers. How is 'if' a macro?


1 point by greatness 4485 days ago | link

IF is a macro because you don't always want to evaluate all of it's arguments...


3 points by kens 4485 days ago | link

I don't want to be pedantic, but 'if' is a special form and not a macro:

  arc> if
  Error: "reference to undefined identifier: _if"
  arc> and
  #3(tagged mac #<procedure>)
It's the basis for other "partial evaluation" macros.

My foundation documentation ( lists the special forms.


2 points by greatness 4484 days ago | link

err, I was refering to the way it executed. I believe On Lisp implemented an if macro.


2 points by Darmani 4483 days ago | link

A conditional such as if can only be implemented as a macro if it expands to another conditional such as cond, which must be implemented as a special form.

In Arc, if is just a special form.


3 points by absz 4483 days ago | link

I think the logic is to make if a "primitive macro," the way + is a primitive function. Just as you can't define + in terms of Arc functions, you can't define if in terms of Arc macros. Nevertheless, (isa + 'fn), and so the thinking is that (isa if 'mac) makes sense.

There are valid reasons not to do things this way, of course. For instance, what's so powerful about macros is that they literally expand into a code tree, which (as you observed) if can't do. For that reason, why not have (isa if 'form) (or 'prim, or 'special, or something similarly descriptive)? Then you have first-class special forms without literally making them macros. This would be a big improvement over the current state of affairs:

  arc> (type if)
  Error: "reference to undefined identifier: _if"



1 point by mecon 4483 days ago | link

That's what i meant.


1 point by zxquarx 4483 days ago | link

If can be implemented as a primitive function instead of a special form given the fn operator. It could take three arguments: a condition, a then function, and an else function and then call the appropriate function. An example implementation is:

(def if2 (cond then else) (if cond (then) (else)))

If2 would be given as a primitive function and its implementation would be hidden like that of cons is. Given access to if2, a basic if construct is:

(mac basic-if (cond then (o else)) `(if2 ,cond (fn () ,then) (fn () ,else)))

This would make code walkers easier because they wouldn't have to know about as many special forms.


3 points by vsingh 4486 days ago | link | parent | on: Exemplary examples of LOOP

Kenny Tilton submitted:

   (loop for y in whatever
         for py = (pfft y)
         when py collect (yo-mama (cons y py)))
The Arc solution is required to be roughly as efficient as the above code.


4 points by vsingh 4486 days ago | link

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 4485 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 4485 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 4485 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 4485 days ago | link

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

      (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 4485 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 4484 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)))


3 points by raymyers 4486 days ago | link

In cases anyone wants to take the efficiency thing seriously, this is what we are up against:
And mind you, we don't even have one of those fancy-pants `goto' things.


1 point by kennytilton 4486 days ago | link

That reminds me, I ended up reinventing Cells over the table in Arc because the real deal was so big it would have been a heckuva project, but I started on the actual code and... whoa! I have one chunk I found easiest to express as a very simple state machine using Common Lisp's tagbody/go and I had very little confidence in my conversion to a functional solution.


2 points by kennytilton 4486 days ago | link

No, I did not submit this. Bad form, old chap.

I chose not to submit anything, because it would just turn into a silly game. If I wanted to make my point, I would simply itemize all the capabilities of loop, but that would be too big a task.

Delete everything but the "Pfft!" and you have my contribution.


6 points by kennytilton 4486 days ago | link

Here's my damn submission:

  (defun ix-render-oblong (lbox thickness baser slices stacks)
  (unless slices (setq slices 0))
  (unless stacks (setq stacks (if (zerop thickness)
                                  0 (min 10
                                      (max 1  ;; force 3d if nonzero thickness
                                        (round (abs thickness) 2))))))
  (when (eql (abs thickness) (abs baser))
    (setf thickness (* .99 thickness)))
  (trc nil "oblong" baser thickness etages)
    with theta = (/ pi 2 slices)
    with etages = stacks ;; french floors (etages) zero = ground floor
    with lw/2 = (/ (r-width lbox) 2)
    with lh/2 = (/ (r-height lbox) 2)
    with bx = (- lw/2 baser)
    with by = (- lh/2 baser)
    for etage upto etages
    for oe = 0 then ie
    for ie = (unless (= etage etages)
               (* (/ (1+ etage) etages)
                 (/ pi 2)))
    for ii = (if (not ie)
                 0 ;; throwaway value to avoid forever testing if nil
               (+ (* (abs thickness)
                    (- 1 (cos ie)))))
    for ox = lw/2 then ix
    for oy = lh/2 then iy
    for oz = 0 then iz
    for oc = (cornering baser slices) then ic
    for ic = (when ie
               (cornering (- baser ii) slices))
    for ix = (- lw/2 ii)
    for iy = (- lh/2 ii)
    for iz = (when ie
               (* thickness (sin ie)))
    do (trc nil "staging" etage ie)
    (gl-translatef (+ (r-left lbox) lw/2)(+ (r-bottom lbox) lh/2) 0)

    (with-gl-begun ((if ie
      (loop for (dx dy no-turn-p)
          in '((1 1)(-1 1)(-1 -1)(1 -1)(1 1 t))
            ;;for dbg = (and (eql dx 1)(eql dy 1)(not no-turn-p))
            do (destructuring-bind (xyn0 ix0 iy0 ox0 oy0) 
                   (cons (+ (if oc (/ theta 2) 0)
                           (ecase dx (1 (ecase dy (1 0)(-1 (/ pi -2))))
                             (-1 (ecase dy (1 (/ pi 2))(-1 pi)))))
                     (if oc
                         (case (* dx dy)
                           (1 (list (* dx ix)(* dy by)(* dx ox)(* dy by)))
                           (-1 (list (* dx bx)(* dy iy)(* dx bx)(* dy oy))))
                        (list (* dx ix)(* dy iy)(* dx ox)(* dy oy))))
                 ;; --- lay-down start/only -------------
                 (when ie
                   (ogl-vertex-normaling ie xyn0 ix0 iy0 iz))
                 (ogl-vertex-normaling  oe xyn0 ox0 oy0 oz)
                 (trc nil "cornering!!!!!!----------------" dx dy)
                 ;; --- corner if slices and not just finishing strip
                 (unless no-turn-p
                   (trc nil "------ start ------------------" (length oc)(length ic))
                   (loop for (oxn . oyn) in oc
                       for icrem = ic then (cdr icrem)
                       for (ixn . iyn) = (car icrem)
                       for xyn upfrom (+ xyn0 theta) by theta
                          do (macrolet
                                 ((vtx (elev gx sx gy sy gz)
                                       (when (minusp (* dx dy))
                                         (rotatef ,sx ,sy))
                                       (ogl-vertex-normaling ,elev xyn
                                         (incf ,gx (* dx ,sx))
                                         (incf ,gy (* dy ,sy))
                               (trc nil "ocn icn" oxn oyn (car icrem))
                               (when icrem
                                 (vtx ie ix0 ixn iy0 iyn iz))
                               (vtx oe ox0 oxn oy0 oyn oz)))))))
    (gl-translatef (- (+ (r-left lbox) lw/2))
      (- (+ (r-bottom lbox) lh/2)) 0)))
Macroexpand that. :)


4 points by kennytilton 4486 days ago | link

"I would simply itemize all the capabilities of loop, but that would be too big a task."

Oooh, look! Someone did it for me:


2 points by vsingh 4485 days ago | link

Sorry about that! I overassumed. I'd change it to "vsingh submits the following" but it won't let me edit it anymore.

Thanks for your new contribution.


1 point by kennytilton 4485 days ago | link

New contribution?! That was a joke, a painful transliteration of a couple of pages of graph paper formulas and diagrams working out the parameterized construction of a 3-dimensional button out of insanely small OpenGL atoms, including the torturous calculation of normals to support lighting.

I steered this thread to the Common Lisp Hyperspec entry on loop. By reading that and examining your own use of Arc iterators you can deduce how it can express them all more briefly and with fewer parens. That immediately helps the hacker over one bump... when it is time to iterate I type "(loop " without thinking and just take it from there -- no worrying about whether it is a sequence, list, or hash table, or whether I will need temp variable to be defined in a let/with statement, loop includes a mechanism for that, etc etc etc...


4 points by vsingh 4486 days ago | link | parent | on: Confusing Macro Error

That looks like a bug to me. This works fine:

    (mac myfn body
        `(fn ,(cons 'frst 'rest) ,@body))


1 point by mec 4486 days ago | link

Thanks! That fix also allowed me to get (_ . __) to work for [] as well which was giving the same error. Now, time to play around with multivar anonymous functions.\

Edit: Well never mind then, that change doesn't work in brackets.scm either so back to just playing with the macro.


2 points by vsingh 4486 days ago | link | parent | on: Seaside-Style Programming in ErlyWeb

"Is it just me, or are continuations in Seasside/Arc's web server just a manual and explicit way to recreate Erlang's cheap concurrency?"

I'd say they're two facets of the same thing. Like objects and closures.


2 points by vsingh 4486 days ago | link | parent | on: symbol macros, please?

Didn't Paul call Loop one of the worst mistakes in Common Lisp? I doubt the man is going to change his mind on this one.

Loop may minimize parentheses (i.e. nesting), but then again, so does BASIC. I'd say the main reason it isn't "Arcy" is that it fails the simplicity-of-implementation test.


2 points by kennytilton 4486 days ago | link

I think you misunderstand. The "weird" to which I refer is precisely pg's anti-(cl)-loopism. He should love loop not just for the brevity, but also because it is a triumph of DSL. ie, CL loop is a DSL for iteration, and I know because I use it for everything. But! pg seems closer to being a schemer at heart so maybe he prefers recursion for things I handle by iteration.

ps. Are you saying BASIC eliminates parentheses the same way LOOP does? :)


1 point by vsingh 4486 days ago | link

It's hard for me to see Loop as a triumph of DSL. I see it more as a failure of Common Lisp to provide simple flexible iteration constructs.

Arc already seems to provide simple operators for many of the cases in which Loop is commonly used. For example: 'accum', 'for', and 'repeat'. It doesn't seem like we need Loop.

Re BASIC: In a way, yes. Both BASIC and Loop use keywords to replace the indication of structure by parentheses. For example, we could eliminate a pair of brackets in 'with' by doing this:

    (with x 2 y 3 z 4 endvars
        (+ x y z))
but that wouldn't be very Lispy.


2 points by kennytilton 4486 days ago | link

Well I resisted Loop for almost ten years then broke down and learned it when PCL came out cuz it had a good chapter on it, so having made the transition I can assure you it is a powerful little iteration language, not just a simple iterator of which CL has many so it is not clear what you do not like about those. I'll ignore your continued insistence that BASIC has anything to do with this discussion. :)

Btw, loop offers a little-known second syntax that is Lispy, one just never sees examples in the wild.


2 points by vsingh 4486 days ago | link

If you have found through long experience that Loop truly offers something unique that can't be offered as well (or as intelligibly) by a combination of simpler operators, then I'll have to take your opinion seriously.

I've made a thread to collect exemplary examples of Loop in action ( and it'd be great if you could contribute your favorites, e.g. from Cells or other code you've written.

Personally, I don't have the same experience as you. I've found Loop to be useful as a replacement for iteration constructs that should have been in CL to begin with, e.g. dovector, when I'm too lazy to code the requisite macro. I haven't ever had to use Loop in its full complexity.


4 points by kennytilton 4486 days ago | link

Sorry, it just sounds from what you have posted so far that you do not know CL's loop, by which I mean make an effort to use all of its capabilities such that you would know what's there so well that you had it at your fingertips. I am having the same problem with CL idiots denouncing Arc who probably have not even installed it.

You want me to code (dotimes (x 10) (foo))?! No way!

  (loop repeat 10 do (foo)). 
And that is not even a good example!!

  (let (x)
     (dolist (y whatever (nreverse x))
        (let ((py (pfft y)))
           (when py
               (push (yo-mama (cons y py)) x)))
Egad! How about:

   (loop for y in whatever
         for py = (pfft y)
         when py collect (yo-mama (cons y py)))
Is the first version starting to look like a disassembly? Bingo!!! :)

btw, the thing that got me to break down and give loop a chance was learning that the expansion was highly optimized code, meaning (for example) it would not first map across whatever and then delete the nils.

but these examples still do not get to the point of LOOP being a DSL. That property emerges only in the next level of application, as even the loop form expands to ten lines. But once you have loop under your belt (I kill myself) you do not even want to code a simple dotimes, that bogus unused count variable just pisses you off no end, never mind all the extra (wait for it) parentheses!

pg, phone home, all is forgiven! :)


2 points by vsingh 4486 days ago | link

That looks interesting. I've submitted that example to my thread.


4 points by vsingh 4496 days ago | link | parent | on: Ruby-like in place list expansion

Your solution is not sufficiently general.

For example, it should keep working if the 'a' in (+ . a) is replaced with its actual value. In that case, we get:

    (+ . '(1 2 3))
which is the same thing as saying

    (+ . (quote (1 2 3))
which is equivalent to

    (+ quote (1 2 3))
which obviously doesn't do the same thing as

    (apply + '(1 2 3))
which is what you wanted.


1 point by bogomipz 4488 days ago | link

That means (+ . (1 2 3)) does what you want, doesn't it?

Granted, to do the equivalent of (+ @(foo)) you would have to do;

  (let temp (foo)
       (+ . temp))
Which is not very nice at all, so I'm not arguing against @. On the contrary.

Edit: I used to think that . and @ would only differ in the sense that cons and splice have different list building semantics, but now I believe that they should also differ in the timing of the operation;

  (+ . (foo))  -> (+ foo)
  (+ . '(foo)) -> (+ quote foo)
  (+ @(foo))   -> what we want, given that foo returns a list
  (+ @'(foo))  -> (+ 'foo)