idris-0.12.3: libs/oldeffects/Effect/File.idr
-- -------------------------------------------------------- [ Effectful FileIO ]
module Effect.File
import Effects
import Control.IOExcept
||| A Dependent type to describe File Handles. File handles are
||| parameterised with the current state of the file: Closed; Open for
||| reading; and Open for writing.
|||
||| @ m The file mode.
data OpenFile : (m : Mode) -> Type where
FH : File -> OpenFile m
openOK : Mode -> Bool -> Type
openOK m True = OpenFile m
openOK m False = ()
-- ------------------------------------------------------------ [ The Protocol ]
||| Here the protocol for resource access is defined as an effect.
||| The state transitions diagram for the protocol is as follows:
|||
||| digraph G {
|||
||| empty; read; write; // States
|||
||| empty -> read [label="Open R"];
||| read -> empty [label="Close"];
||| read -> read [label="ReadLine"];
||| read -> read [label="EOF"];
|||
||| empty -> write [label="Open W"];
||| write -> empty [label="Close"];
||| write -> write [label="WriteLine"];
|||
||| }
data FileIO : Effect where
||| Open a file with the specified mode.
|||
||| Opening a file successful moves the state from 'empty' to the
||| specified mode. If not successful the state is still 'empty'.
|||
||| @ fname The file name to be opened.
||| @ m The file mode.
Open : (fname: String)
-> (m : Mode)
-> {() ==> {res} if res
then OpenFile m
else ()} FileIO Bool
||| Close a file.
|||
||| Closing a file moves the state from Open to closed.
Close : {OpenFile m ==> ()} FileIO ()
||| Read a line from the file.
|||
||| Only files that are open for reading can be read.
ReadLine : {OpenFile Read} FileIO String
||| Write a line to a file.
|||
||| Only file that are open for writing can be written to.
WriteLine : String -> {OpenFile Write} FileIO ()
||| End of file?
|||
||| Only files open for reading can be tested for EOF
EOF : {OpenFile Read} FileIO Bool
-- ------------------------------------------------------------ [ The Handlers ]
--- An implementation of the resource access protocol for the IO Context.
implementation Handler FileIO IO where
handle () (Open fname m) k = do h <- openFile fname m
valid <- validFile h
if valid then k True (FH h)
else k False ()
handle (FH h) Close k = do closeFile h
k () ()
handle (FH h) ReadLine k = do str <- fread h
k str (FH h)
handle (FH h) (WriteLine str) k = do fwrite h str
k () (FH h)
handle (FH h) EOF k = do e <- feof h
k e (FH h)
-- -------------------------------------------------------------- [ The Effect ]
FILE_IO : Type -> EFFECT
FILE_IO t = MkEff t FileIO
-- ------------------------------------------------------------ [ The Bindings ]
--
-- Bind the IO context handlers to functions. These functions will run
-- in the IO context.
--
||| Open a file with the specified mode.
|||
||| @ fname The file name to be opened.
||| @ m The file mode.
open : (fname : String)
-> (m : Mode)
-> { [FILE_IO ()] ==> [FILE_IO (if result
then OpenFile m
else ())] } Eff e Bool
open f m = call $ Open f m
||| Close a file.
close : { [FILE_IO (OpenFile m)] ==> [FILE_IO ()] } Eff e ()
close = call $ Close
||| Read a line from the file.
readLine : { [FILE_IO (OpenFile Read)] } Eff e String
readLine = call $ ReadLine
||| Write a line to a file.
writeLine : String -> { [FILE_IO (OpenFile Write)] } Eff e ()
writeLine str = call $ WriteLine str
||| End of file?
eof : { [FILE_IO (OpenFile Read)] } Eff e Bool
eof = call $ EOF
-- --------------------------------------------------------------------- [ EOF ]