-XStrict在GHC中有什么作用吗



我认为-XStrict应该把GHC变成一个Strict Haskell,所以我尝试了无限Fibonacci序列测试

my_zipWith f  x [] = []
my_zipWith f []  y = []
my_zipWith f (x:xt) (y:yt) = f x y : my_zipWith f xt yt
test_fibs n = 
let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
take n fibs
main = do
putStr $ show $ test_fibs 15

看看它是否会在内存中爆炸,但它不会:

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.2
$ ghc -XStrict fibs.hs && ./fibs 
[1 of 1] Compiling Main             ( fibs.hs, fibs.o )
Linking fibs ...
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377]

我做错了什么?

Strictpragma当然让GHC严格评估所有内容,但只评估为弱头范式。例如:

(a, b) = (error "a", error "b")

如果上述代码存在于Strict杂注下,则会出现任何错误。让我们看看你的代码:

test_fibs n = 
let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
take n fibs

fibs被递归调用,但在列表cons中,所以现在整个列表是WHNF。这就是为什么您的代码没有堆叠的原因。

这篇文章也会对你有所帮助。享受递归和懒惰!

添加:

一个简单的方法,使用deepseq:

{-# LANGUAGE Strict #-}
import Control.DeepSeq
my_zipWith f  x [] = []
my_zipWith f []  y = []
my_zipWith f (x:xt) (y:yt) = force $ f x y : my_zipWith f xt yt
test_fibs :: Int -> [Int]
test_fibs n = 
let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
force $ take n fibs
main = do
putStr $ show $ test_fibs 15

force定义为force x = x `deepSeq` xdeepSeq从字面上对表达进行了深入的评价。这种转换是用CCD_ 8实现的。如果手动转换,只需评估内部数据,就可以重写以下内容:

{-# LANGUAGE Strict #-}
my_zipWith f  x [] = []
my_zipWith f []  y = []
my_zipWith f (x:xt) (y:yt) = f x y : go
where
go = my_zipWith f xt yt
test_fibs n = 
let
fib2 = my_zipWith (+) fibs (tail fibs)
fibs = 0 : 1 : fib2
in
take n fibs
main = do
putStr $ show $ test_fibs 15

但它们实际上不能堆叠。因为GHC可以检测无限循环,但这是另一回事。

相关内容

  • 没有找到相关文章

最新更新