>>> let fac n = if n <= 1 then 1 else n * fac (n-1) in fac 5 120This uses the fact that Haskell’s let introduces recursive bindings. We can rewrite this definition using fix, Instead of making a recursive call, we introduce a dummy parameter rec; when used within fix, this parameter then refers to fix’s argument, hence the recursion is reintroduced.
>>> fix (\rec n -> if n <= 1 then 1 else n * rec (n-1)) 5 120Using fix, we can implement versions of repeat as fix . (:) and cycle as fix . (++)
>>> take 10 $ fix (0:) [0,0,0,0,0,0,0,0,0,0]
>>> map (fix (\rec n -> if n < 2 then n else rec (n - 1) + rec (n - 2))) [1..10] [1,1,2,3,5,8,13,21,34,55]
fix f = let x = f x in xA more straightforward but non-sharing version would look like
fix f = f (fix f)
>>> take 3 <$> fixIO (\x -> putStr ":D" >> (:x) <$> readLn @Int) :D 2 [2,2,2]If we are strict in the value, just as with fix, we do not get termination:
>>> fixIO (\x -> putStr x >> pure ('x' : x)) * hangs forever *We can tie the knot of a structure within IO using fixIO:
data Node = MkNode Int (IORef Node) foo :: IO () foo = do p <- fixIO (p -> newIORef (MkNode 0 p)) q <- output p r <- output q _ <- output r pure () output :: IORef Node -> IO (IORef Node) output ref = do MkNode x p <- readIORef ref print x pure p
>>> foo 0 0 0
>>> realToFrac (0.123456 :: Pico) :: Milli 0.123
MkFixed 12345 :: Fixed E3
>>> isInfixOf "Haskell" "I really like Haskell." True
>>> isInfixOf "Ial" "I really like Haskell." FalseFor the result to be True, the first list must be finite; for the result to be False, the second list must be finite:
>>> [20..50] `isInfixOf` [0..] True
>>> [0..] `isInfixOf` [20..50] False
>>> [0..] `isInfixOf` [0..] * Hangs forever *
>>> "Hello" `isPrefixOf` "Hello World!" True
>>> "Hello" `isPrefixOf` "Wello Horld!" FalseFor the result to be True, the first list must be finite; False, however, results from any mismatch:
>>> [0..] `isPrefixOf` [1..] False
>>> [0..] `isPrefixOf` [0..99] False
>>> [0..99] `isPrefixOf` [0..] True
>>> [0..] `isPrefixOf` [0..] * Hangs forever *isPrefixOf shortcuts when the first argument is empty:
>>> isPrefixOf [] undefined True
>>> "ld!" `isSuffixOf` "Hello World!" True
>>> "World" `isSuffixOf` "Hello World!" FalseThe second list must be finite; however the first list may be infinite:
>>> [0..] `isSuffixOf` [0..99] False
>>> [0..99] `isSuffixOf` [0..] * Hangs forever *
>>> stripPrefix "foo" "foobar" Just "bar"
>>> stripPrefix "foo" "foo" Just ""
>>> stripPrefix "foo" "barfoo" Nothing
>>> stripPrefix "foo" "barfoobaz" Nothing
unsafeFixIO $ \r -> do forkIO (print r) return (...)In this case, the child thread will receive a NonTermination exception instead of waiting for the value of r to be computed.