Repository navigation
Expand file tree
/
Copy pathLanguages.hs
More file actions
216 lines (166 loc) · 6.12 KB
/
Copy pathLanguages.hs
File metadata and controls
216 lines (166 loc) · 6.12 KB
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
-- | Examples of parsing various languages. We'll assume input tokens come from
-- an external variable. Assume the input doesn't given tokens outside the
-- alphabet, and the result is always delayed by one w.r.t. the input stream.
-- Copilot can compute at least NP-Complete problems.
{-# LANGUAGE RebindableSyntax #-}
module Languages (languages) where
import Language.Copilot
import qualified Prelude as P
import qualified Data.List as L
---------------------------------------------------------------------------------
-- Regular expressions
{-
We'll build a Copilot program to accept the regular language over the alphabet
{0,1} that contains an even number of 0s.
-}
reAccept :: Spec
reAccept = do
observer "accept" accept
observer "string" string
where
accept :: Stream Bool
accept = [True] ++ if string == 0
then if accept then false
else true
else accept
-- Input tokens.
string :: Stream Word8
string = [0] ++ if string == 0 then 1 else 0
-- interpret 10 reAccept
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-- Context-free Grammars
{-
This Copilot program recognizes <0^n 1^n>, for n >= 0.
-}
cfAccept :: Int -> Spec
cfAccept n = do
observer "accept" accept
observer "string" string
where
accept :: Stream Bool
accept = if zerosSeen == 0
then true
else false
zerosSeen :: Stream Word64
zerosSeen = [0] ++ if string == 0
then zerosSeen + 1
else zerosSeen - 1
-- Input tokens.
string :: Stream Word8
string = L.replicate n 0 P.++ L.replicate n 1 ++ 0 -- don't care about part of
-- stream after ++
-- interpret 40 (cfAccept 10)
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-- Context-sensitive grammars
{-
This Copilot program recognizes <0^n 1^n 2^n>, for n >= 0.
-}
csAccept :: Int -> Spec
csAccept n = do
observer "accept" accept
observer "string" string
where
accept :: Stream Bool
accept = if zerosSeen == 0 && onesSeen == 0
then true
else false
zerosSeen :: Stream Word64
zerosSeen = [0] ++ if string == 0
then zerosSeen + 1
else if string == 1
then zerosSeen - 1
else zerosSeen
onesSeen :: Stream Word64
onesSeen = [0] ++ if string == 1
then onesSeen + 1
else if string == 0
then onesSeen
else onesSeen - 1
-- Input tokens.
string :: Stream Word8
string = L.replicate n 0 P.++ L.replicate n 1 P.++ L.replicate n 2
++ 0 -- don't care about part of
-- stream after ++
-- interpret 40 (csAccept 5)
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-- Context-sensitive grammars
{-
This Copilot program recognizes the "copy language" <xx | x \in {0,1}*>.
Note: the "trick" is to encode the history of streams in a bitvector. Thus, we
can only recognize arbitrarily long words if we have arbitrarily long
bitvectors. There is nothing in Copilot preventing this, but the largest base
type is currently a Word64.
Without this encoding, we couldn't build a recognizers, because we can't
generate new streams on the fly or look back arbitrarily far in the history of a
stream; both are fixed at compile time.
-}
copyAccept :: Spec
copyAccept = do
observer "accept" accept
observer "hist" hist
observer "string" string
observer "cnt" cnt
where
accept :: Stream Bool
accept = if cnt `mod` 2 == 1 then false else bottom == top
where
halfCnt = cnt `div` 2
zeroBot = (complement $ (2^halfCnt) - 1) .&. hist
top = zeroBot .>>. halfCnt
bottom = hist - zeroBot
hist :: Stream Word64
hist = [0] ++ ((2^cnt) * cast string) + hist
cnt :: Stream Word64
cnt = [0] ++ cnt + 1
-- Input tokens.
string :: Stream Word8
string = let x = [1,0,0,1,0,1] in
x P.++ x
++ 0 -- don't care about part of
-- stream after ++
---------------------------------------------------------------------------------
languages :: IO ()
languages = do
interpret 20 reAccept
interpret 20 (cfAccept 10)
interpret 20 (csAccept 10)
interpret 20 copyAccept
---------------------------------------------------------------------------------
-- -- Recognize the language of arbitrarily long sequence of prime numbers.
-- -- Sieve of Eratosthenes
-- primes :: Word64 -> [Word64]
-- primes n = primes' 2 nums
-- where
-- nums = [2..n]
-- f :: Word64 -> [Word64] -> [Word64]
-- f x = L.filter (\a -> P.not (P.rem a x P.== 0 P.&& a P.> x))
-- primes' :: Word64 -> [Word64] -> [Word64]
-- primes' x ls = let ls' = f x ls in
-- -- Can't use rebinded if-the-else syntax
-- case ls' P.== ls of
-- True -> ls
-- False -> primes' (x P.+ 1) ls'
-- primesInf :: [Word64]
-- primesInf = foldr primes' [2] [3..]
-- where
-- -- returns divisors that evenly divide x
-- f :: Word64 -> [Word64] -> Bool
-- f x ls = ls `seq` (L.or $ map (\a -> P.rem x a P.== 0) ls)
-- -- L.filter (\a -> P.rem x a P.== 0)
-- primes' :: Word64 -> [Word64] -> [Word64]
-- primes' next prms = case prms `seq` f next prms of
-- True -> prms `seq` (next:prms)
-- False -> prms
-- primesAccept :: Word64 -> Spec
-- primesAccept n = do
-- observer "primes" primesStrm
-- observer "accept" accept
-- where
-- -- Assume we are implementing a Sieve of Eratosthenes
-- accept :: Stream Word64
-- accept =
-- primesStrm :: Stream Word64
-- primesStrm = primes n ++ 0 -- don't care about rest of values after ++