A Note from kestas.kuliukas.com rewritten using arrow function/const.
const fact = (n) => n === 1 ? 1 : n*fact(n-1)- factory
factfunction
const makeFact = givenFact => n => n === 1 ? 1 : n*givenFact(n-1)Invariety: fact(n) === makeFact(givenFact)(n)
- use
makeFactto computegivenFact
const makeRealFact = (makeFact) => {
const givenFact = (n) => {
return makeFact(givenFact)(n)
}
return makeFact(givenFact)
}Invariety: fact(n) === makeFact(givenFact)(n) === makeRealFact(makeFact)(n)
Note: makeRealFact is our Y function that uses makeFact to do the acutal factorial function.
Recursive calls: givenFact(n) => makeFact(givenFact)(n) => makeFact(makeFact(givenFact))(n) => ... makeFact(makeFact(makeFact ... ))(n)
Finally makeFact will eliminate givenFact since makeFact does not always call givenFact.
- Now we need to eliminate the
givenFactreference ingivenFact, hence we usegetNextGivenFact()to evaluategivenFact.
const makeRealFact = (makeFact) => {
const getNextGivenFact = () => {
const givenFact = (n) => {
return makeFact(getNextGivenFact())(n)
}
return makeFact(givenFact)
}
return getNextGivenFact()
}- Now we need to eliminate the
getNextGivenFactreference, hence we passgetNextGivenFactto itself as a parameter.
const makeRealFact = (makeFact) => {
const getNextGivenFact = (getNextGivenFactRef) => {
const givenFact = (n) => {
return makeFact(getNextGivenFactRef(getNextGivenFactRef))(n)
}
return makeFact(givenFact)
}
return getNextGivenFact(getNextGivenFact)
}- Now that
makeRealFactcan computefactrecursively without using any variables, we will do the refactor to make it simple and human-comphrehensity-proof.
const makeRealFact = (makeFact) => {
const getNextGivenFact = (getNextGivenFactRef) => makeFact(n => makeFact(getNextGivenFactRef(getNextGivenFactRef))(n))
return getNextGivenFact(getNextGivenFact)
}- Now we use anonymous function to rewrite
makeRealFactagain:
const makeRealFact = (makeFact) =>
((getNextGivenFact) => getNextGivenFact(getNextGivenFact))
((getNextGivenFactRef) => makeFact(n => makeFact(getNextGivenFactRef(getNextGivenFactRef))(n)))- Now we use short initials to make even more obscure:
const Y = (f) => (x => x(x))(x => f(t => x(x)(t)))where f = makeFact, x = getNextGivenFact(Ref), t = n.
The le might be short for lambda-terms \lambda E (see https://en.wikipedia.org/wiki/Combinatory_logic).
The Y combinator can be expressed in lambda caculus as following
Y = λf.(λx.f (x x)) (λx.f (x x))