Arc Forumnew | comments | leaders | submit | kennytilton's commentslogin
2 points by kennytilton 6555 days ago | link | parent | on: Arc's defset : a little anti-arc?

So write defun the Arc macro, the symbol seems to be available. Have it accept (= <??>) as the first param and expand into the defset boilerplate. And it is boilerplate, I simplified arccells client code by cutting/pasting the defset I found for car. Don't forget optional and keyword args. :)

The larger point is that it is exceedingly rare to code a (setf ???) form in CL, tho of course when you want it it totally rocks. But in Arc or CL when I need to get the hood up to do some brown belt coding I expect some unusual wiring to appear.

-----

2 points by cooldude127 6555 days ago | link

I think I will, when I have the time, write a macro in Arc to simplify this.

I'm surprised you say that writing a setf in CL is rare. Perhaps because usually CLOS is doing the work for you?

-----

1 point by kennytilton 6555 days ago | link

Oh, it is not just CLOS. defstruct also defines setters and many an apparent reader function is also a writer, (so we call them accessors). That means one does not fire up (defun (setf foo)...) unless there is an usual case of abstraction where there is some function on an object (not just reading a slot) and where there is some state change intelligibly viewed as being transitive aka share the name with the reader.

In re writing a defun, I probably just talked you out of it, but here is what I did (warning, old nooby Arc code) for optional and keyword args:

  (mac defun (name params . body)
   (w/uniq (rtargs)
    `(def ,name ,rtargs
       (withs ,(with (reqs nil key? nil opt? nil keys nil opts nil without)
                (each p params
                  (if (is p '&o) (do (assert (no opt?) "Duplicate &o:" ',params)
                                     (assert (no key?) "&k cannot precede &o:" ',params)
                                   (= opt? t))
                    (is p '&k) (do (assert (no key?) "Duplicate &k:" ',params)
                                   (= key? t))
                    key? (push-end p keys)
                    opt? (push-end p opts)
                    (do (assert (~acons p) "Reqd parameters need not be defaulted:" p)
                        (push-end p reqs))))
                (with (n -1 kvs (uniq))
                  (+ (mappend [list _ `(nth ,(++ n) ,rtargs)] reqs)
                    (mappend [list (carif _) `(or (nth ,(++ n) ,rtargs)
                                                ,(cadrif _))] opts)
                    (list kvs `(pair (nthcdr ,(++ n) ,rtargs)))
                    (mappend [list (carif _)
                               `(or (alref ,kvs ',(carif _))
                                       ,(cadrif _))] keys)
                    )))
         ,@body))))

-----

7 points by cooldude127 6555 days ago | link

also, i find myself not using clos or defstruct all that much in my cl code. i tend to use ordinary data structures like lists and arrays.

my recent example (an excerpt from which i already showed) was a sudoku solver. i wrote one version in CL, then thought i'd do it in arc for fun. in CL, the puzzles were simply arrays (in Arc, they were lists do to the lack of an array type).

However, i didn't want my code to use the array (or list) accessors built into the language to access values in the puzzle, because that is not abstract enough. so i defined a function called pval that takes the puzzle and an x and y, giving the value in that square. that way, my code deals with puzzles, not arrays.

Then I wanted to be able to set the value in a square using the same pval accessor. Trivial in CL, but Arc made it a little difficult. This comes up rather often for me.

That point might not have justified such a long explanation. Whoops.

-----

2 points by cooldude127 6555 days ago | link

all i really intend to do is a simple def= macro that will transform (def= pval (val puz x y) (= ((puz y) x) val)) into the previously given defset form. shouldn't be too bad. i have no intentions of mimicing CL's defun. i honestly like arc's def as it is.

-----


It varies. Req3 can be a second, then Req4 another twenty, or Req4 and Req5 can be a second and then a killer.

And now I have a meta-concern: Arc's poster boy is the web thingy and in going on a day yours (thx!) is the only response on it being effectively unusable. Whassup with that? I was looking forward to doing a kickass integration of Cells and Arc's webbery. :(

-----

4 points by kens 6555 days ago | link

I gave up (temporarily) on running Arc's web server under Windows, due to various problems (http://arclanguage.org/item?id=1531). My impression is that Windows support is "immature", based on the (system "some Unix command") scattered through the code.

-----

3 points by kennytilton 6555 days ago | link | parent | on: Exemplary examples of LOOP

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 6555 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 6555 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 6555 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 6555 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 6555 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)))

-----


1. You have eight, not 10 :)

2. "Arc lists are terminated with nil, rather than '()." is odd, because nil and '() are the same. Maybe modify the preceding remark to be "Arc uses t and '()/nil for true and false..." and lose this altogether.

-----

7 points by tjr 6555 days ago | link

But then he'd only have seven.

-----

3 points by kennytilton 6555 days ago | link

But Arc is an exercise in minimalism...hang on. pg is being pounded for Arc being too close to Lisp to be hundred-yeary, maybe we should pad the numbers. :)

-----


"Is the use of this type of pattern language something required to make hygienic macros work or is it just a design choice that the Scheme implementors made?"

Great minds wonder alike. Check out the "What's up with Scheme macros?" thread I kicked off on comp.lang.lisp. I do believe you will like I be sorry you asked. :)

I think somewhere in the dozens of treatises is the response "design choice", but I also think that response was challenged (surprise! surprise!). But I am just a working application programmer and I could not understand very much of what they were saying.

I did get a kick out of one shocked Schemer insisting something was trivial and then posting a twenty-line solution which at one point had a form beginning with four (!) left parens.

-----

6 points by Jekyll 6556 days ago | link

Kenny's right.

Pattern matching is completely orthogonal to hygiene.

You could add in another operator, %, that performs exactly the same as ` but hygienically. Personally I'd settle for just being able embed procedures in code trees like you can in common lisp. Being able to write.

  (let this (fn (x) x)
     (mac na-na-na(y)
      `(,this ,y))) ;Can't touch "this". It's lexically bound.
Allows you to fake hygiene in the common cases where it's needed most often.

-----

2 points by nlavine 6555 days ago | link

Hygienic macros do not require pattern-matching, as proven by the example of MIT scheme. Basically, macros in their system take three arguments - an s-expression, the environment the s-expression is being evaluated in, and the environment the macro is written in - and return syntax, which is an s-expression where you've chosen explicitly for each variable what environment it should be evaluated in. (More or less. If you're interested, it's called syntactic closures and you can probably find stuff about it online, or I can just write more here if people want.) I don't remember any way to insert a free identifier, but it might be there.

By the way, arc can already do half of that if you put (procedure? x) into literal.scm. The harder part is making variable references to things that aren't procedures, and I'm not quite sure how you'd do that (except the really annoying way, by wrapping everything in a procedure application).

SRFI-72 is another proof, as someone posted below, and might be better than syntactic closures (I don't know).

-----

1 point by akkartik 6555 days ago | link

http://groups.google.com/group/comp.lang.lisp/browse_thread/...

-----

1 point by kennytilton 6556 days ago | link | parent | on: Exemplary examples of LOOP

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 6556 days ago | link | parent | on: Exemplary examples of LOOP

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 6556 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)
      
  (loop
    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
                        gl_quad_strip
                      gl_polygon))
      
      (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)
                                    `(progn
                                       (when (minusp (* dx dy))
                                         (rotatef ,sx ,sy))
                                       (ogl-vertex-normaling ,elev xyn
                                         (incf ,gx (* dx ,sx))
                                         (incf ,gy (* dy ,sy))
                                         ,gz))))
                               (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 6556 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:

http://www.lispworks.com/documentation/HyperSpec/Body/m_loop...

-----

2 points by vsingh 6555 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 6555 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...

-----

3 points by kennytilton 6557 days ago | link | parent | on: Python-like generators in arc

I think the suggestion was just phrased a little awkwardly.

Lisp is so easy to program that it is commonplace to reinvent builtins -- they are as easy to write as they are to find (especially in an, er, mildly documented language).

I went proactive on reinvention thang and invited people to let me know of things I had reinvented. Somewhat tangentially, I also make an effort to use things like [... _ ...] and func.arg to give pg's ideas a fair test and so my Arc code can help other noobs get up to speed on the language. If I stay as close as I can to my preferred Common Lisp, like someone writing C in Common Lisp neither I nor anyone else gets a feel for Arc. But I digress.

-----

7 points by kennytilton 6557 days ago | link | parent | on: NewLISP anyone?

I do not see any problem with sharing word of another Lisp option in this space as long as it does not turn into a drumbeat. But what do you mean by "goodbye Arc"? It does not sound like you tried it. As for newLISP:

newLISP does not support sharing of subobjects among objects, cyclic structures, nor multiple variables pointing to the same object. Objects are (physically) copied when stored in data structures or passed to functions

Scary.

-----

2 points by th00ster 6556 days ago | link

I just seem to have found the functional programming language of my dreams, just before arc was released...

Although a lot of the issues you guys have with NewLISP sound serious enough, I admit.

-----

2 points by tjr 6554 days ago | link

The only times I've seen folks here talk bad (or really even talk at all) about NewLISP is when someone specifically asks about it. I don't think anyone here is out to destroy NewLISP, or to stop people from using it. If it works for you, then go for it!

-----

3 points by kennytilton 6557 days ago | link | parent | on: Docs?

Yes, because it is not a fixed target (still evolving) tho it sure would be nice to have. :)

fwiw, Here is another link: http://arcfn.com/foundation-doc.html

-----

More