Arc Forumnew | comments | leaders | submit | absz's commentslogin
2 points by absz 5781 days ago | link | parent | on: Afn with

I like this:

  (mac w/rfn (name withses . body)
    `(rfnwith ,name ,(mappend [list _ _] withses) ,@body))

  (mac w/afn (withses . body)
    `(w/rfn ,withses ,@body)
I have something like this for obj, actually, which I use for creating structure-like tables:

  (mac nobj args
    " Creates a table from the list of variables passed to it; each variable's
      name is keyed to its value.  E.g. if x = 10 and y = -10, then (nobj x y)
      results in #hash((y . -10) (x . 10)).
      See also [[obj]] [[table]] "
    `(obj ,@(mappend [list _ _] args)))

-----

2 points by conanite 5781 days ago | link

don't forget the name parameter to w/rfn in w/afn

  (mac w/afn (withses . body)
    `(w/rfn self ,withses ,@body)

-----

1 point by absz 5781 days ago | link

Whoops, you're right. My bad.

-----

5 points by absz 5795 days ago | link | parent | on: Afn with

I like it! It's like Scheme's "named let", which I did miss. Actually, on that note, what about rfnwith:

  (mac rfnwith (name withses . body)
    (let w (pair withses)
      `((rfn ,name ,(map car w) ,@body) ,@(map cadr w))))

  (mac afnwith (withses . body)
    `(rfnwith self ,withses ,@body))

-----

1 point by conanite 5795 days ago | link

even better :)

-----

5 points by absz 5801 days ago | link | parent | on: Proposal for LET

This has come up before; see particularly http://arclanguage.org/item?id=6759 . The reason you can't just do this is that Arc supports list destructuring on variable binding; to wit,

  (def stats (data)
    (list (reduce + data) (avg data)))
  
  (let (sum avg) (stats '(1 2 3 4 5))
    (prn (string "sum = " sum ", avg = " avg)))
  
  ; Output: sum = 15, avg = 3
Thus, even if the first argument is a list, let has well-defined semantics. An alternative in the thread I linked to is to remove the implicit do (either modifying let or creating a new macro given), which never requires parenthesizing the arguments but requires an explicit do if its body contains more than one statement; I still think is is a good idea.

-----

1 point by tc-rucho 5801 days ago | link

Ouch, didn't know abut this. Thanks a ton.

-----

2 points by absz 5809 days ago | link | parent | on: Search functionality for this forum?

There's also always Googling for "site:arclanguage.org QUERY", which is what I do.

-----


Ditto, except I write

  (case
    a-short     (b ...)
    c-very-long (d ...)
                (e ...))
when everything is on one line, and

  (case
    a-short
      (b ...)
    c-very-long
      (d ...)
    ; else
      (e ...))
when it doesn't (though I go back and forth about the ; else).

-----

1 point by shader 5814 days ago | link

Your first version is the one currently implemented by ppr.arc. If you would like, you can write the indentation function for your second version (it can even include the "; else")

Otherwise I think that the first version is generally clearer, and the second is rarely needed, as the value of the case statement can't usually be very long. Could you give me an example where you use your second version?

-----

1 point by absz 5814 days ago | link

Sure; here's something from my tagged-unions.arc on Anarki (Arc 2). It's responsible for parsing the types specified for slots in the tagged union:

  (each type-frag types
    ; Assemble the ('type name) pairs into two lists, so that we can iterate
    ; through them.
    (case (type type-frag)
      ; If it's a symbol, then we're defining a new name; add a new set of
      ; values, and go.
      sym
        (do
          (zap [cons type-frag _] names)
          (zap [cons nil       _] values))
      ; Otherwise, we're adding a value to an existing variant.
      cons
        ; I changed my mind about the order (now it's (name pred?) instead of
        ; (pred? name)), so I'm reversing it here.
        (zap [cons (rev type-frag) _] (car values))
      ; else
        (err "Invalid member of tagged union declaration.")))
I should also add (just as another data point) that my multi-condition ifs look like that too, and single-condition ifs look like the following:

  (def macexn (n expr)
    " Macroexpand `expr' `n' times.  NB: `expr' *is* evaluated!
      See also [[macex1]] [[macex]] "
    (if (and (number n) (> n 0))
      (macexn (- n 1) (macex1 expr))
      expr))
I'm not hugely wedded to any of my conventions, though, and I haven't coded in Arc for quite a while anyway; this isn't intended to get you to change anything or convert people to my style. As I said, it's just another data point.

-----

1 point by absz 5820 days ago | link | parent | on: Multi character matching, and ssyntaxes

Anarki, at least, supports multi-character ssyntaxes, as I committed a .. ssyntax for range. The pos thing is still a good idea.

As you saw, bad ssyntax crashes because empty parts come out as #<eof>, as you saw; why that happens, I can't tell you. But I can tell you why you can't write things like a!(b c) or pr."test". The reason is that ssyntax (symbol syntax) isn't directly part of the read procedure. Structures like (tab!frob xs.ix) are read in as-is; after this, every symbol is traversed and possibly expanded, producing something like ((tab 'frob) (xs ix)). Thus, a!(b c) is read in as the two objects a! and (b c), and a! is then expanded to (a '#<eof>); similarly, pr."test" is read in as pr. "test", and then becomes (pr #<eof>) "test". Granted, those #<eof>s shouldn't be there---probably a syntax error should be produced instead---but that's what's going on.

-----

1 point by shader 5820 days ago | link

So, maybe an arc implementation of the reader is in order? Then we could have arc level implementation of reader macros too, instead of just ssyntaxes and symbol macros.

-----

1 point by conanite 5820 days ago | link

So far, we have lib/arc-read.pack and lib/parser.arc, both in anarki, as well as lib/parsecomb.arc. Not only do you have your reader, but you have a choice of them too!

arc-read seems to be designed for easy extensibility although I haven't tried it at all. (If I had looked carefully before embarking upon parser.arc, I might have saved myself a lot of trouble).

parser.arc doesn't support the full range of scheme numbers, nor does it support |foo| symbol syntax yet, apart from ||. I'm working on a new version that will hopefully be faster - welder depends on the tokeniser for syntax highlighting.

parsecomb.arc, if I understand correctly, isn't an arc parser but a library for building parsers.

In any case, having an implementation of 'read in arc makes a lot of sense, and it's in the todo at the top of arc.arc

-----

1 point by absz 5822 days ago | link | parent | on: How to make this function simpler?

redef is already in Anarki; arc.arc, line 2446:

  (mac redef (name parms . body)
    " Redefine a function.  The old function definition may be used within
      `body' as the name `old'. "
    `(do (tostring
          (let old (varif ,name nilfn)
            (= ,name (fn ,parms ,@body))))
         ,name))
It's the same as yours, except (a) it suppresses the warning on re-assigning an identifier, and (b) it calls the original function old.

-----

2 points by CatDancer 5822 days ago | link

suppressing the warning doesn't appear to be necessary with =

  arc> (def foo () 3)
  #<procedure: foo>
  arc> (= foo 4)
  4
  arc>

-----

1 point by absz 5822 days ago | link

I was wondering if that was necessary... I think redef used to use set, which is why it was there.

-----

1 point by absz 5824 days ago | link | parent | on: Bind a list of variables

The behaviour of the [] syntax makes perfect sense, if you think about it. First, [...] is just an abbreviation for (fn (_) ...) to save typing.[1] Second, `(...) is just an abbreviation for (quasiquote '(...)). Thus [`(...)] is [(quasiquote ...)], which is (fn (_) ((quasiquote ...)). If [] stripped off the outer layer of parentheses, then [+ _ 1] would become (fn (_) + _ 1), which is clearly wrong. Thus, we see that it makes more sense to use fn, since the whole point of [] and ` is to save typing and make code clearer, neither of which they can do here.

Another, possibly nicer, way to think about it is that [] just represents a delayed function call; you're trying to delay an object, and since [] is a function call, you're calling it instead. Either way, the point is that this is the consistent and desirable way for [] to work.

[1]: On Anarki, you also get _1, _2, etc., and __ for varargs, but that's not important for this discussion.

-----

1 point by shader 5824 days ago | link

Yep. Unfortunately, in this case it's practically shorter, and more readable, to use the fn form:

  (fn (_) `(= ,_ ,form))
because you don't have to type out the whole name "quasiquote".

-----

1 point by Adlai 5823 days ago | link

Just a little curious idea:

What about a special syntax (for this one situation), where you can put the backquote thus: [` = ,_ ,form] which would read-macro-expand to (fn (_) `(= ,_ ,form))

I guess it's just a question of how common this problem is, and how difficult it would be to implement this type of read-macro. I guess brackets.scm goes on my list of files to check out...

-----

2 points by absz 5911 days ago | link | parent | on: Arc cgi script that connects to postgresql?

I can't help you with the SQL, but I can give you a formatting tip: to get

  code formatted like this,
surround your code block with a blank line on each side and indent each line of code by at least two spaces.

-----

2 points by justgord 5910 days ago | link

  (prn "thanks absz")

-----

2 points by absz 5921 days ago | link | parent | on: Anonymous macros

That's not the case; apply doesn't care how many arguments the function takes. Take map (which takes a mandatory argument and a rest parameter) and map1 (which takes two mandatory arguments):

  arc> (help map)
  (from "arc.arc")
  [fn]  (map f . seqs)
   Applies the elements of the sequences to the given function.
      Returns a sequence containing the results of the function.
      See also [[each]] [[mapeach]] [[map1]] [[mappend]] [[andmap]]
      [[ormap]] [[reduce]] 
  arc> (map list '(1 2 3) '(4 5 6))
  ((1 4) (2 5) (3 6))
  arc> (apply map list '((1 2 3) (4 5 6)))
  ((1 4) (2 5) (3 6))
  arc> (apply map (list list '(1 2 3) '(4 5 6)))
  ((1 4) (2 5) (3 6))
  
  arc> (help map1)
  (from "arc.arc")
  [fn]  (map1 f xs)
   Return a sequence with function f applied to every element in sequence xs.
      See also [[map]] [[each]] [[mappend]] [[andmap]] [[ormap]] 
  arc> (map1 [* 2 _] '(1 2 3))
  (2 4 6)
  arc> (apply map1 (list [* 2 _] '(1 2 3)))
  (2 4 6)
As long as the last argument to apply is a list, you're golden.

-----

2 points by shader 5921 days ago | link

Interesting. I was wondering if that might be the case.

So I guess that we don't need an anon. macro for that ;)

I'm also wondering whether we would ever actually want an anonymous macro, since often they turn out to be so general purpose that you might want to make a utility out of it.

Does arc have symbol macros?

-----

4 points by absz 5921 days ago | link

I'm not really clear on what an anonymous macro would do. Transform code? If we're writing it in one place, we can just transform it right there. Can you give a usage example?

And no, Arc only has ordinary macros and ssyntax. Though actually---and this just occurred to me now---you can use ssyntax to create symbol macros. For instance, I have the following in a library file

  (= mac-seval $)
  
  (add-ssyntax-bottom
    @    (par apply R)
    $    (fn lists (apply map R lists))
    @    apply
    $    mac-seval)
The first two let me write (@func arg1 restargs) instead of (apply func arg1 restargs) and ($func xs) instead of (map xs). However, this $ makes the $ macro misbehave, and so I added ssyntax turning @ into apply and $ into the original $ macro. It turns out that this technique is fully generic, since ssyntax essentially does a find-and-replace on symbols:

  arc> (= defsym add-ssyntax-top)
  #3(tagged mac #<procedure>)
  arc> (defsym RANDOM (rand))
  t
  arc> RANDOM
  0.5548165450808223
  arc> RANDOM
  0.15745063842035198
  arc> (= things '(alpha beta gamma))
  (alpha beta gamma)
  arc> (defsym THING1 (car things))
  t
  arc> THING1
  alpha
  arc> (= THING1 'one)
  one
  arc> things
  (one beta gamma)
  arc> (defsym NOISY (do (prn 'HI) nil))
  t
  arc> NOISY
  HI
  nil
  arc> (car NOISY)
  HI
  nil

This is actually really nifty, even if it's an unintended side effect. On some level, though, I'm not fully convinced of the value of this---it seems a bit omnipresent. Then again, Common Lisp works fine with them, so perhaps they're fine for Arc too. Are there naming conventions for symbol macros in Common Lisp? I used capital letters above just because I wanted some distinguishing mark.

There are a couple of caveats: first, every time you run add-ssyntax-top, you'll add another entry to the ssyntax table instead of overwriting the old one, so redefinition will make ssyntax slower if it's done too much. Second, the five tokens R, r, L, l, and ... are all unavailable, even if quoted; they turn the given string into modifying ssyntax, not standalone ssyntax. Still, this is a new option I hadn't thought about yet.

-----

More