Arc Forumnew | comments | leaders | submitlogin
1 point by eds 6124 days ago | link | parent

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 6124 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 6124 days ago | link

Example, redefining +:

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

-----

1 point by eds 6124 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 6123 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.

-----