scala> def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))(_:T)
Y: [T](func: (T => T) => (T => T))T => T
scala> def fact = Y {
| f: (Int => Int) =>
| n: Int =>
| if(n <= 0) 1
| else n * f(n - 1)}
fact: Int => Int
scala> println(fact(5))
120
问题1:步骤是如何得出结果为120
的?由于Y(func)
被定义为func(Y(func))
,Y应该变得越来越多,那么Y到底去哪了,在执行过程中如何得出120
?
问题2:以下两行代码有什么区别?
def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))(_:T)
并且
def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))
在Scala REPL中,它们是相同类型的,但第二个无法打印出结果
120
?scala> def Y[T](func: (T => T) => (T => T)): (T => T) = func(Y(func))
Y: [T](func: (T => T) => (T => T))T => T
scala> def fact = Y {
| f: (Int => Int) =>
| n: Int =>
| if(n <= 0) 1
| else n * f(n - 1)}
fact: Int => Int
scala> println(fact(5))
java.lang.StackOverflowError
at .Y(<console>:11)
at .Y(<console>:11)
at .Y(<console>:11)
at .Y(<console>:11)
at .Y(<console>:11)
Y(comp)
部分是一个函数,只有在需要时才会被评估。→ 这不是函数的工作方式。Y(comp)
会立即被评估,并且它会评估为一个闭包(因为使用了(_)
进行了η-展开),然后等待被调用。 - Clémentdef makeAFunction(): Int => Int = { println("Hi!"); x => x }
def comp(f: Int => Int): Unit = ()
println(comp(makeAFunction()))
→comp
忽略了传入的函数参数,但它仍然被求值了。 - Clément=> A
视为() => A
,这与 eta 扩展有关)。回想起来,我同意我不应该提到按名调用和按值调用,因为这可能会引起困惑,特别是因为我们在提供的代码中没有使用它。 - slouc