-XStrict 在 GHC 中有什么作用吗?
Does -XStrict do anything in GHC?
我想-XStrict
was supposed turn GHC into a Strict Haskell,所以我尝试了无限斐波那契数列测试
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]
我做错了什么?
Strict
pragma当然让GHC严格评估一切,但只进入Weak Head Normal Form。例如:
(a, b) = (error "a", error "b")
如果在 Strict
pragma 下存在上述代码,则会出现任何错误。让我们看看您的代码:
test_fibs n =
let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
take n fibs
fibs
递归调用但在列表缺点中,所以现在整个列表是 WHNF。这就是为什么您的代码没有堆叠的原因。
This post 也会帮助你。享受递归和懒惰!
添加:
一个简单的方法,使用 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` x
,deepSeq
将表达式从字面上深入计算为 NF(范式)。这种转换是通过 GHC.Generics
实现的。如果手动转换,只需要评估数据内部,所以可以改写如下:
{-# 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 can detect infinite loop,但这是另外一回事了。
我想-XStrict
was supposed turn GHC into a Strict Haskell,所以我尝试了无限斐波那契数列测试
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]
我做错了什么?
Strict
pragma当然让GHC严格评估一切,但只进入Weak Head Normal Form。例如:
(a, b) = (error "a", error "b")
如果在 Strict
pragma 下存在上述代码,则会出现任何错误。让我们看看您的代码:
test_fibs n =
let fibs = 0 : 1 : my_zipWith (+) fibs (tail fibs) in
take n fibs
fibs
递归调用但在列表缺点中,所以现在整个列表是 WHNF。这就是为什么您的代码没有堆叠的原因。
This post 也会帮助你。享受递归和懒惰!
添加:
一个简单的方法,使用 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` x
,deepSeq
将表达式从字面上深入计算为 NF(范式)。这种转换是通过 GHC.Generics
实现的。如果手动转换,只需要评估数据内部,所以可以改写如下:
{-# 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 can detect infinite loop,但这是另外一回事了。