Arc Forumnew | comments | leaders | submitlogin
2 points by cadaver 6114 days ago | link | parent

From the arc1 source:

  ; another possibility: constant in functional pos means it gets
  ; passed to the first arg, i.e. ('kids item) means (item 'kids).
If this gets added to the language, then that's really all the support you need to make even precedence analysis happen; you'll just have to put analysis into the definitions of +-*/ rather than doing it globally in the core.


2 points by vrk 6113 days ago | link

Now that's an interesting idea. However, it would create some confusion if combined with the . operator:

  item!kids   ; Should really be item.'kids
  'kids.item  ; Huh? It's the same?
Granted, it would simplify some expressions, and you would get that "dot operator as in other programming languages" for free.

-----

1 point by eds 6113 days ago | link

I was under the impression cadaver was talking about infix math, because looking in the second position for the functional argument allows infixy syntax analysis.

You could combine it with the dot operator of course but I wouldn't really see a reason for it. (Why would you use 3.+.4 instead of (3 + 4)?)

And actually, the example you gave doesn't quite work (because of quote, you can't actually put a symbol in the functional position using the . operator).

  arc> (= item (table))
  #hash()
  arc> item!kids
  nil
  arc> 'kids.item
  kids.item

-----

1 point by eds 6114 days ago | link

Yeah, I was looking at that comment right as I was writing my code. It was encouraging to see pg was thinking along similar lines.

But I'm not quite clear on your point about defining precedence in the definitions of +-*/. Perhaps you could elaborate.

-----

3 points by cadaver 6114 days ago | link

Nothing more than that user-code could redefine the arithmetic functions and do exactly the kind of analysis that your infix-eval already does in the core.

infix-eval is like an implicit function that gets added before every number-in-functional-position. If, like the arc1 comment suggests, a literal-in-functional-position gets applied to its first argument (swapped positions), then every infix expression that would have been handled with infix-eval could be handled by the first infix function:

  (1 + 2 * 3)
is currently handled like:

  ([infix-eval] 1 + 2 * 3)
but could also be handled by the first +:

  (+ 1 2 * 3)
The + is passed almost exactly the same info as infix-eval, except that has to account for itself being missing from the argument list.

EDIT: This would also take care of the case where you use infix notation within a prefix expression, e.g. (+ 1 2 * 3), which infix-eval would not get the opportunity to handle. Not sure whether that's important though.

-----

2 points by cadaver 6114 days ago | link

Example, redefining +:

  (def + args
    (infix-eval
      (cons (car args)
            (cons + (cdr args)))))

-----

1 point by eds 6114 days ago | link

Ok, I see what you are saying. It happens that + is already a scheme lambda wrapper around the scheme primitive +, so I guess you'd just modify the existing function. But you would have to add wrappers for the other primitives.

It seems a little strange to me to mix infix and prefix. But I don't see any reason to disallow it.

-----

1 point by eds 6113 days ago | link

After a little work I got +-/* to handle infix evaluation themselves, allowing ar-apply to just switch the positions of the first two arguments. This allows user defined operators, but you have to be careful to make a base case for after infix to prefix conversion. For example:

  (def % args
    (if (some [isa _ 'fn] args)
        (infix-eval (cons (car args) (cons % (cdr args))))
        (apply mod args)))
In (3 % 4 + 5), % will get called twice, once to get the initial infix conversion going, and again after the expression has been converted to prefix. So if you don't have the second case, you'll just get into an infinite loop.

I'm still trying to work out what is the best way to allow user-defined precedence. In the above case, (3 % 4 + 5) will evaluate as (% 3 (+ 4 5)) not (+ (% 3 4) 5), because by default it is lowest precedence. I wrote a little set-precedence function that can be called to do the job:

  (set-precedence % 2)
or

  (set-precedence % *)
(The second version looks up the precedence of * and sets % to that precedence.)

But this method of setting precedence seems a little like a hack. And it doesn't play nicely with =. Any suggestions would be welcome.

-----