blob: 6319aeab9e6da3d29790c6effd861fe339df49f3 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
import Data.STRef.Lazy
import Control.Monad.ST.Lazy as L
import Control.Monad.ST.Strict as S
import qualified Data.STRef as S
import Data.Function (fix)
import System.IO (hPutStrLn, stderr)
import Debug.Trace (trace)
-- The following implements `fix` using lazy `ST`. It is based on code
-- by Oleg Kiselyov (source: http://okmij.org/ftp/Haskell/Fix.hs) which is
-- in the public domain according to the main page (http://okmij.org/ftp/).
fact :: (Int -> Int) -> Int -> Int
fact self 0 = 1
fact self n = n * self (pred n)
-- Test liftM style (Oleg's original style)
fix1 :: (a -> a) -> a
fix1 f = L.runST $ do
wrap <- newSTRef (error "black hole")
let aux = readSTRef wrap >>= (\x -> x >>= pure . f)
writeSTRef wrap aux
aux
-- Test fmap style
fix2 :: (a -> a) -> a
fix2 f = L.runST $ do
wrap <- newSTRef (error "black hole")
let aux = readSTRef wrap >>= \x -> f <$> x
writeSTRef wrap aux
aux
-- The following examples are by Albert Y. C. Lai, and included (under the
-- GHC license) with his permission:
-- https://mail.haskell.org/pipermail/haskell-cafe/2017-January/126182.html
example1 :: [Int]
example1 = L.runST go where
go = do
v <- strictToLazyST (S.newSTRef 0)
fix (\loop -> do
n <- strictToLazyST (do n <- S.readSTRef v
S.writeSTRef v (n+1)
return n
)
ns <- loop
return (n : ns))
example2 :: [Int]
example2 = L.runST main where
main = do
v <- strictToLazyST (S.newSTRef 0)
sequence (repeat (strictToLazyST (do n <- S.readSTRef v
S.writeSTRef v (n+1)
return n
)))
example3 :: L.ST s [Integer]
example3 = do
r <- newSTRef 0
let loop = do
x <- readSTRef r
writeSTRef r $ x + 1
xs <- loop
writeSTRef r $ x + 2
return $ x : xs
loop
example4 :: L.ST s [Integer]
example4 = do
r <- newSTRef 0
let loop = do
x <- readSTRef r
writeSTRef r $ x + 1
xs <- loop
error "this line is dead code"
return $ x : xs
loop
star n s = trace ("<" ++ s ++ show n ++ ">") (return ())
-- Albert called this "Sprinkle sprinkle little stars, how
-- I wonder when you are"
example5 :: L.ST s [Integer]
example5 = do
star 0 "init begin"
r <- newSTRef 0
star 0 "init end"
let loop n = do
star n "A"
x <- readSTRef r
star n "B"
writeSTRef r $ x + 1
star n "C"
xs <- loop (n+1)
star n "D"
writeSTRef r $ x + 2
star n "E"
return $ x : xs
loop 0
main :: IO ()
main = do
print $ fix1 fact 5
print $ fix2 fact 6
print $ take 5 example1
print $ take 5 example2
print $ take 10 (L.runST example3)
print $ take 10 (L.runST example4)
hPutStrLn stderr $ show (take 5 (L.runST example5))
|