我想在不应用功能的情况下将其评估为正常形式,例如
\n -> n + sum [1..100]
应评估为
\n -> n + 5050
但是没有函数的NFData
实例,这是合理的,因为我们无法获得函数的子项。
我想知道是否有可能借助一些编译器魔术来完全规范化一个函数。
不,不可能。但是,在大多数情况下,它不是必需的。我怀疑您所缺少的诀窍正在提升不依赖于let输出的昂贵计算。比较:
-- recomputes `sum [1..100]` each time you apply it to an argument
f1 :: Int -> Int
f1 n = n + sum [1..100]
-- computes `sum [1..100]` just once, then uses the "cached" result each time
-- you apply it to an argument
f2 :: Int -> Int
f2 = let s = sum [1..100] in \n -> n + s
功能f1
每次使用都非常昂贵。函数f2
首次使用时很昂贵,但此后每次都很便宜。
(此答案是针对GHC的。其他编译器,如果有的话,可能会有所不同。)