diff options
author | Péter Diviánszky <divipp@gmail.com> | 2016-04-08 12:02:33 +0200 |
---|---|---|
committer | Péter Diviánszky <divipp@gmail.com> | 2016-04-08 12:02:33 +0200 |
commit | 02c3f915861d53122624417a9d97068d754a4b26 (patch) | |
tree | baeaff1fb4954b5b9a6761772282c8cf268f425a /prototypes | |
parent | 2e65df79cda76000ae0b69b8b9b85f4abac7f084 (diff) |
split Stream.hs; bugfixes
Diffstat (limited to 'prototypes')
-rw-r--r-- | prototypes/ShiftReducer.hs | 361 | ||||
-rw-r--r-- | prototypes/Stream.hs | 248 |
2 files changed, 366 insertions, 243 deletions
diff --git a/prototypes/ShiftReducer.hs b/prototypes/ShiftReducer.hs index 97e589a7..f40c7656 100644 --- a/prototypes/ShiftReducer.hs +++ b/prototypes/ShiftReducer.hs | |||
@@ -16,6 +16,7 @@ | |||
16 | {-# language FlexibleContexts #-} | 16 | {-# language FlexibleContexts #-} |
17 | {-# language TemplateHaskell #-} -- for testing | 17 | {-# language TemplateHaskell #-} -- for testing |
18 | {-# language NoMonomorphismRestriction #-} | 18 | {-# language NoMonomorphismRestriction #-} |
19 | module ShiftReducer where | ||
19 | 20 | ||
20 | import Data.Monoid | 21 | import Data.Monoid |
21 | import Data.Maybe | 22 | import Data.Maybe |
@@ -30,214 +31,7 @@ import Test.QuickCheck.Function | |||
30 | import GHC.Generics | 31 | import GHC.Generics |
31 | import Debug.Trace | 32 | import Debug.Trace |
32 | 33 | ||
33 | ------------------------------------------------------------ utils | 34 | import Stream |
34 | |||
35 | iterateN i f x = iterate f x !! i | ||
36 | |||
37 | (<&>) = flip (<$>) | ||
38 | |||
39 | data Void | ||
40 | |||
41 | instance Eq Void where (==) = error "(==) @Void" | ||
42 | instance Show Void where show = error "show @Void" | ||
43 | |||
44 | {- used later? | ||
45 | -- supplementary data: data with no semantic relevance | ||
46 | newtype SData a = SData a | ||
47 | instance Show (SData a) where show _ = "SData" | ||
48 | instance Eq (SData a) where _ == _ = True | ||
49 | instance Ord (SData a) where _ `compare` _ = EQ | ||
50 | -} | ||
51 | |||
52 | ------------------------------------------------------------ streams | ||
53 | |||
54 | -- streams with constant tails | ||
55 | -- invariant property: Repeat is used when possible (see cons) | ||
56 | data Stream a | ||
57 | = Cons a (Stream a) | ||
58 | | Repeat a | ||
59 | deriving (Eq, Show, Functor) -- Functor is not proper, may break invariant | ||
60 | |||
61 | -- smart constructor to construct normal form of streams | ||
62 | cons b (Repeat b') | b == b' = Repeat b' | ||
63 | cons b x = Cons b x | ||
64 | |||
65 | -- stream head | ||
66 | sHead (Cons a _) = a | ||
67 | sHead (Repeat a) = a | ||
68 | |||
69 | -- stream tail | ||
70 | sTail (Cons _ a) = a | ||
71 | sTail (Repeat a) = Repeat a | ||
72 | |||
73 | instance Applicative Stream where | ||
74 | pure a = Repeat a | ||
75 | -- (<*>) is not proper, may break invariant | ||
76 | Repeat f <*> Repeat a = Repeat $ f a | ||
77 | x <*> y = Cons{-should be cons-} (sHead x $ sHead y) (sTail x <*> sTail y) | ||
78 | |||
79 | foldStream :: (b -> a -> a) -> (b -> a) -> Stream b -> a | ||
80 | foldStream f g (Cons b u) = f b (foldStream f g u) | ||
81 | foldStream f g (Repeat b) = g b | ||
82 | |||
83 | -- final value in the stream | ||
84 | limes :: Stream a -> a | ||
85 | limes = foldStream const id | ||
86 | |||
87 | -- replace limes by given stream | ||
88 | sCont :: Eq a => Stream a -> (a -> Stream a) -> Stream a | ||
89 | sCont as f = foldStream cons f as | ||
90 | |||
91 | -- semantics of Stream | ||
92 | streamToList :: Stream a -> [a] | ||
93 | streamToList = foldStream (:) repeat | ||
94 | |||
95 | streamToFun :: Stream a -> Int -> a | ||
96 | streamToFun u i = streamToList u !! i | ||
97 | |||
98 | sFromList :: Eq a => [a] -> a -> Stream a | ||
99 | sFromList xs b = foldr cons (Repeat b) xs | ||
100 | |||
101 | instance (Arbitrary a, Eq a) => Arbitrary (Stream a) where | ||
102 | arbitrary = sFromList <$> arbitrary <*> arbitrary | ||
103 | |||
104 | -- iterate on stream | ||
105 | sIterate :: Eq a => (a -> a) -> a -> Stream a | ||
106 | sIterate f x | ||
107 | | y == x = Repeat x | ||
108 | | otherwise = Cons x $ sIterate f y | ||
109 | where | ||
110 | y = f x | ||
111 | |||
112 | sCatMaybes :: Stream (Maybe a) -> [a] | ||
113 | sCatMaybes = foldStream (\m s -> maybe s (:s) m) (maybe [] repeat) | ||
114 | |||
115 | ---------------------------------------------------------- operations involving Boolean streams | ||
116 | |||
117 | mergeStreams :: Eq a => Stream Bool -> Stream a -> Stream a -> Stream a | ||
118 | mergeStreams (Cons True u) as bs = cons (sHead as) $ mergeStreams u (sTail as) bs | ||
119 | mergeStreams (Cons False u) as bs = cons (sHead bs) $ mergeStreams u as (sTail bs) | ||
120 | mergeStreams (Repeat True) as bs = as | ||
121 | mergeStreams (Repeat False) as bs = bs | ||
122 | |||
123 | sFilter :: Stream Bool -> [a] -> [a] | ||
124 | sFilter (Cons True u) is = take 1 is ++ sFilter u (drop 1 is) | ||
125 | sFilter (Cons False u) is = sFilter u (drop 1 is) | ||
126 | sFilter (Repeat True) is = is | ||
127 | sFilter (Repeat False) is = [] | ||
128 | |||
129 | -- sFilter for streams | ||
130 | -- the first stream is used when no more element can pass the filter | ||
131 | filterStream :: Eq a => Stream a -> Stream Bool -> Stream a -> Stream a | ||
132 | filterStream d (Cons True s) as = cons (sHead as) $ filterStream d s $ sTail as | ||
133 | filterStream d (Cons False s) as = filterStream d s $ sTail as | ||
134 | filterStream d (Repeat True) as = as | ||
135 | filterStream d (Repeat False) as = d | ||
136 | |||
137 | sOr :: Stream Bool -> Stream Bool -> Stream Bool | ||
138 | sOr (Cons b u) (Cons b' u') = cons (b || b') $ sOr u u' | ||
139 | sOr (Repeat False) u = u | ||
140 | sOr (Repeat True) u = Repeat True | ||
141 | sOr u (Repeat False) = u | ||
142 | sOr u (Repeat True) = Repeat True | ||
143 | |||
144 | prop_sOr_idemp a = sOr a a == a | ||
145 | prop_sOr_comm a b = sOr a b == sOr b a | ||
146 | |||
147 | dbAnd a b = not <$> sOr (not <$> a) (not <$> b) | ||
148 | |||
149 | instance Monoid (Stream Bool) where | ||
150 | mempty = Repeat False | ||
151 | mappend = sOr | ||
152 | |||
153 | prop_StreamBool_monoid_left (a :: Stream Bool) = mempty <> a == a | ||
154 | prop_StreamBool_monoid_right (a :: Stream Bool) = a <> mempty == a | ||
155 | prop_StreamBool_monoid_assoc (a :: Stream Bool) b c = (a <> b) <> c == a <> (b <> c) | ||
156 | |||
157 | -- composition of (Stream Bool) values (by sFilter semantics) | ||
158 | sComp :: Stream Bool -> Stream Bool -> Stream Bool | ||
159 | sComp bs as = mergeStreams bs as $ Repeat False | ||
160 | |||
161 | prop_sComp a b xs = sFilter (sComp a b) xs == (sFilter b . sFilter a) xs | ||
162 | prop_sComp_trans a b (getNonNegative -> i) = indexTrans (sComp a b) i == (indexTrans a =<< indexTrans b i) | ||
163 | |||
164 | filterDBUsed :: Stream Bool -> Stream Bool -> Stream Bool | ||
165 | filterDBUsed = filterStream $ Repeat False | ||
166 | |||
167 | --prop_filterDBUsed bs = mergeStreams bs xs ys sOr b a `sComp` filterDBUsed (sOr b a) a == a | ||
168 | |||
169 | prop_filterDBUsed a b = sOr b a `sComp` filterDBUsed (sOr b a) a == a | ||
170 | |||
171 | compress s = filterDBUsed s s | ||
172 | |||
173 | |||
174 | --takeUps :: Int -> Stream Bool -> Stream Bool | ||
175 | --takeUps i = (`sComp` sFromList (replicate i True) False) | ||
176 | |||
177 | --prop_takeUps (getNonNegative -> n) u = streamToList (takeUps n u) == normSem (take n $ streamToList u) | ||
178 | |||
179 | --takeUps' :: Int -> Stream Bool -> Stream Bool | ||
180 | --takeUps' i = sComp $ sFromList (replicate i True) False | ||
181 | |||
182 | --prop_takeUps' u (getNonNegative -> n) = streamToList (takeUps' n u) == head (dropWhile ((< n) . length . filter id) (inits $ streamToList u) ++ [streamToList u]) | ||
183 | |||
184 | --------------------------------------------------------------- indices | ||
185 | |||
186 | -- index of the first appearance of the limes | ||
187 | limesIndex :: Stream a -> Int | ||
188 | limesIndex = foldStream (const (+1)) (const 0) | ||
189 | |||
190 | -- indices at which the stream value is True | ||
191 | trueIndices :: Stream Bool -> [Int] | ||
192 | trueIndices s = sFilter s [0..] | ||
193 | |||
194 | prop_trueIndices (getExpDB -> u) = all (streamToFun u) $ trueIndices u | ||
195 | |||
196 | invTrueIndices :: [Int] -> Stream Bool | ||
197 | invTrueIndices = f 0 where | ||
198 | f i [] = Repeat False | ||
199 | f i (k: ks) = iterateN (k - i) (cons False) $ cons True $ f (k + 1) ks | ||
200 | |||
201 | prop_invTrueIndices (map getNonNegative . Set.toList -> ks) = trueIndices (invTrueIndices ks) == ks | ||
202 | prop_invTrueIndices' (getExpDB -> u) = u == invTrueIndices (trueIndices u) | ||
203 | |||
204 | -- a Boolean stream can be seen as an index transformation function for indices 0..n | ||
205 | indexTrans :: Stream Bool -> Int -> Maybe Int | ||
206 | indexTrans s i = ((Just <$> sFilter s [0..]) ++ repeat Nothing) !! i | ||
207 | |||
208 | -- inverse of indexTrans | ||
209 | invIndexTrans :: Stream Bool -> Int -> Maybe Int | ||
210 | invIndexTrans s i = case dropWhile ((< i) . snd) $ zip [0..] $ sFilter s [0..] of | ||
211 | ((x, i'): _) | i' == i -> Just x | ||
212 | _ -> Nothing | ||
213 | |||
214 | prop_invIndexTrans u (getNonNegative -> i) = maybe True (==i) (indexTrans u i >>= invIndexTrans u) | ||
215 | |||
216 | diffDBs as = (u, filterDBUsed u <$> as) where u = mconcat as | ||
217 | |||
218 | |||
219 | ------------------------------------------------------------ used/unused de bruijn indices | ||
220 | |||
221 | -- which de bruijn indicies are used? | ||
222 | -- semantics of DBUsed is given by trueIndices | ||
223 | -- True: use index; False: skip index | ||
224 | type DBUsed = Stream Bool | ||
225 | |||
226 | -- invariant property: limes is False | ||
227 | -- finite indicies are used; lambda expressions are decorated with this | ||
228 | newtype ExpDB = ExpDB { getExpDB :: DBUsed } | ||
229 | deriving (Eq, Show) | ||
230 | |||
231 | instance Arbitrary ExpDB where | ||
232 | arbitrary = ExpDB . flip sFromList False <$> arbitrary | ||
233 | |||
234 | -- invariant property: limes is True | ||
235 | -- finite indicies are not used; good for index shifting transformations | ||
236 | newtype ShiftDB = ShiftDB { getShiftDB :: DBUsed } | ||
237 | deriving (Eq, Show) | ||
238 | |||
239 | instance Arbitrary ShiftDB where | ||
240 | arbitrary = ShiftDB . flip sFromList True <$> arbitrary | ||
241 | 35 | ||
242 | ------------------------------------------------------------ de bruijn index shifting layer | 36 | ------------------------------------------------------------ de bruijn index shifting layer |
243 | 37 | ||
@@ -278,6 +72,7 @@ mkShift e = Shift (getDBUsed e) e | |||
278 | instance (Arbitrary a, GetDBUsed a) => Arbitrary (Shift a) where | 72 | instance (Arbitrary a, GetDBUsed a) => Arbitrary (Shift a) where |
279 | arbitrary = upToShift <$> arbitrary | 73 | arbitrary = upToShift <$> arbitrary |
280 | 74 | ||
75 | |||
281 | ---------------- | 76 | ---------------- |
282 | 77 | ||
283 | -- for testing | 78 | -- for testing |
@@ -361,56 +156,86 @@ data Let e a = Let (Substs e) a | |||
361 | instance (GetDBUsed e, GetDBUsed a) => GetDBUsed (Let e a) where | 156 | instance (GetDBUsed e, GetDBUsed a) => GetDBUsed (Let e a) where |
362 | getDBUsed (Let m e) = getDBUsed $ ShiftLet (getDBUsed e <> mconcat (Map.elems $ getDBUsed <$> m)) m e | 157 | getDBUsed (Let m e) = getDBUsed $ ShiftLet (getDBUsed e <> mconcat (Map.elems $ getDBUsed <$> m)) m e |
363 | 158 | ||
159 | -- let with outer shifts | ||
160 | -- handles let keys removal / addition | ||
364 | pattern ShiftLet :: DBUsed -> Substs a -> b -> Shift (Let a b) | 161 | pattern ShiftLet :: DBUsed -> Substs a -> b -> Shift (Let a b) |
365 | pattern ShiftLet u m e <- (getShiftLet -> (u, m, e)) where ShiftLet u m e = Shift (filterDBUsed (not <$> substsKeys m) u) (Let m e) | 162 | pattern ShiftLet u m e <- (getShiftLet -> (u, m, e)) where ShiftLet u m e = Shift (filterDBUsed (not <$> substsKeys m) u) (Let m e) |
366 | 163 | ||
367 | getShiftLet (Shift u (Let m e)) = (mergeStreams (substsKeys m) (Repeat True) u, m, e) | 164 | getShiftLet (Shift u (Let m e)) = (mergeStreams (substsKeys m) (Repeat True) u, m, e) |
368 | 165 | ||
166 | -- push shift into let | ||
369 | -- TODO: remove Eq a | 167 | -- TODO: remove Eq a |
370 | pattern PShiftLet :: () => (Eq a, ShiftLike a, ShiftLike b) => Substs a -> b -> Shift (Let a b) | 168 | pattern PushedShiftLet :: () => (Eq a, ShiftLike a, ShiftLike b) => Substs a -> b -> Shift (Let a b) |
371 | pattern PShiftLet m e <- (pushShiftLet -> Let m e) where | 169 | pattern PushedShiftLet m e <- (pushShiftLet -> Let m e) where |
372 | PShiftLet m e = ShiftLet u (filterSubsts u m) $ modDBUsed (filterDBUsed u) e | 170 | PushedShiftLet m e = ShiftLet u (filterSubsts u m) $ modDBUsed (filterDBUsed u) e |
373 | where | 171 | where |
374 | u = getDBUsed e <> mconcat (Map.elems $ getDBUsed <$> m) | 172 | u = getDBUsed e <> mconcat (Map.elems $ getDBUsed <$> m) |
375 | 173 | ||
376 | pushShiftLet (ShiftLet u m e) = Let (expandSubsts u m) (up u e) | 174 | pushShiftLet (ShiftLet u m e) = Let (expandSubsts u m) (up u e) |
377 | 175 | ||
378 | mkLet :: (Eq a, ShiftLike a, ShiftLike b) => Substs a -> b -> Shift (Let a b) | 176 | mkLet :: (Eq a, ShiftLike a, ShiftLike b) => Substs a -> b -> Shift (Let a b) |
379 | mkLet m e = PShiftLet (Map.filterWithKey (\k _ -> streamToFun c k) m) e | 177 | mkLet m e = PushedShiftLet (Map.filterWithKey (\k _ -> streamToFun (transitiveClosure (getDBUsed <$> m) $ getDBUsed e) k) m) e |
178 | |||
179 | -- determine which let expressions are used (kinf of garbage collection) | ||
180 | -- TODO: speed this up somehow | ||
181 | transitiveClosure m e = limes $ sIterate f e | ||
380 | where | 182 | where |
381 | -- determine which let expressions are used (garbage collection) | 183 | f x = dbAnd ks $ x <> mconcat (sCatMaybes $ filterStream (Repeat Nothing) x us) |
382 | -- TODO: speed this up somehow | 184 | ks = substsKeys m |
383 | c = limes $ sIterate f $ getDBUsed e | 185 | us = substsStream m |
384 | where | 186 | |
385 | f x = dbAnd ks $ x <> mconcat (sCatMaybes $ filterStream (Repeat Nothing) x us) | 187 | {- TODO |
386 | ks = substsKeys m | 188 | prop_mkLet_idempotent = l == f l |
387 | us = substsStream $ getDBUsed <$> m | 189 | where |
190 | l = mkLet m e | ||
191 | f (Let m e) = mkLet m e | ||
192 | -} | ||
193 | |||
194 | mkLet_test1 = mkLet m e == Shift s (Let m' e') | ||
195 | where | ||
196 | e = f [0] | ||
197 | m = Map.fromList | ||
198 | [ (0, f [10]) | ||
199 | , (2, f []) | ||
200 | , (3, f []) | ||
201 | , (10, f [0, 2]) | ||
202 | ] | ||
203 | |||
204 | s = invTrueIndices [7] | ||
205 | e' = f [0] | ||
206 | m' = Map.fromList | ||
207 | [ (0, f [2]) | ||
208 | , (1, f []) | ||
209 | , (2, f [0, 1]) | ||
210 | ] | ||
211 | |||
212 | f x = Shift (invTrueIndices x) () | ||
388 | 213 | ||
389 | transportIntoLet (Let m _) e = up (not <$> substsKeys m) e | 214 | transportIntoLet (Let m _) e = up (not <$> substsKeys m) e |
390 | 215 | ||
391 | ----------------------------------------------------------------- MaybeLet | 216 | ----------------------------------------------------------------- MaybeLet |
392 | 217 | ||
393 | data MaybeLet a b c | 218 | data MaybeLet a b |
394 | = HasLet (Let a (Shift c)) | 219 | = HasLet (Let a (Shift b)) |
395 | | NoLet b | 220 | | NoLet b |
396 | deriving (Show, Eq) | 221 | deriving (Show, Eq, Functor) |
397 | |||
398 | type MaybeLet' a b = MaybeLet a b b | ||
399 | 222 | ||
400 | maybeLet :: (Eq a, ShiftLike a) => Shift (Let a (Shift b)) -> Shift (MaybeLet' a b) | 223 | maybeLet :: (Eq a, ShiftLike a) => Shift (Let a (Shift b)) -> Shift (MaybeLet a b) |
401 | maybeLet l@(Shift u (Let m e)) | 224 | maybeLet l@(Shift u (Let m e)) |
402 | | Map.null m = up u $ NoLet <$> e | 225 | | Map.null m = up u $ NoLet <$> e |
403 | | otherwise = HasLet <$> l | 226 | | otherwise = HasLet <$> l |
404 | 227 | ||
405 | joinLets :: (Eq a, ShiftLike a) => MaybeLet' a (MaybeLet' a b) -> MaybeLet' a b | 228 | joinLets :: (Eq a, ShiftLike a) => MaybeLet a (MaybeLet a b) -> MaybeLet a b |
406 | joinLets (NoLet e) = e | 229 | joinLets (NoLet e) = e |
407 | joinLets (HasLet (Let m (Shift s' (NoLet e)))) = HasLet $ Let m $ Shift s' e | 230 | joinLets (HasLet (Let m (Shift s' (NoLet e)))) = HasLet $ Let m $ Shift s' e |
408 | joinLets (HasLet (Let m (Shift s' (HasLet (Let m' e))))) | 231 | joinLets (HasLet (Let m (Shift s' (HasLet (Let m' e))))) |
409 | = HasLet $ Let (expandSubsts (not <$> substsKeys sm) m <> sm) se | 232 | = HasLet $ Let (expandSubsts (not <$> substsKeys sm) m <> sm) se |
410 | where | 233 | where |
411 | (PShiftLet sm se) = Shift s' (Let m' e) | 234 | (PushedShiftLet sm se) = Shift s' (Let m' e) |
412 | 235 | ||
413 | instance (GetDBUsed a, GetDBUsed b, GetDBUsed c) => GetDBUsed (MaybeLet a b c) where | 236 | -- TODO: test joinLets |
237 | |||
238 | instance (GetDBUsed a, GetDBUsed b) => GetDBUsed (MaybeLet a b) where | ||
414 | getDBUsed = \case | 239 | getDBUsed = \case |
415 | NoLet a -> getDBUsed a | 240 | NoLet a -> getDBUsed a |
416 | HasLet x -> getDBUsed x | 241 | HasLet x -> getDBUsed x |
@@ -448,7 +273,17 @@ type RHSExp = Exp Void | |||
448 | -- left-hand-side expression (allows RHS constructor) | 273 | -- left-hand-side expression (allows RHS constructor) |
449 | type LHSExp = Exp RHSExp | 274 | type LHSExp = Exp RHSExp |
450 | 275 | ||
451 | type WithLet a = MaybeLet (Shift LHSExp) a a | 276 | -- TODO: make this constant time operation |
277 | lhs :: RHSExp -> LHSExp | ||
278 | lhs = \case | ||
279 | ELit l -> ELit l | ||
280 | EVar -> EVar | ||
281 | ELamD e -> ELamD $ lhs e | ||
282 | ELam l -> ELam $ lhs <$> l | ||
283 | EApp a b -> EApp (lhs <$> a) (lhs <$> b) | ||
284 | RHS _ -> error "lhs: impossible" | ||
285 | |||
286 | type WithLet a = MaybeLet (Shift LHSExp) a | ||
452 | 287 | ||
453 | -------------------------------------------------------- | 288 | -------------------------------------------------------- |
454 | 289 | ||
@@ -474,33 +309,44 @@ newtype SimpleExp = SimpleExp { getSimpleExp :: SLExp } | |||
474 | 309 | ||
475 | instance Arbitrary SimpleExp where | 310 | instance Arbitrary SimpleExp where |
476 | arbitrary = fmap SimpleExp $ oneof | 311 | arbitrary = fmap SimpleExp $ oneof |
477 | [ var . getNonNegative <$> arbitrary | 312 | [ Var . getNonNegative <$> arbitrary |
478 | , Int <$> arbitrary | 313 | , Int <$> arbitrary |
479 | , app <$> (getSimpleExp <$> arbitrary) <*> (getSimpleExp <$> arbitrary) | 314 | , app <$> (getSimpleExp <$> arbitrary) <*> (getSimpleExp <$> arbitrary) |
480 | , lam <$> (getSimpleExp <$> arbitrary) | 315 | , lam <$> (getSimpleExp <$> arbitrary) |
481 | ] | 316 | ] |
482 | 317 | ||
318 | -- does no reduction | ||
319 | pattern SLLit :: Lit -> SLExp | ||
483 | pattern SLLit l <- (getLit -> Just l) where SLLit = Shift mempty . NoLet . ELit | 320 | pattern SLLit l <- (getLit -> Just l) where SLLit = Shift mempty . NoLet . ELit |
484 | 321 | ||
485 | getLit :: SLExp -> Maybe Lit | 322 | getLit :: SLExp -> Maybe Lit |
486 | getLit (Shift _ (NoLet (ELit l))) = Just l | 323 | getLit (Shift (Repeat False) (NoLet (ELit l))) = Just l |
487 | getLit (Shift _ (HasLet (Let _ (Shift _ (ELit l))))) = Just l | 324 | getLit (Shift _ (HasLet (Let _ (Shift _ (ELit l))))) = error "getLit: impossible: literals does not depend on variables" |
488 | getLit _ = Nothing | 325 | getLit _ = Nothing |
489 | 326 | ||
490 | pattern Int i = SLLit (LInt i) | 327 | pattern Int i = SLLit (LInt i) |
491 | 328 | ||
492 | var :: Int -> SLExp | 329 | -- TODO: should it reduce on pattern match? |
493 | var i = fmap NoLet $ up_ 0 i $ mkShift EVar | 330 | pattern Var :: Int -> SLExp |
331 | pattern Var i <- (getVar -> Just i) where Var i = fmap NoLet $ up_ 0 i $ mkShift EVar | ||
494 | 332 | ||
495 | prop_upVar (getNonNegative -> k) (getNonNegative -> n) (getNonNegative -> i) = up_ k n (var i) == var (if k <= i then n + i else i) | 333 | getVar (Shift u (NoLet EVar)) = Just $ fromMaybe (error "getVar: impossible") $ listToMaybe $ trueIndices u |
496 | prop_downVar (getNonNegative -> k) (getNonNegative -> i) = down_ k (var i) == case compare k i of LT -> Just (var $ i-1); EQ -> Nothing; GT -> Just (var i) | 334 | getVar (Shift _ (HasLet (Let _ (Shift _ _)))) = error "getVar: TODO" |
335 | getVar _ = Nothing | ||
336 | |||
337 | prop_Var (getNonNegative -> i) = case (Var i) of Var j -> i == j | ||
338 | |||
339 | prop_upVar (getNonNegative -> k) (getNonNegative -> n) (getNonNegative -> i) = up_ k n (Var i) == Var (if k <= i then n + i else i) | ||
340 | prop_downVar (getNonNegative -> k) (getNonNegative -> i) = down_ k (Var i) == case compare k i of LT -> Just (Var $ i-1); EQ -> Nothing; GT -> Just (Var i) | ||
497 | 341 | ||
498 | lam :: SLExp -> SLExp | 342 | lam :: SLExp -> SLExp |
499 | lam (Shift u e) = Shift (sTail u) $ if sHead u then eLam e else eLamD e | 343 | lam (Shift u e) = Shift (sTail u) $ if sHead u then eLam e else eLamD e |
500 | where | 344 | where |
501 | eLam (NoLet e) = NoLet $ ELam $ NoLet e | 345 | eLam (NoLet e) = NoLet $ ELam $ NoLet e |
502 | -- TODO: improve this by let-floating | 346 | -- TODO: improve this by let-floating |
503 | eLam (HasLet (Let m (Shift u x))) = NoLet $ ELam (HasLet (Let m (Shift u x))) | 347 | eLam (HasLet (Let m e)) = NoLet $ ELam (HasLet (Let m{-(filterSubsts (not <$> c) m)-} e)) |
348 | where | ||
349 | c = transitiveClosure (getDBUsed <$> m) $ Cons True $ Repeat False | ||
504 | 350 | ||
505 | eLamD (NoLet e) = NoLet $ ELamD e | 351 | eLamD (NoLet e) = NoLet $ ELamD e |
506 | -- TODO: review | 352 | -- TODO: review |
@@ -508,6 +354,28 @@ lam (Shift u e) = Shift (sTail u) $ if sHead u then eLam e else eLamD e | |||
508 | where | 354 | where |
509 | ul = Cons False $ Repeat True | 355 | ul = Cons False $ Repeat True |
510 | 356 | ||
357 | lam_test_let = lam $ lets_ m e -- == Shift s (Let m' e') | ||
358 | where | ||
359 | f (HasLet (Let m a)) = HasLet $ Let m a | ||
360 | |||
361 | e = Var 0 `app` Var 1 `app` Var 10 | ||
362 | m = Map.fromList | ||
363 | [ (0, Var 13) | ||
364 | , (2, Var 1) | ||
365 | , (3, Var 1) | ||
366 | , (10, Var 0 `app` Var 2) | ||
367 | ] | ||
368 | {- | ||
369 | s = invTrueIndices [7] | ||
370 | e' = f [0] | ||
371 | m' = Map.fromList | ||
372 | [ (0, f [2]) | ||
373 | , (1, f []) | ||
374 | , (2, f [0, 1]) | ||
375 | ] | ||
376 | -} | ||
377 | -- f x = Shift (invTrueIndices x) () | ||
378 | |||
511 | app :: SLExp -> SLExp -> SLExp | 379 | app :: SLExp -> SLExp -> SLExp |
512 | app (Shift ua (NoLet a)) (Shift ub (NoLet b)) | 380 | app (Shift ua (NoLet a)) (Shift ub (NoLet b)) |
513 | = Shift u $ NoLet $ EApp (Shift (filterDBUsed u ua) a) (Shift (filterDBUsed u ub) b) | 381 | = Shift u $ NoLet $ EApp (Shift (filterDBUsed u ua) a) (Shift (filterDBUsed u ub) b) |
@@ -530,6 +398,13 @@ app x y = f x y | |||
530 | lb'@(Let mb eb) = pushShiftLet $ Shift ulb' lb | 398 | lb'@(Let mb eb) = pushShiftLet $ Shift ulb' lb |
531 | xa = transportIntoLet lb' $ Shift ula' la | 399 | xa = transportIntoLet lb' $ Shift ula' la |
532 | 400 | ||
401 | -- TODO: handle lets inside | ||
402 | lets_ :: Substs SLExp -> SLExp -> SLExp | ||
403 | lets_ m e = lets (f <$> m) e | ||
404 | where | ||
405 | f :: SLExp -> Shift LHSExp | ||
406 | f (Shift u (NoLet e)) = Shift u $ lhs e | ||
407 | |||
533 | lets :: Substs (Shift LHSExp) -> SLExp -> SLExp | 408 | lets :: Substs (Shift LHSExp) -> SLExp -> SLExp |
534 | lets m e = fmap joinLets $ maybeLet $ mkLet m e | 409 | lets m e = fmap joinLets $ maybeLet $ mkLet m e |
535 | 410 | ||
@@ -559,7 +434,7 @@ pushShift (Shift u e) = ExpS $ case e of | |||
559 | LHS a b -> LHS_ a (up u <$> b) -- ??? $ SData (pushShift $ Shift u c) | 434 | LHS a b -> LHS_ a (up u <$> b) -- ??? $ SData (pushShift $ Shift u c) |
560 | -- Delta x -> Delta_ $ SData x | 435 | -- Delta x -> Delta_ $ SData x |
561 | 436 | ||
562 | prop_var (getNonNegative -> i) = case pushShift (fromLet $ var i) of | 437 | prop_Var (getNonNegative -> i) = case pushShift (fromLet $ Var i) of |
563 | ExpS (EVar i') -> i == i' | 438 | ExpS (EVar i') -> i == i' |
564 | _ -> False | 439 | _ -> False |
565 | 440 | ||
@@ -567,7 +442,7 @@ prop_app (getSimpleExp -> a) (getSimpleExp -> b) = case pushShift $ fromLet $ ap | |||
567 | ExpS (EApp a' b') -> (a', b') == (fromLet a, fromLet b) | 442 | ExpS (EApp a' b') -> (a', b') == (fromLet a, fromLet b) |
568 | _ -> False | 443 | _ -> False |
569 | 444 | ||
570 | --prop_lam (getNonNegative -> i) = elimShift undefined undefined undefined (==i) (var i) | 445 | --prop_lam (getNonNegative -> i) = elimShift undefined undefined undefined (==i) (Var i) |
571 | 446 | ||
572 | --prop_pushShift (Shift u e) = | 447 | --prop_pushShift (Shift u e) = |
573 | 448 | ||
@@ -600,7 +475,7 @@ pushLet' (Shift u l) = case l of | |||
600 | -- ELamD a -> ELamD $ NoLet a | 475 | -- ELamD a -> ELamD $ NoLet a |
601 | LHS a b -> LHS_ a ((fmap NoLet . up u) <$> b) | 476 | LHS a b -> LHS_ a ((fmap NoLet . up u) <$> b) |
602 | HasLet l -> case Shift u l of | 477 | HasLet l -> case Shift u l of |
603 | PShiftLet m e -> case pushShift e of | 478 | PushedShiftLet m e -> case pushShift e of |
604 | ExpS e' -> case e' of | 479 | ExpS e' -> case e' of |
605 | EApp a b -> ExpL $ EApp (fmap HasLet (mkLet m a)) (fmap HasLet (mkLet m b)) | 480 | EApp a b -> ExpL $ EApp (fmap HasLet (mkLet m a)) (fmap HasLet (mkLet m b)) |
606 | ELit i -> ExpL $ ELit i | 481 | ELit i -> ExpL $ ELit i |
@@ -634,7 +509,7 @@ hnf e = case pushLet' e of | |||
634 | ----------------------------------------------------------------------------------- | 509 | ----------------------------------------------------------------------------------- |
635 | -} | 510 | -} |
636 | idE :: SLExp | 511 | idE :: SLExp |
637 | idE = lam $ var 0 | 512 | idE = lam $ Var 0 |
638 | {- | 513 | {- |
639 | add :: SLExp | 514 | add :: SLExp |
640 | add = NoLet <$> mkShift (LHS "add" []) -- $ ELam $ NoLet $ ELam $ NoLet $ Delta f) | 515 | add = NoLet <$> mkShift (LHS "add" []) -- $ ELam $ NoLet $ ELam $ NoLet $ Delta f) |
@@ -652,7 +527,7 @@ example2 = app (app add (Int 10)) (Int 5) | |||
652 | ----------------------------------------------------------------- run all tests | 527 | ----------------------------------------------------------------- run all tests |
653 | -} | 528 | -} |
654 | return [] | 529 | return [] |
655 | runTests = $quickCheckAll | 530 | runTests | mkLet_test1 = $quickCheckAll |
656 | 531 | ||
657 | {- | 532 | {- |
658 | TODO | 533 | TODO |
@@ -666,7 +541,7 @@ TODO | |||
666 | - up, down | 541 | - up, down |
667 | - subst | 542 | - subst |
668 | - constructions | 543 | - constructions |
669 | - lam, pi, app, var, lit, ... | 544 | - lam, pi, app, Var, lit, ... |
670 | - eliminations | 545 | - eliminations |
671 | 546 | ||
672 | - intergrate into the compiler | 547 | - intergrate into the compiler |
diff --git a/prototypes/Stream.hs b/prototypes/Stream.hs new file mode 100644 index 00000000..4d68d3b0 --- /dev/null +++ b/prototypes/Stream.hs | |||
@@ -0,0 +1,248 @@ | |||
1 | {-# language ScopedTypeVariables #-} | ||
2 | {-# language LambdaCase #-} | ||
3 | {-# language TypeOperators #-} | ||
4 | {-# language TypeFamilies #-} | ||
5 | {-# language ViewPatterns #-} | ||
6 | {-# language PatternGuards #-} | ||
7 | {-# language PatternSynonyms #-} | ||
8 | {-# language RankNTypes #-} | ||
9 | {-# language DataKinds #-} | ||
10 | {-# language KindSignatures #-} | ||
11 | {-# language GADTs #-} | ||
12 | {-# language DeriveFunctor #-} | ||
13 | {-# language DeriveGeneric #-} | ||
14 | {-# language DefaultSignatures #-} | ||
15 | {-# language FlexibleInstances #-} | ||
16 | {-# language FlexibleContexts #-} | ||
17 | {-# language TemplateHaskell #-} -- for testing | ||
18 | {-# language NoMonomorphismRestriction #-} | ||
19 | module Stream where | ||
20 | |||
21 | import Data.Monoid | ||
22 | import Data.Maybe | ||
23 | import Data.List | ||
24 | import Data.Map (Map) | ||
25 | import qualified Data.Map as Map | ||
26 | import qualified Data.Set as Set | ||
27 | import Control.Monad | ||
28 | import Control.Arrow hiding (app) | ||
29 | import Test.QuickCheck | ||
30 | import Test.QuickCheck.Function | ||
31 | import GHC.Generics | ||
32 | import Debug.Trace | ||
33 | |||
34 | ------------------------------------------------------------ utils | ||
35 | |||
36 | iterateN i f x = iterate f x !! i | ||
37 | |||
38 | (<&>) = flip (<$>) | ||
39 | |||
40 | data Void | ||
41 | |||
42 | instance Eq Void where (==) = error "(==) @Void" | ||
43 | instance Show Void where show = error "show @Void" | ||
44 | |||
45 | {- used later? | ||
46 | -- supplementary data: data with no semantic relevance | ||
47 | newtype SData a = SData a | ||
48 | instance Show (SData a) where show _ = "SData" | ||
49 | instance Eq (SData a) where _ == _ = True | ||
50 | instance Ord (SData a) where _ `compare` _ = EQ | ||
51 | -} | ||
52 | |||
53 | ------------------------------------------------------------ streams | ||
54 | |||
55 | -- streams with constant tails | ||
56 | -- invariant property: Repeat is used when possible (see cons) | ||
57 | data Stream a | ||
58 | = Cons a (Stream a) | ||
59 | | Repeat a | ||
60 | deriving (Eq, Show, Functor) -- Functor is not proper, may break invariant | ||
61 | |||
62 | -- smart constructor to construct normal form of streams | ||
63 | cons b (Repeat b') | b == b' = Repeat b' | ||
64 | cons b x = Cons b x | ||
65 | |||
66 | -- stream head | ||
67 | sHead (Cons a _) = a | ||
68 | sHead (Repeat a) = a | ||
69 | |||
70 | -- stream tail | ||
71 | sTail (Cons _ a) = a | ||
72 | sTail (Repeat a) = Repeat a | ||
73 | |||
74 | instance Applicative Stream where | ||
75 | pure a = Repeat a | ||
76 | -- (<*>) is not proper, may break invariant | ||
77 | Repeat f <*> Repeat a = Repeat $ f a | ||
78 | x <*> y = Cons{-should be cons-} (sHead x $ sHead y) (sTail x <*> sTail y) | ||
79 | |||
80 | foldStream :: (b -> a -> a) -> (b -> a) -> Stream b -> a | ||
81 | foldStream f g (Cons b u) = f b (foldStream f g u) | ||
82 | foldStream f g (Repeat b) = g b | ||
83 | |||
84 | -- final value in the stream | ||
85 | limes :: Stream a -> a | ||
86 | limes = foldStream (flip const) id | ||
87 | |||
88 | prop_limes (getNonNegative -> n) = limes (sFromList [0..n-1] n) == n | ||
89 | |||
90 | -- replace limes by given stream | ||
91 | sCont :: Eq a => Stream a -> (a -> Stream a) -> Stream a | ||
92 | sCont as f = foldStream cons f as | ||
93 | |||
94 | -- semantics of Stream | ||
95 | streamToList :: Stream a -> [a] | ||
96 | streamToList = foldStream (:) repeat | ||
97 | |||
98 | streamToFun :: Stream a -> Int -> a | ||
99 | streamToFun u i = streamToList u !! i | ||
100 | |||
101 | sFromList :: Eq a => [a] -> a -> Stream a | ||
102 | sFromList xs b = foldr cons (Repeat b) xs | ||
103 | |||
104 | instance (Arbitrary a, Eq a) => Arbitrary (Stream a) where | ||
105 | arbitrary = sFromList <$> arbitrary <*> arbitrary | ||
106 | |||
107 | -- iterate on stream | ||
108 | sIterate :: Eq a => (a -> a) -> a -> Stream a | ||
109 | sIterate f x | ||
110 | | y == x = Repeat x | ||
111 | | otherwise = Cons x $ sIterate f y | ||
112 | where | ||
113 | y = f x | ||
114 | |||
115 | sCatMaybes :: Stream (Maybe a) -> [a] | ||
116 | sCatMaybes = foldStream (\m s -> maybe s (:s) m) (maybe [] repeat) | ||
117 | |||
118 | ---------------------------------------------------------- operations involving Boolean streams | ||
119 | |||
120 | mergeStreams :: Eq a => Stream Bool -> Stream a -> Stream a -> Stream a | ||
121 | mergeStreams (Cons True u) as bs = cons (sHead as) $ mergeStreams u (sTail as) bs | ||
122 | mergeStreams (Cons False u) as bs = cons (sHead bs) $ mergeStreams u as (sTail bs) | ||
123 | mergeStreams (Repeat True) as bs = as | ||
124 | mergeStreams (Repeat False) as bs = bs | ||
125 | |||
126 | sFilter :: Stream Bool -> [a] -> [a] | ||
127 | sFilter (Cons True u) is = take 1 is ++ sFilter u (drop 1 is) | ||
128 | sFilter (Cons False u) is = sFilter u (drop 1 is) | ||
129 | sFilter (Repeat True) is = is | ||
130 | sFilter (Repeat False) is = [] | ||
131 | |||
132 | -- sFilter for streams | ||
133 | -- the first stream is used when no more element can pass the filter | ||
134 | filterStream :: Eq a => Stream a -> Stream Bool -> Stream a -> Stream a | ||
135 | filterStream d (Cons True s) as = cons (sHead as) $ filterStream d s $ sTail as | ||
136 | filterStream d (Cons False s) as = filterStream d s $ sTail as | ||
137 | filterStream d (Repeat True) as = as | ||
138 | filterStream d (Repeat False) as = d | ||
139 | |||
140 | sOr :: Stream Bool -> Stream Bool -> Stream Bool | ||
141 | sOr (Cons b u) (Cons b' u') = cons (b || b') $ sOr u u' | ||
142 | sOr (Repeat False) u = u | ||
143 | sOr (Repeat True) u = Repeat True | ||
144 | sOr u (Repeat False) = u | ||
145 | sOr u (Repeat True) = Repeat True | ||
146 | |||
147 | prop_sOr_idemp a = sOr a a == a | ||
148 | prop_sOr_comm a b = sOr a b == sOr b a | ||
149 | |||
150 | dbAnd a b = not <$> sOr (not <$> a) (not <$> b) | ||
151 | |||
152 | instance Monoid (Stream Bool) where | ||
153 | mempty = Repeat False | ||
154 | mappend = sOr | ||
155 | |||
156 | prop_StreamBool_monoid_left (a :: Stream Bool) = mempty <> a == a | ||
157 | prop_StreamBool_monoid_right (a :: Stream Bool) = a <> mempty == a | ||
158 | prop_StreamBool_monoid_assoc (a :: Stream Bool) b c = (a <> b) <> c == a <> (b <> c) | ||
159 | |||
160 | -- composition of (Stream Bool) values (by sFilter semantics) | ||
161 | sComp :: Stream Bool -> Stream Bool -> Stream Bool | ||
162 | sComp bs as = mergeStreams bs as $ Repeat False | ||
163 | |||
164 | prop_sComp a b xs = sFilter (sComp a b) xs == (sFilter b . sFilter a) xs | ||
165 | prop_sComp_trans a b (getNonNegative -> i) = indexTrans (sComp a b) i == (indexTrans a =<< indexTrans b i) | ||
166 | |||
167 | filterDBUsed :: Stream Bool -> Stream Bool -> Stream Bool | ||
168 | filterDBUsed = filterStream $ Repeat False | ||
169 | |||
170 | --prop_filterDBUsed bs = mergeStreams bs xs ys sOr b a `sComp` filterDBUsed (sOr b a) a == a | ||
171 | |||
172 | prop_filterDBUsed a b = sOr b a `sComp` filterDBUsed (sOr b a) a == a | ||
173 | |||
174 | compress s = filterDBUsed s s | ||
175 | |||
176 | |||
177 | --takeUps :: Int -> Stream Bool -> Stream Bool | ||
178 | --takeUps i = (`sComp` sFromList (replicate i True) False) | ||
179 | |||
180 | --prop_takeUps (getNonNegative -> n) u = streamToList (takeUps n u) == normSem (take n $ streamToList u) | ||
181 | |||
182 | --takeUps' :: Int -> Stream Bool -> Stream Bool | ||
183 | --takeUps' i = sComp $ sFromList (replicate i True) False | ||
184 | |||
185 | --prop_takeUps' u (getNonNegative -> n) = streamToList (takeUps' n u) == head (dropWhile ((< n) . length . filter id) (inits $ streamToList u) ++ [streamToList u]) | ||
186 | |||
187 | --------------------------------------------------------------- indices | ||
188 | |||
189 | -- index of the first appearance of the limes | ||
190 | limesIndex :: Stream a -> Int | ||
191 | limesIndex = foldStream (const (+1)) (const 0) | ||
192 | |||
193 | -- indices at which the stream value is True | ||
194 | trueIndices :: Stream Bool -> [Int] | ||
195 | trueIndices s = sFilter s [0..] | ||
196 | |||
197 | prop_trueIndices (getExpDB -> u) = all (streamToFun u) $ trueIndices u | ||
198 | |||
199 | invTrueIndices :: [Int] -> Stream Bool | ||
200 | invTrueIndices = f 0 where | ||
201 | f i [] = Repeat False | ||
202 | f i (k: ks) = iterateN (k - i) (cons False) $ cons True $ f (k + 1) ks | ||
203 | |||
204 | prop_invTrueIndices (map getNonNegative . Set.toList -> ks) = trueIndices (invTrueIndices ks) == ks | ||
205 | prop_invTrueIndices' (getExpDB -> u) = u == invTrueIndices (trueIndices u) | ||
206 | |||
207 | -- a Boolean stream can be seen as an index transformation function for indices 0..n | ||
208 | indexTrans :: Stream Bool -> Int -> Maybe Int | ||
209 | indexTrans s i = ((Just <$> sFilter s [0..]) ++ repeat Nothing) !! i | ||
210 | |||
211 | -- inverse of indexTrans | ||
212 | invIndexTrans :: Stream Bool -> Int -> Maybe Int | ||
213 | invIndexTrans s i = case dropWhile ((< i) . snd) $ zip [0..] $ sFilter s [0..] of | ||
214 | ((x, i'): _) | i' == i -> Just x | ||
215 | _ -> Nothing | ||
216 | |||
217 | prop_invIndexTrans u (getNonNegative -> i) = maybe True (==i) (indexTrans u i >>= invIndexTrans u) | ||
218 | |||
219 | diffDBs as = (u, filterDBUsed u <$> as) where u = mconcat as | ||
220 | |||
221 | ------------------------------------------------------------ used/unused de bruijn indices | ||
222 | |||
223 | -- which de bruijn indicies are used? | ||
224 | -- semantics of DBUsed is given by trueIndices | ||
225 | -- True: use index; False: skip index | ||
226 | type DBUsed = Stream Bool | ||
227 | |||
228 | -- invariant property: limes is False | ||
229 | -- finite indicies are used; lambda expressions are decorated with this | ||
230 | newtype ExpDB = ExpDB { getExpDB :: DBUsed } | ||
231 | deriving (Eq, Show) | ||
232 | |||
233 | instance Arbitrary ExpDB where | ||
234 | arbitrary = ExpDB . flip sFromList False <$> arbitrary | ||
235 | |||
236 | -- invariant property: limes is True | ||
237 | -- finite indicies are not used; good for index shifting transformations | ||
238 | newtype ShiftDB = ShiftDB { getShiftDB :: DBUsed } | ||
239 | deriving (Eq, Show) | ||
240 | |||
241 | instance Arbitrary ShiftDB where | ||
242 | arbitrary = ShiftDB . flip sFromList True <$> arbitrary | ||
243 | |||
244 | ------------------------------------------------------------------ | ||
245 | |||
246 | return [] | ||
247 | main = $quickCheckAll | ||
248 | |||