Does -XStrict do anything in GHC?

Viewed 177

I thought -XStrict was supposed turn GHC into a Strict Haskell, so I tried the infinite Fibonacci sequence test

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

to see if it would blow up in memory, but it doesn't:

$ 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]

What am I doing wrong?

1 Answers

Strict pragma certainly let GHC evaluate everything strictly, but into only Weak Head Normal Form. For example:

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

If above code exists under Strict pragma, any error arises. Let's see your code:

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

fibs called recursively but in list cons, so now whole list is WHNF. That is reason why your code didn't stack.

This post will help you also. Enjoy recursion and laziness!

Add:

An easy way, to use 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 defined as force x = x `deepSeq` x, deepSeq evaluate an expression deeply literally to NF (Normal Form). This conversion is achieved with GHC.Generics. If convert manually, just have to evaluate inside of data, so can rewrite following:

{-# 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

But they can't stack actually. Because GHC can detect infinite loop, but it's another story.

Related