Re: Lambda over types.

(Redirected from haskell to haskell-cafe.) Well, I tried to fix the problems you mention. Results attached. I have managed to do without de Brujin notation. The evaluator is (modulo bugs!) normal order. One can easily do an applicative order evaluator as well. Evaluating to WHNF is probably easy too (this is what the previous version supposed to do). I'll try to come up with a regression test suite for this stuff as my (copious :) free time permits, but on the surface it looks ok. --- oleg@pobox.com wrote:
anatoli <anatoli at yahoo> wrote:
This is all, of course, of purely academical interest. The notation is extremely inconvenient to do any real work. I'd rather prefer a real, language-supported lambda over types.
Or... wait a minute! You did find all those problems; does it mean you tried to *use* this stuff for something? Just curious.
I must start with a profuse apology, because what follows is perhaps of little relevance to the list. I also propose to re-direct the follow-ups to the Haskell Cafe.
I have examined your code and then tried a few examples, some of which from my code's regression tests.
I have implemented a compile-time lambda-calculator, in a different language. I should say, in a meta-language. The output of the evaluator is a term that can then be compiled and evaluated. The lambda-calculator acts as a partial evaluator. The calculator normalizes a term in a pure untyped lambda calculus. The result is compiled and evaluated in a call-by-value lambda-calculus with constants.
Haskell typechecker (augmented with multi-parameter classes with functional dependencies and let on loose) may do something similar.
BTW, the meta-language lambda-evaluator code (with the regression tests) can be found at http://pobox.com/~oleg/ftp/Computation/rewriting-rule-lambda.txt The calculator is implemented in CPS, in some sort of extended lambda calculus. Therefore, the code has three kinds of lambdas: of the source language, of the transformer meta-language, and of the target language. The first and the third lambdas are spelled the same and are the same.
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
__________________________________________________ Do You Yahoo!? Yahoo! Tax Center - online filing with TurboTax http://taxes.yahoo.com/

Well, I tried to fix the problems you mention. Results attached.
I'm sorry I can't get it to work. The simplest example passes: Lambda> :t eval (A (L x0 x0) x1) eval (A (L x0 x0) x1) :: Next X but even anything more complex seems to fail: Lambda> :t eval (A (L x0 x0) (A x0 x0)) eval (A (L x0 x0) (A x0 x0)) :: Eval (A (L X X) (A X X)) a => a The reduce functions seems to do better: Lambda> :t reduce (A (L x0 x0) (L x1 x1)) reduce (A (L x0 x0) (L x1 x1)) :: (L (Next X) (Next X),T) but fails on more complex examples: Lambda> :t reduce (A (L x0 (L x1 (A x0 x1))) x2) reduce (A (L x0 (L x1 (A x0 x1))) x2) :: Reduce (A (L X (L (Next X) (A X (Next X)))) (Next (Next X))) (L a (A b c)) d => (L a (A b c),d)
I have managed to do without de Brujin notation. It seems that you've implemented something like the calculus of explicit substitutions. The latter has a 'shift' operation to shift up all the variables: s0 -> s1, s1 -> s2, etc.
I'll try to come up with a regression test suite You may want to try evaluating the following terms:
((lambda (x) (x x)) (lambda (y) (y z))) ==> (z z) (lambda (a) ((lambda (x) (lambda (a) (x a))) a)) ==> (lambda (a) (lambda (a-new) (a a-new))) ; compute a*(a+b) ( (lambda (a) (lambda (b) (lambda (f) (a (lambda (x) ((b f) ((a f) x))))))) (lambda (f) (lambda (x) (f (f x)))) ; Numeral 2 (lambda (f) (lambda (x) (f x))) ; Numeral 1 ) ==> numeral for 6 These are some of the tests from my meta-lambda calculator. The normal-order evaluator recipe includes a "repeat until done" phrase. This is one of the challenging aspects: keeping track when done. It seems there is a simpler, purely recursive way of performing the normal reductions. First we need a more general notation for applications: (A t (C t1 (C t2 CNil))) is the same as ((A t t1) t2). The algorithm can be expressed as a sequence of the following re-writing rules, which must be tried in the order given: ; The top-level is a lambda-term: reduce inside Eval (L x body) -> (L x (Eval body)) ; The top-most leftmost is a redex ; Reduce it and retry from the top Eval ((L x body) term) -> Eval (Beta x body term) ; The topmost is a nested application ; Unfold using the associativity rule: ; If (a b) is not a redex and a is not a pair, we try reducing b ; If (a b) is not a redex and a is a pair (x y), we unfold this ; as (x y b) and repeat. Eval ((x) rest) -> Eval (x rest) ; (x) is the same as x Eval ((x y . in-rest) . rest) -> Eval (Append (x y . in-rest) rest) ; In topmost (x y z ...), x is not an appl and not an abst ; It is equivalent to ((x y) z ...) ; Try to reduce y, z, etc. separately Eval (x y . rest) -> (A x (Map Eval (y . rest))) ; The topmost is (x) -- remove the extra parens Eval (term) -> Eval term Eval var -> var This algorithm has been literally implemented in http://pobox.com/~oleg/ftp/Computation/rewriting-rule-lambda.txt (in a continuation-passing-style).

oleg@pobox.com wrote [in part]:
but even anything more complex seems to fail:
Lambda> :t eval (A (L x0 x0) (A x0 x0)) eval (A (L x0 x0) (A x0 x0)) :: Eval (A (L X X) (A X X)) a => a
It evaluates all right to "A X X" in both ghci 5.02.1 and December 2001 Hugs.
Lambda> :t reduce (A (L x0 (L x1 (A x0 x1))) x2) reduce (A (L x0 (L x1 (A x0 x1))) x2) :: Reduce (A (L X (L (Next X) (A X (Next X)))) (Next (Next X))) (L a (A b c)) d => (L a (A b c),d)
Same here: evaluates to (L (Next (Next (Next X))) (A (Next (Next X)) (Next (Next (Next X)))),T) You may be using an older version of Hugs that is known to have problems with fundeps.
You may want to try evaluating the following terms:
((lambda (x) (x x)) (lambda (y) (y z))) ==> (z z)
Here is a real bug, even two. First, two rules for SameVar are wrong; second, a rule for Apply is missing. diff lambda.lhs lambda.lhs.buggy 80c80 < > instance SameVar (Next x) (A y z) F ---
instance SameVar (Next x) (A x y) F 82c82 < > instance SameVar (Next x) (L y z) F
instance SameVar (Next x) (L x y) F 150d149 < > instance (Reduce y y' tryAgain) => Apply (Next x) y (A (Next x) y') tryAgain
With these fixes, this one passes:
(lambda (a) ((lambda (x) (lambda (a) (x a))) a)) ==> (lambda (a) (lambda (a-new) (a a-new)))
Lambda> :t eval (L x0 (A (L x1 (L x0 (A x1 x0))) x0)) L X (L (Next (Next X)) (A X (Next (Next X)))) but this does not, no matter what I try:
; compute a*(a+b) ( (lambda (a) (lambda (b) (lambda (f) (a (lambda (x) ((b f) ((a f) x)))))))
(lambda (f) (lambda (x) (f (f x)))) ; Numeral 2 (lambda (f) (lambda (x) (f x))) ; Numeral 1 ) ==> numeral for 6
Time to try other approaches... -- anatoli __________________________________________________ Do You Yahoo!? Yahoo! Tax Center - online filing with TurboTax http://taxes.yahoo.com/
participants (2)
-
anatoli
-
oleg@pobox.com