Arc Forumnew | comments | leaders | submit | fallintothis's commentslogin

I can't help but feel this is the wrong way to approach the problem. Even if you got your current definition working, there are too many ways for it to break. e.g.,

  (isdef (table [for i 1 3 (= _.i (* i i))]))
reads in as

  (isdef (table (fn (_) (for i 1 3 (= _.i (* i i))))))
and fails. There's the special form fn (neither lexically nor globally bound), plus the tricky business of checking defined when compiling fn so that _ is actually lexically bound (otherwise, it appears to be undefined). Same goes for expanding the for macro and i, I imagine.

All this parsing / partial compilation smacks of over-engineering. Even if you avoid multiple-evaluation issues, it seems too easy to make a typo in the middle of a contextual each like

  (myeach (table [for i 1 3 (= _.i (* i u))])
    (prn _))
where u is undefined, meaning it tries to destructure the table expression against (prn _), leading to confusing errors:

  arc> (each (table [for i 1 3 (= _.i (* i u))]) (prn _))
  Error: "Can't understand fn arg list 1"
The syntax for this each you're trying to write is suspect. From a certain angle, it almost seems like trying to overload on arity even though both forms take an unlimited number of values (on account of the rest parameters).

For all I know about Perl (which isn't much), it looks like its foreach works with explicit and implicit variables because you can consistently parse it -- you always have parentheses delimiting the array.

  foreach $item (@items) { print $item; }
vs

  foreach (@items) { print $_; }
If that's the case, the equivalent doesn't map cleanly over to Arc, since the syntax for

  (each item items (prn item))
looks effectively the same as

  (each items (prn _))
to the parser.

I know it's probably not what you want, but perhaps you could consider something with a more regular syntax?

  (mac myeach ((var expr) . body)
    (when (no expr)
      (= expr var var '_))
    `(each ,var ,expr ,@body))

  arc> (myeach ('(1 2 3)) (prn _))
  1
  2
  3
  nil
  arc> (myeach (v '(1 2 3)) (prn v))
  1
  2
  3
  nil
  arc> (myeach ((k v) '((a 1) (b 2) (c 3))) (prn k ": " v))
  a: 1
  b: 2
  c: 3
  nil
  arc> (myeach ((k v) (table [for i 1 3 (= _.i (* i i))])) (prn k ": " v))
  2: 4
  1: 1
  3: 9
  #hash((3 . 9) (1 . 1) (2 . 4))
  arc> (myeach ((table [for i 1 3 (= _.i (* i i))])) (prn _))
  (2 4)
  (1 1)
  (3 9)
  #hash((3 . 9) (1 . 1) (2 . 4))
  arc> (macex1 '(myeach (a b) c))
  (each a b c)
  arc> (macex1 '(myeach (a) b c))
  (each _ a b c)
  arc> (let v 2 (myeach (v '(1 2 3)) (prn v)))
  1
  2
  3
  nil
  arc> (let lst '(1 2 3) (myeach (lst) (prn _)))
  1
  2
  3
  nil
The extra parentheses are kind of ugly when you have expressions (e.g., a call to table), but I find that I'm most often iterating over variables anyways. Or you could rely on the Scheme reader recognizing curly-braces as parens:

  arc> (myeach {x (range 1 5)} (prn x))
  1
  2
  3
  4
  5
  nil
Sorry I don't have any better suggestions.

-----

1 point by palsecam 5948 days ago | link

> too many ways for it to break

> The syntax for this each you're trying to write is suspect

> perhaps you could consider something with a more regular syntax?

You're right. The more I think about it, the less I like this 'each idea.

> All this parsing / partial compilation smacks of over-engineering.

True, but this is also part of the fun here ;-)

> For all I know about Perl (which isn't much), it looks like its foreach works with explicit and implicit variables because you can consistently parse it -- you always have parentheses delimiting the array.

You are absolutely right here, and you made me realize I am actually trying to get something more dirty/complicated than in Perl, which is... really not a good sign :-D!

> Or you could rely on the Scheme reader recognizing curly-braces as parens

This is also an interesting option. Good to know.

> Sorry I don't have any better suggestions.

Gosh, that's already a bunch of good ideas! Thanks!

-----

4 points by fallintothis 5949 days ago | link | parent | on: Bug or lisp gotcha?

Tends to be a Lisp gotcha with quoted things, which act more like pointers than explicit copies.

  $ mzscheme
  Welcome to MzScheme version 360, Copyright (c) 2004-2006 PLT Scheme Inc.
  > (define (foo s)
      (let ((a '(3)))
        (set-car! a (cons s (car a)))
        (car a)))
  > (foo 3)
  (3 . 3)
  > (foo 3)
  (3 3 . 3)
Note that

  arc> (def foo (s) (let a (list 3) (= (car a) (cons s (car a)))))
  #<procedure: foo>
  arc> (foo 3)
  (3 . 3)
  arc> (foo 3)
  (3 . 3)
since list copies data.

-----

1 point by akkartik 5949 days ago | link

Ok, makes sense. Thanks!

-----

2 points by fallintothis 5951 days ago | link | parent | on: Macro expansion/evaluation problem

  (mac myeach (first expr . body)
    (if (errsafe (eval first)) ; questionable, but essentially what 'defined did
                               ; just happens at expansion instead of compilation
        `(each _ ,first ,expr ,@body)
        `(each ,first ,expr ,@body)))

  arc> (myeach '(1 2 3) (prn _))
  1
  2
  3
  nil
  arc> (myeach v '(1 2 3) (prn v))
  1
  2
  3
  nil
  arc> (myeach (k v) '((a 1) (b 2) (c 3)) (prn k ": " v))
  a: 1
  b: 2
  c: 3
  nil
  arc> (myeach (k v) (table [for i 1 3 (= _.i (* i i))]) (prn k ":" v " "))
  2:4
  1:1
  3:9
  #hash((3 . 9) (1 . 1) (2 . 4))
  arc> (myeach (table [for i 1 3 (= _.i (* i i))]) (prn (car _) ":" (cadr _) " "))
  2:4
  1:1
  3:9
  #hash((3 . 9) (1 . 1) (2 . 4))
  arc> (macex1 '(myeach a b c)) ; note: a is undefined
  (each a b c)
  arc> (= a '(1 2 3))
  (1 2 3)
  arc> (macex1 '(myeach a b c)) ; note: a is now defined
  (each _ a b c)
  arc> (let v 2 (myeach v '(1 2 3) (prn v)))
  1
  2
  3
  nil
Any better?

-----

1 point by palsecam 5951 days ago | link

Thanks for the proposal! Very interesting.

However, 'eval is not perfect.

   arc> (let lst '(1 2 3) (myeach lst (prn _)))
   Error: "reference to undefined identifier: __"  
   ; ^ lst was taken for the variable to bind
   ; and (prn _) for the sequence to traverse

   arc> (= glst '(1 2 3))
   (1 2 3)
   arc> (eval 'glst)  ; global scope, OK
   (1 2 3)
   arc> (let lst '(1 2 3) (eval 'lst))  ; lexical scope, KO
   Error: "reference to undefined identifier: _lst"

-----

1 point by fallintothis 5951 days ago | link

Which is what makes a macro like this so hairy: the inconsistency.

There are the lexical bindings you want to use as iteration variables

  (let v 2 (myeach v '(1 2 3) (prn v)))
and the ones you want to iterate over

  (let lst '(1 2 3) (myeach lst (prn _)))
Something about having your cake, eating it, etc.

Maybe what you want to do is specialize on whether the second parameter evaluates to an iterable object?

I'm not sure if, by the time anyone got the separate cases working, I'd like seeing this in use -- complexity creep.

-----

2 points by palsecam 5951 days ago | link

> Which is what makes a macro like this so hairy: the inconsistency.

Yes.

> There are the lexical bindings you want to use as iteration variables [...] and the ones you want to iterate over

Yes "context" stuff. See Perl.

> Maybe what you want to do is specialize on whether the second parameter evaluates to an iterable object?

Yes, it may be a way.

> don't know if I'd like seeing this in use -- complexity creep.

You are certainly wise here :-).

But you know, I don't care of 'each. It's OK if in current Arc it is too tricky to have, and I don't try anymore to have it work my way. It will anyway always be tricky and whether something like this should be used is another debate.

Actually what I care more about is the 'if behaviour. Everyone here seems to ignore this eventual issue and focus on the precise problem of 'each, but this was not my point initially.

-----

2 points by fallintothis 5951 days ago | link

ignore this eventual issue and focus on the precise problem of 'each

Certainly. It was in the back of my head when I wrote my reply. I didn't mention it because I was trying to be terse (I have a problem being long-winded), so opted to focus on something small in my post.

But I agree: macroexpansion time is kind of fuzzy in Arc. It even gets in the way of things like

  arc> (let do [+ _ 1] (do 1 2 3))
  3
which has been a source of hand-waving for awhile with no clear answer: http://arclanguage.org/item?id=9696. But that's another story (in a manner of speaking).

Not to pick on the intended each behavior (after all, why bother writing code if you don't like how it looks?) or the actual topic of this post.

-----

1 point by palsecam 5951 days ago | link

Thanks for the link and (let do ...) example. Interesting to read.

> macroexpansion time is kind of fuzzy in Arc

Well, this was the point of this post! It is important to know about the "limits" of your macros system. As CatDancer mentioned it, there are differences between them. The catch phrase "macros are evaluated at expansion time, functions at runtime, ..." is too simplistic and doesn't provide enough knowledge at some point.

> why bother writing code if you don't like how it looks?

You, Sir, are a wise man :-)!

-----

7 points by fallintothis 5955 days ago | link | parent | on: Starting up with Arc

The link to "Other Versions" on PLT's main download page is a bit non-obvious, but it's there: http://download.plt-scheme.org/all-versions.html

I'm guessing v372 for Ubuntu probably works on Debian, since they're largely similar. If it doesn't, I've been running v360 on squeeze and haven't noticed any issues with arc3. Failing either of these, you could build v372 yourself.

Once MzScheme is installed, there's not much to do about Arc that's not already on http://www.arclanguage.org/install. You might consider aliasing it in your .bashrc (or whatever), and I recommend using rlwrap. e.g.,

  alias arc='cd ~/arc3; rlwrap mzscheme -m -f as.scm'
Good luck!

-----

2 points by palsecam 5955 days ago | link

I confirm: v372 for Ubuntu works also with Debian Squeeze (testing) i686, without modification (I run it).

Direct link: http://download.plt-scheme.org/plt-372-bin-i386-linux-ubuntu....

Actually it's not a .deb package to install with dpkg, it's a self-installer.

-----

2 points by edeion 5954 days ago | link

Thanks palsecam! (btw, are you French?)

I would add (for other potential readers) that it is a very neat self-installer that makes it possible to install in user directory (so that it doesn't spread on the whole system).

What's more, this i386 version worked smoothly despite my amd64 kernel.

-----

1 point by palsecam 5954 days ago | link

Yes I'm French. How did you guess? The username?

Good to know it works without problem on x64. Thanks for this precision and good luck with Arc!

-----

1 point by edeion 5953 days ago | link

Right, the username. Someone who figured out I was French (a space slipped before a question mark) on a lisp-related IRC chan told me there were many French Lispers. I wonder how many we actually are.

-----

1 point by conanite 5953 days ago | link

Hey, I live in Paris ... are any of you nearby? Who wants to meet up in the real world?

-----

2 points by edeion 5953 days ago | link

In Paris too, and I'd be glad to meet some other lispers. Especially since I'm still in the early process of learning Lisp. But I guess we should find another way of dealing with IRL meetings than the forum...

-----

1 point by conanite 5953 days ago | link

to borrow an idiom, (prn "conan" #\@ "conandalton.net")

-----

1 point by palsecam 5953 days ago | link

Mine is in my profile.

-----

4 points by Arubis 5949 days ago | link

If you're running your 'arc' alias from TextMate or the like, this won't much matter, but if you're just executing in Bash, something like:

  alias arc='pushd ~/arc3; rlwrap mzscheme -m -f as.scm ; popd'
...will return you to the directory from whence you came. Which is nice.

-----

1 point by palsecam 5949 days ago | link

Oh yes, I didn't remember of pushd/popd!

Really handy in this case.

Thanks for the tip!

-----

2 points by edeion 5955 days ago | link

Great! Thank you so much, I indeed missed the link on PLT's download page. I'll try it as soon as I'm back home (I can't wait). And thanks for the rlwrap tip too!

-----


I also noticed this error back when I ported quasiquote from GNU clisp (http://arclanguage.org/item?id=9962). I was happy to find that the port fixed this bug when I similarly made a macro-defining macro where the newly-defined one took a rest parameter. Small world.

-----

1 point by conanite 5956 days ago | link

I was also happy to find rainbow doesn't have this issue either ... but I'm putting that down to luck :))

small world indeed

-----


MzScheme has mzc, which does bytecode compilation. You can create something like standalone executables by embedding a copy of MzScheme into the module you're compiling. See http://download.plt-scheme.org/doc/372/html/mzc/ for more details.

Using some work done on Anarki (http://github.com/nex3/arc/blob/dca901c0cb59ebb533a511df3a84... and http://github.com/nex3/arc/blob/dca901c0cb59ebb533a511df3a84...), you could throw together something like:

test.arc

  (prn "Hello, world")
arc-exe-init.scm

  (module arc-exe-init mzscheme
    (provide (all-from-except mzscheme read read-syntax)))
test.arc.scm

  (module test.arc "arc-exe-init.scm"

    (require "ac.scm")
    (namespace-require "ac.scm")
    (require "brackets.scm")
    (use-bracket-readtable)

    (aload "arc.arc")
    (aload "libs.arc")

    (aload "test.arc") ; or the output of (acompile "test.arc") could work
  )
Then

  $ mzc --exe test test.arc.scm
  mzc version 360, Copyright (c) 2004-2006 PLT Scheme Inc. 
  [output to "test"]
  $ ./test
  Hello, world
The results you get hardly seem worth the effort. With this, you'd still need to distribute with some form of ac.scm et al.

  $ mv test ~/Desktop/
  $ cd ~/Desktop/
  $ ./test
  default-load-handler: cannot open input file: "~/Desktop/ac.scm" (No such file or directory; errno=2)

   === context ===
  #f::352: loop
There are probably smarter ways of compiling that don't have this hang-up, but in the end you'll still have kind of a large binary with MzScheme embedded.

If you just want the Scheme equivalent of Arc code, Arc already compiles down to Scheme. To get this compiled version (even if you can't run it directly without loading ac.scm, brackets.scm, arc.arc, and libs.arc):

  $ cat test.arc
  (prn "Hello, world")
  $ mzscheme -m -f as.scm
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> :a
  > (acompile "test.arc")
  Hello, world
  #t
  > ^D
  $ cat test.arc.scm
  (ar-funcall1 _prn "Hello, world")

-----

4 points by thaddeus 5957 days ago | link

Not to worried about about mzscheme being embedded as it's only 24MB. This is good to know... I plan to experiment with it a little so thanks for guidance.

T.

-----


Not to clutter my own thread, but these are some issues that I wasn't smart enough to solve before publication. I felt only one of them qualified as a bug, so I posted it to a bitbucket issue tracker: http://bitbucket.org/fallintothis/arc-vim/issues/

Known Issues:

1. The way numbers are highlighted is mostly a hack. Arc, built atop mzscheme, currently inherits the Scheme reader. As such, numbers comply with R5RS syntax, plus some mz extensions. Highlighting is somewhat complicated: reals, rationals, complex numbers, binary, octal, hexadecimal, exponentiation, etc. The way I do it is to programmatically piece together giant, naively-built regular expressions from the R5RS EBNF grammar (modified slightly for mz). Then, each RE is noisier because I wrap them in delimiter REs so that numbers won't highlight when they're in names (like foldl1, 1up, or p2p).

This might make rendering slower versus simpler, naive alternatives (see Scheme & CL highlighting); I've not noticed anything terrible, myself. Having complex numbers & such highlight correctly is awesome, so I'm inclined to stick with the grammar route, if there aren't any major issues. There could be bugs in the way I generate the RE, which would be noticeable if valid numbers didn't highlight. Again, I've not noticed any (save for the ssyntax issue discussed later), but please tell me if you do.

2. I make overzealous use of display in the Vimscript, guessing at when it should be okay to use (the documentation isn't that clear). Not sure if there are bugs here, though they might also be mitigated with different synchronization methods. You'd notice this issue if, while scrolling through a file, Vim suddenly "runs out of colors" -- highlighting everything like a string or a comment, even though the region ended somewhere above your cursor. It's an easily overlooked problem (once you jar Vim into highlighting correctly), but one I don't like much: it's hard to replicate or know what's wrong. I've not noticed any problems like this for awhile, though.

3. There are some difficult edge-cases for highlighting ssyntax vs valid numbers. See http://bitbucket.org/fallintothis/arc-vim/issue/1/highlighti... for the full explanation.

4. The g:arc_bodops option requires that Vim is compiled with Python support because I couldn't figure out a way that wasn't convoluted to iterate through regular expression matches in a buffer. Seems gross to rely on Python, but I don't know how you can beat

  for line in vim.current.buffer:
      m = re.match(regex, line)
with Vimscript. Suggestions are welcome.

After this, it's worth noting that number (and ssyntax) highlighting is still pretty accurate. It correctly highlights the following, even though you might not be able to tell at first glance what the right behavior is supposed to be:

  #e#x+e#s+e@-e#l-e                                                         ; a
  16140901064495857664-50176i.#e#x+e#s+e@-e#l-e                             ; b
  #b#e101010101111101010101201010101010000010101                            ; c
  127.0.0.1                                                                 ; d
  +inf.0@3+4i                                                               ; e
  +inf.0                                                                    ; f
  1.+i                                                                      ; g
  _.1.3                                                                     ; h
  16140901064495857664-50176.0i!#e#x+e#s+e@-e#l-e:+inf.0@1/1###.##0e4/2i+hi ; i

Whereas with the Scheme highlighter: (a) incorrectly rejects, (b) incorrectly accepts, (c) rejects for the wrong reason (more than one # mark), (d) incorrectly accepts, (e) rejects for the wrong reason (doesn't recognize mz inf constants), (f) rejects (doesn't recognize mz inf constants), (g) correctly accepts, (h & i) doesn't have ssyntax, unfair comparison.

These are just some of the tests I've run (many ripped off of mzscheme tests).

-----


Miscellaneous thoughts:

1. Vim's auto-indentation for Lisp is controlled by the &lispwords variable. e.g.,

  ; :set lispwords+=def
  (def f (x)
    body)

  ; :set lispwords-=list
  (list x
        y
        z)
def forms have their arguments indented by the standard amount of space, while the arguments to list are lined up with each other.

&lispwords can be approximated by the names of macros that take a rest parameter named "body". It's not as strict as in Common Lisp, because it's just a naming convention instead of a keyword, but it's followed pretty closely in Arc's source. I just maintain a few exceptions to the rule.

But using &lispwords gives a pretty binary choice that fails on "wavy" indentation like

  (if a
        b
      c
        d
        e)
and the indentation of paired forms like the variables of

  (with (x something
         y something-else)
    body)
In all, a better equalprg would be really nice. Not something I plan on doing, but maybe some crazies out there feel like it.

2. Symbols like avg get highlighted in the deftem at the top of news.arc, even though it doesn't refer to the function avg. This can actually be really helpful, so that you know when you accidentally shadow a standard function/macro/variable. Besides, detecting this distinction in Vim seems too difficult.

3. Open question: should forms like a!b!c only highlight the exclamation points, or (current behavior) highlight past each ! as though they are quoted symbols? I think single exclamation marks like a!b should highlight past ! like a quoted symbol, since that's what the ssyntax means and it's quite readable, but nested ones will "run together" under such a scheme.

4. If, like me, you use Vim views & sessions, your old settings for existing Arc files may prevent

  au BufRead,BufNewFile *.arc setf arc
from kicking in. You can setf manually, so that the view is saved with this info, or delete the existing views so that it stops reverting the filetype from (in my case) "arc" back to just "". Took me for-fucking-ever to figure that one out. Hope this helps someone as much as it would've helped me.

-----


The 'li function could be simplified. html.arc has the facilities to define tags; coupled with 'tostring, we can capture the output, giving something like:

  (attribute li class opstring)
  (attribute li id    opstring)
  
  (def li items
    (tostring
      (each i items
        (if (isa i 'table)
            (tag (li class i!class id i!id) (pr i!body))
            (tag li (pr i))))))
This also uses a rest parameter so that 'li can take any number of arguments and collect them up into a list:

  arc> (li (obj body "hi" id "brown") (obj body "world" class "green") "foo")
  "<li id=\"brown\">hi</li><li class=\"green\">world</li><li>foo</li>"
Though it doesn't quite replicate the use of 'string you had originally, e.g.,

  arc> (li ''(a b c))        ; the one defined above
  "<li>(quote (a b c))</li>"
  arc> (li (list ''(a b c))) ; yours
  "<li>quoteabc</li>"
You note that 'gentag prints all over the place. I'm sure (because of the game you built) you notice that Arc uses printing in its html-generation tools. So if you wanted to use this 'li function inside, say, a 'defop, you probably don't want to wrap it in the 'tostring -- instead, let it print so that you don't have to make the call to 'pr yourself.

-----

1 point by coconutrandom 5973 days ago | link

Thanks for the info, didn't know the 'tostring did that!

The reason I didn't want it to pr at the moment was the output from this or other functions could be assembled to make a html template system.

-----

1 point by fallintothis 5981 days ago | link | parent | on: Ask Arc: inst or filltbl?

I think the difficult part is passing in an arbitrary name to a function, for which the tables 'name' becomes set to, but I am just guessing that's what he wants...

I rather doubt that's the issue, as it's easy to do with a macro.

  arc> (mac filltbl (tbl keys vals)
         `(= ,tbl (fill-table (table) (mappend list ,keys ,vals))))
  #3(tagged mac #<procedure: filltbl>)
  arc> (filltbl blah '(a b c) '(1 2 3))
  #hash((c . 3) (a . 1) (b . 2))
  arc> blah
  #hash((c . 3) (a . 1) (b . 2))

I think it's just a request for a convenience function to zip together a list of keys with a list of values into a table, since the existing methods for creating tables center around having alternating key/value pairs.

-----

1 point by thaddeus 5981 days ago | link

Agreed, it was only a wild guess given he was already given a good solution, yet...

   "Am I missing anything here?"
So I don't know what the deal is, but I don't plan to spend any time thinking about it :)

-----

More