-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapter15.2.idr
187 lines (161 loc) · 5.46 KB
/
chapter15.2.idr
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
module Main
import Data.Vect
import System.Concurrency.Channels
%default total
data Message = Add Nat Nat
AdderType : Message -> Type
AdderType (Add _ _) = Nat
data ListAction : Type where
Length : List elem -> ListAction
Append : List elem -> List elem -> ListAction
ListType : ListAction -> Type
ListType (Length xs) = Nat
ListType (Append {elem} xs ys) = List elem
data MessagePID : (iface : reqType -> Type) -> Type where
MkMessage : PID -> MessagePID iface
data Fuel = Dry | More (Lazy Fuel)
covering
forever : Fuel
forever = More forever
data ProcState = NoRequest | Sent | Complete
data Process : (iface : reqType -> Type) -> Type -> (in_state : ProcState) -> (out_state : ProcState) -> Type where
Request : MessagePID service_iface -> (msg : service_reqType) -> Process iface (service_iface msg) st st
Respond : ((msg : reqType) -> Process iface (iface msg) NoRequest NoRequest) -> Process iface (Maybe reqType) st Sent
Spawn : Process service_iface () NoRequest Complete ->Process iface (Maybe (MessagePID service_iface)) st st
Loop : Inf (Process iface a NoRequest Complete) -> Process iface a Sent Complete
Action : IO a -> Process iface a st st
Pure : a -> Process iface a st st
(>>=) : Process iface a st1 st2 -> (a -> Process iface b st2 st3) -> Process iface b st1 st3
NoRecv : Void -> Type
NoRecv = void
Service : (iface : reqType -> Type) -> Type -> Type
Service iface a = Process iface a NoRequest Complete
Client : Type -> Type
Client a = Process NoRecv a NoRequest NoRequest
procAdder : Service AdderType ()
procAdder =
do
Respond (
\msg =>
case msg of
Add x y => Pure (x + y))
Loop procAdder
procMain : Client ()
procMain =
do
Just adder_id <- Spawn procAdder
| Nothing => Action (putStrLn "Spawn failed")
answer <- Request adder_id (Add 2 3)
Action (printLn answer)
run : Fuel -> Process iface t in_state out_state -> IO (Maybe t)
run Dry _ = pure Nothing
run fuel (Request (MkMessage {iface} process) msg) =
do
Just chan <- connect process
| _ => pure Nothing
ok <- unsafeSend chan msg
if ok then unsafeRecv (iface msg) chan else pure Nothing
run fuel (Respond {reqType} calc)
=
do
Just sender <- listen 1
| Nothing => pure (Just Nothing)
Just msg <- unsafeRecv reqType sender
| Nothing => pure (Just Nothing)
Just res <- run fuel (calc msg)
| Nothing => pure Nothing
unsafeSend sender res
pure (Just (Just msg))
run (More fuel) (Loop act) = run fuel act
run fuel (Spawn proc) =
do
Just pid <- spawn (
do
run fuel proc
pure ()
)
| Nothing => pure Nothing
pure (Just (Just (MkMessage pid)))
run fuel (Action act) =
do
res <- act
pure (Just res)
run fuel (Pure val) = pure (Just val)
run fuel (act >>= next) =
do
Just x <- run fuel act
| Nothing => pure Nothing
run fuel (next x)
procList : Service ListType ()
procList =
do
Respond
(
\msg =>
case msg of
(Length xs) => Pure $ length xs
(Append xs ys) => Pure $ xs ++ ys
)
Loop procList
procListMain : Client ()
procListMain =
do
Just list <- Spawn procList
| Nothing => Action (putStrLn "Spawn failed")
len <- Request list (Length [1,2,3])
Action (printLn len)
app <- Request list (Append [1,2,3] [4,5,6])
Action (printLn app)
covering
runProc : Client () -> IO ()
runProc proc =
do
run forever proc
pure ()
record WCData where
constructor MkWCData
wordCount : Nat
lineCount : Nat
doCount : (content : String) -> WCData
doCount content =
let lcount = length (lines content)
wcount = length (words content)
in MkWCData lcount wcount
data WC = CountFile String | GetData String
WCType : WC -> Type
WCType (CountFile x) = ()
WCType (GetData x) = Maybe WCData
countFile : List (String, WCData) -> String -> Process WCType (List (String, WCData)) Sent Sent
countFile files fname =
do
Right content <- Action (readFile fname)
| Left err => Pure files
let count = doCount content
Action (putStrLn ("Counting complete for " ++ fname))
Pure ((fname, doCount content) :: files)
wcService : (loaded : List (String, WCData)) -> Service WCType ()
wcService loaded =
do
msg <- Respond
(
\msg => case msg of
CountFile fname => Pure ()
GetData fname => Pure (lookup fname loaded)
)
newLoaded <- case msg of
Just (CountFile fname) => countFile loaded fname
_ => Pure loaded
Loop (wcService newLoaded)
procWcMain : Client ()
procWcMain =
do
let fileName = "chapter15.2.idr";
Just wc <- Spawn (wcService [])
| Nothing => Action (putStrLn "Spawn failed")
Action (putStrLn $ "Counting " ++ fileName)
Request wc (CountFile fileName)
Action (putStrLn "Processing")
Just wcdata <- Request wc (GetData fileName)
| Nothing => Action (putStrLn "File error")
Action (putStrLn ("Words: " ++ show (wordCount wcdata)))
Action (putStrLn ("Lines: " ++ show (lineCount wcdata)))