为什么部分评估在部分申请的时刻没有严格评估,为什么不止一次重新评估?作为一个时髦的问题,Scala和Haskell中的例子(我认为Haskell的表现会有所不同):
在斯卡拉:
scala> def f(x: Int)(y: Int) = {println("inside"); x * y}
f: (x: Int)(y: Int)Int
scala> val f2 = f(2) _
f2: Int => Int = <function1>
scala> f2(3)
inside //internals of f calculated for the first time
res7: Int = 6
scala> f2(7)
inside //internals of f recalculated
res8: Int = 14
Run Code Online (Sandbox Code Playgroud)
在Haskell:
Prelude> import Debug.Trace
Prelude Debug.Trace> let f x y = trace "inside" x * y
Prelude Debug.Trace> let f2 = f 2
Prelude Debug.Trace> f2 3
inside //internals of f calculated for the first time
6
Prelude Debug.Trace> f2 3
inside //internals of f recalculated
6
Prelude Debug.Trace> f2 7
inside //internals of f recalculated
14
Run Code Online (Sandbox Code Playgroud)
我知道这是可能重新定义f
返回的功能就像在下面的代码,但它会是有趣的,有那些功能真的部分,甚至在他们进行评估完全评估:
scala> def f(x: Int) = {println("inside"); (y:Int) => x * y}
f: (x: Int)Int => Int
scala> val f2 = f(2)
inside //internals of f calculated only this time
f2: Int => Int = <function1>
scala> f2(3)
res12: Int = 6
scala> f2(7)
res13: Int = 14
Run Code Online (Sandbox Code Playgroud)
Tom*_*lis 14
在Haskell,是的.你必须要小心你的函数定义所涉及的lambda表达式.例如
Prelude> import Debug.Trace
Prelude Debug.Trace> let f x = let x1 = trace "inside" x in \y -> x1 * y
Prelude Debug.Trace> let f2 = f 2
Prelude Debug.Trace> f2 3
inside
6
Prelude Debug.Trace> f2 3
6
Prelude Debug.Trace> f2 7
14
Run Code Online (Sandbox Code Playgroud)
Sassa NF提出的另一个例子.请注意,在g
该trace "inside" succ
闭合重建每次通话,而在h
封闭势必h
一劳永逸.Eta减少不会保留Haskell中的操作语义!
Prelude Debug.Trace> let g = \x -> (trace "inside" succ) x :: Int
Prelude Debug.Trace> g 1
inside
2
Prelude Debug.Trace> g 2
inside
3
Prelude Debug.Trace> g 3
inside
4
Prelude Debug.Trace> let h = trace "inside" succ :: Int -> Int
Prelude Debug.Trace> h 1
inside
2
Prelude Debug.Trace> h 2
3
Prelude Debug.Trace> h 3
4
Run Code Online (Sandbox Code Playgroud)