部分应用功能的共享

nbu*_*nbu 4 monads lambda haskell sharing

我目前正在尝试共享部分应用的功能。为了使共享可见,我使用了描摹效果。为了说明我的问题,我首先展示一个简化的例子

f1, f2, f3, f4 :: Int -> Int
f1   = \x -> trace "f1" 0 + x
f2 x = trace "f2" 0 + x
f3   = (trace "f3" 0 +)
f4   = (+) (trace "f4" 0)
Run Code Online (Sandbox Code Playgroud)

我在以下场景中比较了这些函数,其中f1由不同的函数代替。

apply :: (Int -> Int) -> (Int -> Int) -> Int
apply f g = f 42 + g 42

result = let f = f1
         in apply f f
Run Code Online (Sandbox Code Playgroud)

输出(未经优化编译)如下。

f1 f1 f2 f2 f3 f4 336
Run Code Online (Sandbox Code Playgroud)

核心代码显示f1f2都是 lambda 函数,而f3f4是部分应用函数。在第一种情况下,在 lambda 的主体内似乎没有共享参数,而在第二种情况下它起作用。启用编译器优化会导致所有定义的共享,但我对为什么 lambda 函数中没有共享感兴趣。

lef*_*out 5

我对为什么 lambda 函数中没有共享感兴趣。

有些应用程序,你真的想要共享。经典示例是,如果要共享的值是一个惰性(可能是无限)列表。那么在非共享的情况下,第一次使用的站点可能会以流的方式处理这个列表,垃圾收集器可以在它之后立即清理。列表的第二个用户然后需要重新进行列表构建计算,是的,但一切都发生在O (1) 内存中。

通过共享,在这种情况下,您保留对列表根目录的引用,因此垃圾收集器只会在第二个用户也使用该列表后才会启动。也许这发生在很久以后,在第一个用户已经将列表扩展到几 GB 大小之后。一般来说,你不想要那个!因此,lambdas (CAF) 提供了一种防止在这种情况下共享的方法。只有当编译器确定共享在某些情况下确实有益时,它才会优化共享。

是否State有可能为 monad 实例共享 monadic 计算?

Y...是的,但我真的不明白你想分享什么以及如何分享。请澄清问题。

  • 我通常就默认共享提出一个观点:正如 leftaroundabout 所说,有时你想要它,有时你不需要,但 GHC 必须选择一种行为。如果选择默认共享,则很难获得不共享行为。由于它默认选择不共享,因此如果您需要的话,很容易获得共享行为:将您想要共享的内容从 lambda 中提升出来。我想这可能是你在接近尾声时得到的结果,但我并不完全清楚。 (4认同)