
Just Another Y Combinator Derivation - tu7001
http://lion137.blogspot.com/2016/01/another-y-combinator-derrivation.html
======
jarcane
Your stupid Lisp trick for the day: In Heresy, one of my contributors had a
clever moment when he realized that Y can be generalized in Lisps to take
multiple arguments, because technically Lisp lambdas always take just one
argument in reality: a list of arguments. So this:

    
    
      ; Y
      ; The Y-combinator
      (def Y
        (fn (b)
          ((fn (f) (b (fn (x) ((f f) x))))
           (fn (f) (b (fn (x) ((f f) x)))))))
    

Becomes this:

    
    
      ;; Y*
      ;; the Y-combinator, generalized for multiple argument functions
      (def Y*
        (fn (b)
          ((fn (f) (b (fn args (apply (f f) args))))
           (fn (f) (b (fn args (apply (f f) args)))))))
    

And thus can be used with multiple argument functions. But then we can further
have some fun with a simple little macro like this:

    
    
      ; (fnlet *name* args body ...)
      ; A syntax sugaring for less verbose use of Y
      ; Allows lambda functions that can still self-refer
      ; uses the generalized Y-combinator
      (def macro fnlet (name args body ...)
        (Y*
         (fn (name)
           (fn args
             body ...))))
    

And now we have a lambda that can have it's own local name:

    
    
      > (map (fnlet fib (n)
               (select
                ((zero? n) 0)
                ((one? n) 1)
                (else (+ (fib (- n 2)) (fib (- n 1))))))
             (range 0 to 20))
      
      '(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765)

~~~
tu7001
Good stuff!

