on master help sign in
Added effects package and associated tests
commit0b5a5b33dc5369a0f3999721707e645cdbad9259 authorEdwin Brady <ecb10@st-andrews.ac.uk> dateFri 1 Mar 2013, 13:52 (14 years ago) parent14cce81
19 files changed+638−2
Makefile+2−1 Setup.hs+11−1 effects/Effect/Exception.idr+37 effects/Effect/File.idr+65 effects/Effect/Random.idr+21 effects/Effect/Select.idr+23 effects/Effect/State.idr+31 effects/Effect/StdIO.idr+58 effects/Effect/Threads.idr+68 effects/Effects.idr+207 effects/Makefile+13 effects/effects.ipkg+6 idris.cabal+1 test/README+1 test/test021/expected+6 test/test021/run+6 test/test021/test021.idr+38 test/test021/test021a.idr+42 test/test021/testFile+2
Makefile+2−1
@@ -18,7 +18,8 @@ test : .PHONY
1818
1919relib: .PHONY
2020 make -C lib IDRIS=../dist/build/idris/idris clean
21− make -C lib IDRIS=../dist/build/idris/idris
21+ make -C effects IDRIS=../dist/build/idris/idris clean
22+ $(CABAL) install
2223
2324linecount : .PHONY
2425 wc -l src/Idris/*.hs src/Core/*.hs src/IRTS/*.hs src/Pkg/*.hs
Setup.hs+11−1
@@ -25,7 +25,8 @@ idrisCmd local = ".." </> buildDir local </> "idris" </> "idris"
2525#endif
2626
2727cleanStdLib verbosity
28− = make verbosity [ "-C", "lib", "clean" ]
28+ = do make verbosity [ "-C", "lib", "clean", "IDRIS=idris" ]
29+ make verbosity [ "-C", "effects", "clean", "IDRIS=idris" ]
2930
3031installStdLib pkg local verbosity copy
3132 = do let dirs = L.absoluteInstallDirs pkg local copy
@@ -37,6 +38,11 @@ installStdLib pkg local verbosity copy
3738 , "TARGET=" ++ idir
3839 , "IDRIS=" ++ icmd
3940 ]
41+ make verbosity
42+ [ "-C", "effects", "install"
43+ , "TARGET=" ++ idir
44+ , "IDRIS=" ++ icmd
45+ ]
4046 let idirRts = idir </> "rts"
4147 putStrLn $ "Installing run time system in " ++ idirRts
4248 make verbosity
@@ -64,6 +70,10 @@ checkStdLib local verbosity
6470 [ "-C", "lib", "check"
6571 , "IDRIS=" ++ icmd
6672 ]
73+ make verbosity
74+ [ "-C", "effects", "check"
75+ , "IDRIS=" ++ icmd
76+ ]
6777 make verbosity
6878 [ "-C", "rts", "check"
6979 , "IDRIS=" ++ icmd
effects/Effect/Exception.idrnew file+37
@@ -0,0 +1,37 @@
1+module Effect.Exception
2+
3+import Effects
4+import System
5+import Control.IOExcept
6+
7+data Exception : Type -> Type -> Type -> Type -> Type where
8+ Raise : a -> Exception a () () b
9+
10+instance Handler (Exception a) Maybe where
11+ handle _ (Raise e) k = Nothing
12+
13+instance Show a => Handler (Exception a) IO where
14+ handle _ (Raise e) k = do print e
15+ believe_me (exit 1)
16+
17+instance Handler (Exception a) (IOExcept a) where
18+ handle _ (Raise e) k = ioM (return (Left e))
19+
20+EXCEPTION : Type -> EFF
21+EXCEPTION t = MkEff () (Exception t)
22+
23+raise : a -> Eff m [EXCEPTION a] b
24+raise err = Raise err
25+
26+
27+
28+
29+
30+
31+
32+-- TODO: Catching exceptions mid program?
33+-- probably need to invoke a new interpreter
34+
35+-- possibly add a 'handle' to the Eff language so that an alternative
36+-- handler can be introduced mid interpretation?
37+
effects/Effect/File.idrnew file+65
@@ -0,0 +1,65 @@
1+module Effect.File
2+
3+import Effects
4+import Control.IOExcept
5+
6+data OpenFile : Mode -> Type where
7+ FH : File -> OpenFile m
8+
9+data FileIO : Effect where
10+ Open : String -> (m : Mode) -> FileIO () (OpenFile m) ()
11+ Close : FileIO (OpenFile m) () ()
12+
13+ ReadLine : FileIO (OpenFile Read) (OpenFile Read) String
14+ WriteLine : String -> FileIO (OpenFile Write) (OpenFile Write) ()
15+ EOF : FileIO (OpenFile Read) (OpenFile Read) Bool
16+
17+instance Handler FileIO IO where
18+ handle () (Open fname m) k = do h <- openFile fname m
19+ k (FH h) ()
20+ handle (FH h) Close k = do closeFile h
21+ k () ()
22+ handle (FH h) ReadLine k = do str <- fread h
23+ k (FH h) str
24+ handle (FH h) (WriteLine str) k = do fwrite h str
25+ k (FH h) ()
26+ handle (FH h) EOF k = do e <- feof h
27+ k (FH h) e
28+
29+instance Handler FileIO (IOExcept String) where
30+ handle () (Open fname m) k
31+ = do h <- ioe_lift (openFile fname m)
32+ valid <- ioe_lift (validFile h)
33+ if valid then k (FH h) ()
34+ else ioe_fail "File open failed"
35+ handle (FH h) Close k = do ioe_lift (closeFile h); k () ()
36+ handle (FH h) ReadLine k = do str <- ioe_lift (fread h)
37+ k (FH h) str
38+ handle (FH h) (WriteLine str) k = do ioe_lift (fwrite h str)
39+ k (FH h) ()
40+ handle (FH h) EOF k = do e <- ioe_lift (feof h)
41+ k (FH h) e
42+
43+FILE_IO : Type -> EFF
44+FILE_IO t = MkEff t FileIO
45+
46+open : Handler FileIO e =>
47+ String -> (m : Mode) -> EffM e [FILE_IO ()] [FILE_IO (OpenFile m)] ()
48+open f m = Open f m
49+
50+close : Handler FileIO e =>
51+ EffM e [FILE_IO (OpenFile m)] [FILE_IO ()] ()
52+close = Close
53+
54+readLine : Handler FileIO e => Eff e [FILE_IO (OpenFile Read)] String
55+readLine = ReadLine
56+
57+writeLine : Handler FileIO e => String -> Eff e [FILE_IO (OpenFile Write)] ()
58+writeLine str = WriteLine str
59+
60+eof : Handler FileIO e => Eff e [FILE_IO (OpenFile Read)] Bool
61+eof = EOF
62+
63+
64+
65+
effects/Effect/Random.idrnew file+21
@@ -0,0 +1,21 @@
1+module Effect.Random
2+
3+import Effects
4+
5+data Random : Type -> Type -> Type -> Type where
6+ getRandom : Random Int Int Int
7+
8+using (m : Type -> Type)
9+ instance Handler Random m where
10+ handle seed getRandom k
11+ = let seed' = 1664525 * seed + 1013904223 in
12+ k seed' seed'
13+
14+RND : EFF
15+RND = MkEff Int Random
16+
17+rndInt : Int -> Int -> Eff m [RND] Int
18+rndInt lower upper = do v <- getRandom
19+ return (v `mod` (upper - lower) + lower)
20+
21+
effects/Effect/Select.idrnew file+23
@@ -0,0 +1,23 @@
1+module Effect.Select
2+
3+import Effects
4+
5+data Selection : Effect where
6+ Select : List a -> Selection () () a
7+
8+instance Handler Selection Maybe where
9+ handle _ (Select xs) k = tryAll xs where
10+ tryAll [] = Nothing
11+ tryAll (x :: xs) = case k () x of
12+ Nothing => tryAll xs
13+ Just v => Just v
14+
15+instance Handler Selection List where
16+ handle r (Select xs) k = concatMap (k r) xs
17+
18+SELECT : EFF
19+SELECT = MkEff () Selection
20+
21+select : List a -> Eff m [SELECT] a
22+select xs = Select xs
23+
effects/Effect/State.idrnew file+31
@@ -0,0 +1,31 @@
1+module Effect.State
2+
3+import Effects
4+
5+%access public
6+
7+data State : Effect where
8+ Get : State a a a
9+ Put : b -> State a b ()
10+
11+using (m : Type -> Type)
12+ instance Handler State m where
13+ handle st Get k = k st st
14+ handle st (Put n) k = k n ()
15+
16+STATE : Type -> EFF
17+STATE t = MkEff t State
18+
19+get : Eff m [STATE x] x
20+get = Get
21+
22+put : x -> Eff m [STATE x] ()
23+put val = Put val
24+
25+putM : y -> EffM m [STATE x] [STATE y] ()
26+putM val = Put val
27+
28+update : (x -> x) -> Eff m [STATE x] ()
29+update f = do val <- get
30+ put (f val)
31+
effects/Effect/StdIO.idrnew file+58
@@ -0,0 +1,58 @@
1+module Effect.StdIO
2+
3+import Effects
4+import Control.IOExcept
5+
6+data StdIO : Effect where
7+ PutStr : String -> StdIO () () ()
8+ GetStr : StdIO () () String
9+
10+instance Handler StdIO IO where
11+ handle () (PutStr s) k = do putStr s; k () ()
12+ handle () GetStr k = do x <- getLine; k () x
13+
14+instance Handler StdIO (IOExcept a) where
15+ handle () (PutStr s) k = do ioe_lift (putStr s); k () ()
16+ handle () GetStr k = do x <- ioe_lift getLine; k () x
17+
18+-- Handle effects in a pure way, for simulating IO for unit testing/proof
19+
20+data IOStream a = MkStream (List String -> (a, List String))
21+
22+injStream : a -> IOStream a
23+injStream v = MkStream (\x => (v, []))
24+
25+instance Handler StdIO IOStream where
26+ handle () (PutStr s) k
27+ = MkStream (\x => case k () () of
28+ MkStream f => let (res, str) = f x in
29+ (res, s :: str))
30+ handle {a} () GetStr k
31+ = MkStream (\x => case x of
32+ [] => cont "" []
33+ (t :: ts) => cont t ts)
34+ where
35+ cont : String -> List String -> (a, List String)
36+ cont t ts = case k () t of
37+ MkStream f => f ts
38+
39+--- The Effect and associated functions
40+
41+STDIO : EFF
42+STDIO = MkEff () StdIO
43+
44+putStr : Handler StdIO e => String -> Eff e [STDIO] ()
45+putStr s = PutStr s
46+
47+putStrLn : Handler StdIO e => String -> Eff e [STDIO] ()
48+putStrLn s = putStr (s ++ "\n")
49+
50+getStr : Handler StdIO e => Eff e [STDIO] String
51+getStr = GetStr
52+
53+mkStrFn : Eff IOStream xs a -> Env IOStream xs ->
54+ List String -> (a, List String)
55+mkStrFn {a} p env input = case mkStrFn' of
56+ MkStream f => f input
57+ where mkStrFn' : IOStream a
58+ mkStrFn' = runWith injStream env p
effects/Effect/Threads.idrnew file+68
@@ -0,0 +1,68 @@
1+module Main
2+
3+import Eff
4+import State
5+
6+mutual
7+ Thunk : (Type -> Type) -> Type
8+ Thunk m = (t : Type) -> Threads m ->
9+ (Threads m -> () -> m t) -> m t
10+
11+ data Threads : (Type -> Type) -> Type where
12+ MkThreads : List (Thunk m) -> List (Thunk m) -> Threads m
13+
14+initThreads : Monad m => Threads m
15+initThreads = MkThreads [] []
16+
17+data Threading : (Type -> Type) -> Effect where
18+ Yield : Threading m (Threads m) (Threads m) ()
19+ Fork : Threading m (Threads m) (Threads m) Bool
20+
21+instance Monad m => Effective (Threading m) m where
22+ runEffect (MkThreads ds []) Yield k
23+ = k (MkThreads [] (reverse ds)) ()
24+ runEffect (MkThreads ds (q :: qs)) Yield k
25+ = q _ (MkThreads (newThread :: ds) qs) k
26+ where newThread _ st k' = do k st ()
27+ k' st ()
28+
29+ runEffect (MkThreads ds qs) Fork k
30+ = k (MkThreads ds (newThread :: qs)) False
31+ where newThread t st k' = do t <- k st True
32+ k' st ()
33+
34+THREADING : (Type -> Type) -> EFF
35+THREADING m = MkEff (Threads m) (Threading m)
36+
37+fork : Monad m => (EffT m [THREADING m] ()) -> EffT m [THREADING m] ()
38+fork prog = do branch <- effect Fork
39+ if branch then prog else return ()
40+
41+yield : Monad m => EffT m [THREADING m] ()
42+yield = effect Yield
43+
44+printA : Int -> Eff [THREADING m, STATE String] ()
45+printA 0 = return ()
46+printA n = do s <- lift get
47+ lift (put (s ++ "A"))
48+ lift yield
49+ printA (n - 1)
50+
51+printB : Int -> Eff [THREADING m, STATE String] ()
52+printB 0 = return ()
53+printB n = do s <- lift get
54+ lift (put (s ++ "B"))
55+ lift yield
56+ printB (n - 1)
57+
58+printAB : Int -> Eff [THREADING m, STATE String] String
59+printAB n = do branch <- effect Fork
60+ if branch then printA n
61+ else printB n
62+ lift get
63+
64+
65+main : IO ()
66+main = print $ runPure [initThreads, ""] (printAB 10)
67+
68+
effects/Effects.idrnew file+207
@@ -0,0 +1,207 @@
1+module Effects
2+
3+import Language.Reflection
4+import Control.Catchable
5+
6+%access public
7+
8+---- Effects
9+
10+Effect : Type
11+Effect = Type -> Type -> Type -> Type
12+
13+data EFF : Type where
14+ MkEff : Type -> Effect -> EFF
15+
16+class Handler (e : Effect) (m : Type -> Type) where
17+ handle : res -> (eff : e res res' t) -> (res' -> t -> m a) -> m a
18+
19+---- Properties and proof construction
20+
21+using (xs : List a, ys : List a)
22+ data SubList : List a -> List a -> Type where
23+ SubNil : SubList {a} [] []
24+ Keep : SubList xs ys -> SubList (x :: xs) (x :: ys)
25+ Drop : SubList xs ys -> SubList xs (x :: ys)
26+
27+ subListId : SubList xs xs
28+ subListId {xs = Nil} = SubNil
29+ subListId {xs = x :: xs} = Keep subListId
30+
31+data Env : (m : Type -> Type) -> List EFF -> Type where
32+ Nil : Env m Nil
33+ (::) : Handler eff m => a -> Env m xs -> Env m (MkEff a eff :: xs)
34+
35+data EffElem : (Type -> Type -> Type -> Type) -> Type ->
36+ List EFF -> Type where
37+ Here : EffElem x a (MkEff a x :: xs)
38+ There : EffElem x a xs -> EffElem x a (y :: xs)
39+
40+-- make an environment corresponding to a sub-list
41+dropEnv : Env m ys -> SubList xs ys -> Env m xs
42+dropEnv [] SubNil = []
43+dropEnv (v :: vs) (Keep rest) = v :: dropEnv vs rest
44+dropEnv (v :: vs) (Drop rest) = dropEnv vs rest
45+
46+updateWith : (ys' : List a) -> (xs : List a) ->
47+ SubList ys xs -> List a
48+updateWith (y :: ys) (x :: xs) (Keep rest) = y :: updateWith ys xs rest
49+updateWith ys (x :: xs) (Drop rest) = x :: updateWith ys xs rest
50+updateWith [] [] SubNil = []
51+
52+-- put things back, replacing old with new in the sub-environment
53+rebuildEnv : Env m ys' -> (prf : SubList ys xs) ->
54+ Env m xs -> Env m (updateWith ys' xs prf)
55+rebuildEnv [] SubNil env = env
56+rebuildEnv (x :: xs) (Keep rest) (y :: env) = x :: rebuildEnv xs rest env
57+rebuildEnv xs (Drop rest) (y :: env) = y :: rebuildEnv xs rest env
58+
59+---- The Effect EDSL itself ----
60+
61+-- some proof automation
62+findEffElem : Nat -> Tactic -- Nat is maximum search depth
63+findEffElem O = Refine "Here" `Seq` Solve
64+findEffElem (S n) = GoalType "EffElem"
65+ (Try (Refine "Here" `Seq` Solve)
66+ (Refine "There" `Seq` (Solve `Seq` findEffElem n)))
67+
68+findSubList : Nat -> Tactic
69+findSubList O = Refine "SubNil" `Seq` Solve
70+findSubList (S n)
71+ = GoalType "SubList"
72+ (Try (Refine "subListId" `Seq` Solve)
73+ ((Try (Refine "Keep" `Seq` Solve)
74+ (Refine "Drop" `Seq` Solve)) `Seq` findSubList n))
75+
76+updateResTy : (xs : List EFF) -> EffElem e a xs -> e a b t ->
77+ List EFF
78+updateResTy {b} (MkEff a e :: xs) Here n = (MkEff b e) :: xs
79+updateResTy (x :: xs) (There p) n = x :: updateResTy xs p n
80+
81+infix 5 :::, :-, :=
82+
83+data LRes : lbl -> Type -> Type where
84+ (:=) : (x : lbl) -> res -> LRes x res
85+
86+(:::) : lbl -> EFF -> EFF
87+(:::) {lbl} x (MkEff r eff) = MkEff (LRes x r) eff
88+
89+private
90+unlabel : {l : ty} -> Env m [l ::: x] -> Env m [x]
91+unlabel {m} {x = MkEff a eff} [l := v] = [v]
92+
93+private
94+relabel : (l : ty) -> Env m [x] -> Env m [l ::: x]
95+relabel {x = MkEff a eff} l [v] = [l := v]
96+
97+-- the language of Effects
98+
99+data EffM : (m : Type -> Type) ->
100+ List EFF -> List EFF -> Type -> Type where
101+ value : a -> EffM m xs xs a
102+ ebind : EffM m xs xs' a -> (a -> EffM m xs' xs'' b) -> EffM m xs xs'' b
103+ effect : {a, b: _} -> {e : Effect} ->
104+ (prf : EffElem e a xs) ->
105+ (eff : e a b t) ->
106+ EffM m xs (updateResTy xs prf eff) t
107+ lift : (prf : SubList ys xs) ->
108+ EffM m ys ys' t -> EffM m xs (updateWith ys' xs prf) t
109+ new : Handler e m =>
110+ res -> EffM m (MkEff res e :: xs) (MkEff res' e :: xs') a ->
111+ EffM m xs xs' a
112+ catch : Catchable m err =>
113+ EffM m xs xs' a -> (err -> EffM m xs xs' a) ->
114+ EffM m xs xs' a
115+ (:-) : (l : ty) -> EffM m [x] [y] t -> EffM m [l ::: x] [l ::: y] t
116+
117+-- Eff : List (EFF m) -> Type -> Type
118+
119+implicit
120+lift' : {default tactics { reflect findSubList 10; solve; }
121+ prf : SubList ys xs} ->
122+ EffM m ys ys' t -> EffM m xs (updateWith ys' xs prf) t
123+lift' {prf} e = lift prf e
124+
125+implicit
126+effect' : {a, b: _} -> {e : Effect} ->
127+ {default tactics { reflect findEffElem 10; solve; }
128+ prf : EffElem e a xs} ->
129+ (eff : e a b t) ->
130+ EffM m xs (updateResTy xs prf eff) t
131+effect' {prf} e = effect prf e
132+
133+
134+-- for 'do' notation
135+
136+return : a -> EffM m xs xs a
137+return x = value x
138+
139+(>>=) : EffM m xs xs' a -> (a -> EffM m xs' xs'' b) -> EffM m xs xs'' b
140+(>>=) = ebind
141+
142+-- for idiom brackets
143+
144+infixl 2 <$>
145+
146+pure : a -> EffM m xs xs a
147+pure = value
148+
149+(<$>) : EffM m xs xs (a -> b) -> EffM m xs xs a -> EffM m xs xs b
150+(<$>) prog v = do fn <- prog
151+ arg <- v
152+ return (fn arg)
153+
154+-- an interpreter
155+
156+private
157+execEff : Env m xs -> (p : EffElem e res xs) ->
158+ (eff : e res b a) ->
159+ (Env m (updateResTy xs p eff) -> a -> m t) -> m t
160+execEff (val :: env) Here eff' k
161+ = handle val eff' (\res, v => k (res :: env) v)
162+execEff (val :: env) (There p) eff k
163+ = execEff env p eff (\env', v => k (val :: env') v)
164+
165+eff : Env m xs -> EffM m xs xs' a -> (Env m xs' -> a -> m b) -> m b
166+eff env (value x) k = k env x
167+eff env (prog `ebind` c) k
168+ = eff env prog (\env', p' => eff env' (c p') k)
169+eff env (effect prf effP) k = execEff env prf effP k
170+eff env (lift prf effP) k
171+ = let env' = dropEnv env prf in
172+ eff env' effP (\envk, p' => k (rebuildEnv envk prf env) p')
173+eff env (new r prog) k
174+ = let env' = r :: env in
175+ eff env' prog (\(v :: envk), p' => k envk p')
176+eff env (catch prog handler) k
177+ = catch (eff env prog k)
178+ (\e => eff env (handler e) k)
179+eff {xs = [l ::: x]} env (l :- prog) k
180+ = let env' = unlabel {l} env in
181+ eff env' prog (\envk, p' => k (relabel l envk) p')
182+
183+run : Applicative m => Env m xs -> EffM m xs xs' a -> m a
184+run env prog = eff env prog (\env, r => pure r)
185+
186+runEnv : Applicative m => Env m xs -> EffM m xs xs' a -> m (Env m xs', a)
187+runEnv env prog = eff env prog (\env, r => pure (env, r))
188+
189+runPure : Env id xs -> EffM id xs xs' a -> a
190+runPure env prog = eff env prog (\env, r => r)
191+
192+runWith : (a -> m a) -> Env m xs -> EffM m xs xs' a -> m a
193+runWith inj env prog = eff env prog (\env, r => inj r)
194+
195+Eff : (Type -> Type) -> List EFF -> Type -> Type
196+Eff m xs t = EffM m xs xs t
197+
198+-- some higher order things
199+
200+mapE : Applicative m => (a -> Eff m xs b) -> List a -> Eff m xs (List b)
201+mapE f [] = pure []
202+mapE f (x :: xs) = [| f x :: mapE f xs |]
203+
204+when : Applicative m => Bool -> Eff m xs () -> Eff m xs ()
205+when True e = e
206+when False e = pure ()
207+
effects/Makefilenew file+13
@@ -0,0 +1,13 @@
1+
2+check: .PHONY
3+ $(IDRIS) --build effects.ipkg
4+
5+recheck: clean check
6+
7+install:
8+ $(IDRIS) --install effects.ipkg
9+
10+clean: .PHONY
11+ $(IDRIS) --clean effects.ipkg
12+
13+.PHONY:
effects/effects.ipkgnew file+6
@@ -0,0 +1,6 @@
1+package effects
2+
3+opts = "-i ../lib"
4+modules = Effects,
5+ Effect.Exception, Effect.File, Effect.State,
6+ Effect.Random, Effect.StdIO, Effect.Select
idris.cabal+1
@@ -56,6 +56,7 @@ Extra-source-files: lib/Makefile lib/*.idr lib/Prelude/*.idr
5656 lib/System/Concurrency/*.idr
5757 lib/Data/*.idr lib/Debug/*.idr
5858 lib/Decidable/*.idr
59+ effects/*.idr effects/Effect/*.idr
5960 tutorial/examples/*.idr lib/base.ipkg
6061 config.mk
6162 rts/*.c rts/*.h rts/Makefile
test/README+1
@@ -20,5 +20,6 @@ Tests:
2020018: Message passing concurrency (raw form)
2121019: magic with
2222020: implicit conversions
23+021: effects
2324
2425regxxx: various regression tests
test/test021/expectednew file+6
@@ -0,0 +1,6 @@
1+[HELLO!!!
2+, WORLD!!!
3+, ]
4+3
5+23
6+Answer: 107
test/test021/runnew file+6
@@ -0,0 +1,6 @@
1+#!/bin/bash
2+idris -p effects $@ test021.idr -o test021
3+idris -p effects $@ test021a.idr -o test021a
4+./test021
5+./test021a
6+rm -f test021 test021a *.ibc
test/test021/test021.idrnew file+38
@@ -0,0 +1,38 @@
1+module Main
2+
3+import Effect.File
4+import Effect.State
5+import Effect.StdIO
6+import Control.IOExcept
7+
8+data FName = Count | NotCount
9+
10+FileIO : Type -> Type -> Type
11+FileIO st t
12+ = Eff (IOExcept String) [FILE_IO st, STDIO, Count ::: STATE Int] t
13+
14+readFile : FileIO (OpenFile Read) (List String)
15+readFile = readAcc [] where
16+ readAcc : List String -> FileIO (OpenFile Read) (List String)
17+ readAcc acc = do e <- eof
18+ if (not e)
19+ then do str <- readLine
20+ ls <- Count :- get
21+ Count :- put (ls + 1)
22+ readAcc (str :: acc)
23+ else return (reverse acc)
24+
25+testFile : FileIO () ()
26+testFile = catch (do open "testFile" Read
27+ str <- readFile
28+ putStrLn (show str)
29+ ls <- Count :- get
30+ close
31+ putStrLn (show ls))
32+ (\err => putStrLn ("Handled: " ++ show err))
33+
34+main : IO ()
35+main = do ioe_run (run [(), (), Count := 0] testFile)
36+ (\err => print err) (\ok => return ())
37+
38+
test/test021/test021a.idrnew file+42
@@ -0,0 +1,42 @@
1+module Main
2+
3+import Effect.State
4+import Effect.Exception
5+import Effect.Random
6+import Effect.StdIO
7+
8+data Expr = Var String
9+ | Val Int
10+ | Add Expr Expr
11+ | Random Int
12+
13+Env : Type
14+Env = List (String, Int)
15+
16+-- Evaluator : Type -> Type
17+-- Evaluator t
18+-- = Eff m [EXCEPTION String, RND, STATE Env] t
19+
20+eval : Expr -> Eff IO [EXCEPTION String, STDIO, RND, STATE Env] Int
21+eval (Var x) = do vs <- get
22+ case lookup x vs of
23+ Nothing => raise ("No such variable " ++ x)
24+ Just val => return val
25+eval (Val x) = return x
26+eval (Add l r) = [| eval l + eval r |]
27+eval (Random upper) = do val <- rndInt 0 upper
28+ putStrLn (show val)
29+ return val
30+
31+testExpr : Expr
32+testExpr = Add (Add (Var "foo") (Val 42)) (Random 100)
33+
34+runEval : List (String, Int) -> Expr -> IO Int
35+runEval args expr = run [(), (), 123456, args] (eval expr)
36+
37+main : IO ()
38+main = do let x = 42
39+ val <- runEval [("foo", x)] testExpr
40+ putStrLn $ "Answer: " ++ show val
41+
42+
test/test021/testFilenew file+2
@@ -0,0 +1,2 @@
1+HELLO!!!
2+WORLD!!!