Hacker News new | ask | show | jobs
by junke 3648 days ago

   func (n)to(m)do(blk) {
     x = n
     ...
     do blk x
     ...
   }
This looks ambiguous. Your function does not have a name, how do you do if another library wants to do something different with the same keywords? And how do you know when arguments should be evaluated? In your case, "blk" seems to be a set of statements to be executed when "do" is applied, is it right? shall we scan the body to detect if we use "do" on our arguments or does "do" in the signature have a special meaning?
2 comments

I was describing a syntax I'd like starting from the idea that the compiler should bend to developers and not viceversa.

Let's see if we can make it work.

func (n)to(m)do(blk) could be syntactic sugar for to:do: funci (n, m, blk). I saw funci in the examples, I didn't investigate if there are other type of function definitions. However, if the definition starts with (arg) it should be easy to map it into a funci. This either solves the problem of name clashes with other libraries, or the problem is unsolved right now.

The block passing is more serious. Maybe we could mark blk in such a way we know it's a block. Ruby uses & as in

    func (n)to(m)do(&blk)
Maybe Spry uses & in an incompatible way and I don't like it much anyway. It's developers bending to the compiler, but let's be realistic: we don't want slow compilers.

What Ruby also does is having a yield keyword that calls an anonymous block passed at the invocation point of the function (a method in Ruby's world). The block is not declared as argument of the function/method. Maybe:

    func (n)to(m)do() { # an empty arg is a block
     x = n
     ...
     do x
     ...
    }

    1 to 5 do { echo x }
But I think this is getting far away from the way of Spry.
I am sympathetic to the idea that compilers should bend for developers and that's partly why I love Lisp. Your new syntax has to be learnt by the compiler and that does not scale necessarily well. The regularity of Lisp's syntax is what helps writing code that writes code. Messing up with the readtable, you could obtain something like this:

    {1 to 5 (echo x)}
... which would read into:

    (loop for x from 1 upto 5 do (echo x))
Note that binding `x` implicitly is bad style, as well as defining terse syntax for every construct.
I should mention that Spry uses all of () []{}. The () are reified as Paren as in Rebol which makes it useful in templating etc. {} are used to create Maps, like {x = 1} creates a Map with one kv pair.
I tried to find an example of the macro-like approach of Spry and couldn't. How is it expressed?
It's not as evolved yet - but funcs pull in arguments via :x and can instead use :$x (I used ^ earlier, but switched to $) which will pull in that AST node (argument) without evaluating it first at the call site.

So it's a kind of quoting. I haven't pushed these things further yet, and frankly I am not that heavily into macros unless they are really needed. But obviously AST manipulation is easy in Spry.

In case you want to work on that, be sure to define how quote and eval work with respect to the lexical environment.
You could also use mixfix notation for this:

    _to_do_
      n to m do f =
        x := n
        ...