non recursive lambda calculus factorial function

前端 未结 2 1808
旧巷少年郎
旧巷少年郎 2020-12-07 04:34

How to write a factorial function without use of recursion using lambda calculus? Meaning just the math notation not implementation in any particular programming language.

2条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-07 05:06

    i didn't say anything i didn't mean

    By "without the use of recursion" you must mean "without a function calling itself by name"

    Anyway, let's write factorial

    fact := λn. zero? n one (mult n (fact (dec n)))

    Now, we don't particularly care about zero?, mult, dec, or even one in this example; you can implement those on your own – we just want to remove the bolded, by-name recursion,

    ... fact (dec n)

    The easiest way to do this is to apply a lambda to itself – meet the U combinator

    U := λf. f f
    

    Now, we can wrap our original expression in a lambda, and apply U

    fact := U (λf. λn. zero? n one (mult n (??? (dec n))))

    But what do we put in place of fact ??? – Recall that f is a reference to the outer lambda itself, so in order for that to be the same case in the next "iteration", we must apply f to itself, just as U did – in fact, you can think of U as a sort of mirror, and your function can reflect back into that mirror in order to recur; only this time, without using a name ^_^

    fact := U (λf. λn. zero? n one (mult n (f f (dec n))))

    Yes, yes, but the even more astute will notice that you can utilize the mirror (U) directly inside the lambda, too

    fact := U (λf. λn. zero? n one (mult n (U f (dec n))))

    expanded without U

    We know how to expand the inner – we wrote it that way the first time

    fact := U (λf. λn. zero? n one (mult n (f f (dec n))))

    Now expand the outer U

    fact := (λf. λn. zero? n one (mult n (f f (dec n)))) (λf. λn. zero? n one (mult n (f f (dec n))))

    does it work?

    all church numerals represented as #N

    fact := U λf. λn. zero? n #1 (mult n (U f (dec n)))
    
    fact #4
    
    U (λf. λn. zero? n #1 (mult n (U f (dec n))) #4
    
    (λf. f f) (λf. λn. zero? n #1 (mult n (U f (dec n))) #4
    
    (λf. λn. zero? n #1 (mult n (U f (dec n))) (λf. λn. zero? n #1 (mult n (U f (dec n))) #4
    
    (λn. zero? n #1 (mult n (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec n))) #4
    
    zero? #4 #1 (mult #4 (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4)))
    
    zero? #4 #1 (mult #4 (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4)))
    
    // (zero? #4); false; returns second argument
    (mult #4 (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4)))
    
    // which is #4 * ...
    (U (λf. λn. zero? n #1 (mult n (U f (dec n))) (dec #4))
    
    // which is ...
    (U (λf. λn. zero? n #1 (mult n (U f (dec n))) #3)
    
    // which is equivalent to...
    fact #3
    
    // so ...
    (mult #4 (fact #3))
    
    // repeating this pattern ...
    (mult #4 (mult #3 (fact #2))
    (mult #4 (mult #3 (mult #2 (fact #1)))
    (mult #4 (mult #3 (mult #2 (mult #1 (fact #0))))
    (mult #4 (mult #3 (mult #2 (mult #1 #1))))
    (mult #4 (mult #3 (mult #2 #1)))
    (mult #4 (mult #3 #2))
    (mult #4 #6)
    #24
    

    demonstration in javascript

    Go ahead and view the U combinator's power with your very own eyeballs !

    const U =
      f => f (f)
      
    const fact =
      U (f => n =>
        n === 0 ? 1 : n * U (f) (n - 1))
        
    console.log (fact (4)) // 24

    And again as a pure lambda expression

    console.log (
      (f => n => n === 0 ? 1 : n * f (f) (n - 1))
        (f => n => n === 0 ? 1 : n * f (f) (n - 1))
          (4)
    ) // 24

    mutual recursion

    The above snippet demonstrates a very important property of this recursive process: it's mutually recursive. As you can see, there are actually two (albeit the same) functions driving the recursion; A calls B, B calls A – However in the case of the U combinator, there is only one function that gets applied to itself, so it does in fact enable direct recursion – the lambda does call itself using its parameter, not its name (lambdas don't have a name to call)


    Y ?

    Because I said so

    the U combinator is a little cumbersome because it expects the user to "reflect" the function in order to recur – what if we could provide the outer lambda with a function that is the mirror itself?

    U := λf. f f
    Y := λg. U (λf. g (U f))
    

    I'm gonna show you the same definition again, but on two lines just so you can see the "mirrors" and their positions

              / g, user's function
             /
            /  / outer reflection
           /  /
    Y := λg. U (λf.   ...   )
                    g (U f)
                     \
                      \ call g with inner reflection

    So now, whenever you apply Y to any lambda (g), its parameter becomes the function to compute the lambda itself – changing fact to

    fact := Y (λf. λn. zero? n one (mult n (f (dec n))))

    expanding Y

    Y := λg. U (λf. g (U f))             // expand inner U
    Y := λg. U (λf. g (f f))             // expand outer U
    Y := λg. (λf. g (f f)) (λf. g (f f))

    which is the definition you see there in wikipedia; just alpha-renamed


    i just had a profound discovery

    Deriving Y from U above, I saw something I've never seen before - a hidden B

    Y := λg. U (λf. g (U f))
    
    B := λf. λg. λx. f (g x)
    
    Y' := λg. U (B g U)
    

    One of the most beautiful things I've ever seen – and it works too; not that we should have any reason to think it wouldn't...

    #lang lazy
    
    (define B (λ (f)
                (λ (g)
                  (λ (x)
                    (f (g x))))))
    
    (define U (λ (f)
                (f f)))
    
    (define Y (λ (g)
                (U ((B g) U))))
    
    (define fact (Y (λ (f)
                      (λ (n)
                        (if (= n 0)
                            1
                            (* n (f (sub1 n))))))))
    
    (fact 4) ;; 24
    

    Haskellers

    Have you ever seen Y expressed as?

    Y = U . (. U)
      where U f = f f
    

提交回复
热议问题