One of the highly-touted features is that if a program compiles, it highly likely to be mostly correct, more so than a program written in a language with a less sophisticated or
Laziness, especially lazy I/O where pure functions can force IO
actions or closing a file Handle
prior to reading. The Haskell course by Stanford University has good information on this in the Iteratee
lecture. Imho, this lecture series is very well written and covers a lot of ground.
Consider the following dataype:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
import Data.Foldable
import qualified Data.Traversable as T
import Control.Monad.Random
data U a = U [a] a deriving (Show,Functor,Foldable,T.Traversable)
I want to create a U Int
with random values. It's easy using the Traversable
instance:
ri :: Rand StdGen Int
ri = getRandomR (0,3)
randomU :: U Int
randomU = flip evalRand (mkStdGen 7)
. T.sequence
$ U (replicate 3 ri) ri
putStrLn . show $ randomU -- works
Now I create a random infinite U Int
and print the first three values of the list:
randomInfiniteU :: U Int
randomInfiniteU = flip evalRand (mkStdGen 7)
. T.sequence
$ U (repeat ri) ri
putStrLn . show $ take 3 $ (\(U l _) -> l) $ randomInfiniteU
Works fine as well. As a last test, let's print the single value to the right:
putStrLn . show $ (\(U _ i) -> i) $ randomInfiniteU
Ugh. This hangs.
It doesn’t have to be asymptotic, but space leaks due to lazyness are a problem in real-world applications of Haskell. I know of Haskell-using companies that completely switched to strict datatypes (while still using the laziness of function parameters).
For sources on that view, see: