diff options
author | Péter Diviánszky <divipp@gmail.com> | 2016-05-16 04:33:01 +0200 |
---|---|---|
committer | Péter Diviánszky <divipp@gmail.com> | 2016-05-16 04:33:01 +0200 |
commit | 503ff0250240f487d7562ec1c83e4c3251479f0b (patch) | |
tree | 947dd8e01b54550cbb7b08b09e930c19af1f719c /prototypes/LamMachine.hs | |
parent | 7a8eabd1a066579d4dcb35f5950f87bad5667b37 (diff) |
LamMachine
Diffstat (limited to 'prototypes/LamMachine.hs')
-rw-r--r-- | prototypes/LamMachine.hs | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/prototypes/LamMachine.hs b/prototypes/LamMachine.hs new file mode 100644 index 00000000..3bfbe104 --- /dev/null +++ b/prototypes/LamMachine.hs | |||
@@ -0,0 +1,402 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | {-# LANGUAGE PatternSynonyms #-} | ||
3 | {-# LANGUAGE PatternGuards #-} | ||
4 | {-# LANGUAGE ViewPatterns #-} | ||
5 | {-# LANGUAGE LambdaCase #-} | ||
6 | {-# LANGUAGE TypeSynonymInstances #-} | ||
7 | {-# LANGUAGE FlexibleInstances #-} | ||
8 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
9 | |||
10 | import Data.List | ||
11 | import Data.Maybe | ||
12 | import Control.Arrow | ||
13 | import Control.Category hiding ((.)) | ||
14 | import Control.Monad.Writer | ||
15 | import Control.Monad.Identity | ||
16 | import Debug.Trace | ||
17 | import System.Environment | ||
18 | |||
19 | import LambdaCube.Compiler.Pretty | ||
20 | import LambdaCube.Compiler.DeBruijn hiding (up) | ||
21 | |||
22 | ----------------- | ||
23 | |||
24 | -- expression | ||
25 | data Exp_ | ||
26 | = Lam_ Exp | ||
27 | | Var_ Int | ||
28 | | App_ Exp Exp | ||
29 | | Seq_ Exp Exp | ||
30 | | Con_ String Int [Exp] | ||
31 | | Case_ Exp [(String, Exp)] | ||
32 | | Int_ Int | ||
33 | | Op1_ Op1 Exp | ||
34 | | Op2_ Op2 Exp Exp | ||
35 | | Y_ Exp | ||
36 | deriving (Eq) | ||
37 | |||
38 | data Op1 = Round | ||
39 | deriving (Eq, Show) | ||
40 | |||
41 | data Op2 = Add | Sub | Mod | LessEq | EqInt | ||
42 | deriving (Eq, Show) | ||
43 | |||
44 | -- cached free variables set | ||
45 | data Exp = Exp FreeVars Exp_ | ||
46 | |||
47 | -- state of the machine | ||
48 | data MSt = MSt [(FreeVars, Exp)] -- TODO: use finger tree instead of list | ||
49 | Exp | ||
50 | [Exp] -- TODO: use finger tree instead of list | ||
51 | |||
52 | --------------------------------------------------------------------- toolbox: pretty print | ||
53 | |||
54 | instance PShow Exp where | ||
55 | pShow = \case | ||
56 | Var i -> DVar i | ||
57 | App a b -> DApp (pShow a) (pShow b) | ||
58 | Seq a b -> DOp "`seq`" (Infix 1) (pShow a) (pShow b) | ||
59 | Lam e -> shLam_ True $ pShow e | ||
60 | Con s i xs -> foldl DApp (text s) $ pShow <$> xs | ||
61 | Int i -> pShow i | ||
62 | Op1 o x -> text (show o) `DApp` pShow x | ||
63 | Op2 EqInt x y -> DOp "==" (Infix 4) (pShow x) (pShow y) | ||
64 | Op2 Add x y -> DOp "+" (InfixL 6) (pShow x) (pShow y) | ||
65 | Op2 o x y -> text (show o) `DApp` pShow x `DApp` pShow y | ||
66 | Y e -> "Y" `DApp` pShow e | ||
67 | Case e xs -> DPreOp (-20) (ComplexAtom "case" (-10) (pShow e) (SimpleAtom "of")) $ foldr1 DSemi [DArr_ "->" (text a) (pShow b) | (a, b) <- xs] | ||
68 | |||
69 | shLam_ usedVar b = DFreshName usedVar $ showLam (DVar 0) b | ||
70 | |||
71 | showLam x (DFreshName u d) = DFreshName u $ showLam (DUp 0 x) d | ||
72 | showLam x (DLam xs y) = DLam (DSep (InfixR 11) x xs) y | ||
73 | showLam x y = DLam x y | ||
74 | |||
75 | shLet i a b = DLet' (DLet "=" (blue $ shVar i) $ DUp i a) (DUp i b) | ||
76 | |||
77 | showLet x (DFreshName u d) = DFreshName u $ showLet (DUp 0 x) d | ||
78 | showLet x (DLet' xs y) = DLet' (DSemi x xs) y | ||
79 | showLet x y = DLet' x y | ||
80 | |||
81 | shLet_ a b = DFreshName True $ showLet (DLet "=" (shVar 0) $ DUp 0 a) b | ||
82 | |||
83 | instance PShow MSt where | ||
84 | pShow (MSt as b bs) = case foldl (flip (:)) (DBrace (pShow b): [pShow x | x <- bs]) [pShow x | EPP x <- as] of | ||
85 | x: xs -> foldl (flip shLet_) x xs | ||
86 | |||
87 | |||
88 | --------------------------------------------------------------------- toolbox: free variables | ||
89 | |||
90 | instance Eq Exp where Exp _ a == Exp _ b = a == b | ||
91 | |||
92 | instance HasFreeVars Exp where | ||
93 | getFreeVars (Exp fv _) = fv | ||
94 | |||
95 | pattern Int i <- Exp _ (Int_ i) | ||
96 | where Int i = Exp mempty $ Int_ i | ||
97 | pattern App a b <- Exp _ (App_ a b) | ||
98 | where App a b = Exp (getFreeVars a <> getFreeVars b) $ App_ a b | ||
99 | pattern Seq a b <- Exp _ (Seq_ a b) | ||
100 | where Seq a b = Exp (getFreeVars a <> getFreeVars b) $ Seq_ a b | ||
101 | pattern Op2 op a b <- Exp _ (Op2_ op a b) | ||
102 | where Op2 op a b = Exp (getFreeVars a <> getFreeVars b) $ Op2_ op a b | ||
103 | pattern Op1 op a <- Exp _ (Op1_ op a) | ||
104 | where Op1 op a = Exp (getFreeVars a) $ Op1_ op a | ||
105 | pattern Var i <- Exp _ (Var_ i) | ||
106 | where Var i = Exp (freeVar i) $ Var_ i | ||
107 | pattern Lam i <- Exp _ (Lam_ i) | ||
108 | where Lam i = Exp (shiftFreeVars (-1) $ getFreeVars i) $ Lam_ i | ||
109 | pattern Y i <- Exp _ (Y_ i) | ||
110 | where Y i = Exp (getFreeVars i) $ Y_ i | ||
111 | pattern Con a b i <- Exp _ (Con_ a b i) | ||
112 | where Con a b i = Exp (foldMap getFreeVars i) $ Con_ a b i | ||
113 | pattern Case a b <- Exp _ (Case_ a b) | ||
114 | where Case a b = Exp (getFreeVars a <> foldMap (getFreeVars . snd) b) $ Case_ a b | ||
115 | |||
116 | infixl 4 `App` | ||
117 | |||
118 | --------------------------------------------------------------------- toolbox: de bruijn index shifting | ||
119 | -- TODO: speedup these with reification | ||
120 | |||
121 | data Up = Up !Int{-level-} !Int{-num-} | ||
122 | |||
123 | up :: Up -> Exp -> Exp | ||
124 | up (Up i num) e = f i e where | ||
125 | f i e@(Exp s x) | ||
126 | | dbGE i s = e | ||
127 | | otherwise = Exp (rearrangeFreeVars (RFUp num) i s) $ case x of | ||
128 | App_ a b -> App_ (f i a) (f i b) | ||
129 | Seq_ a b -> Seq_ (f i a) (f i b) | ||
130 | Con_ cn s xs -> Con_ cn s (f i <$> xs) | ||
131 | Case_ s xs -> Case_ (f i s) (second (f i) <$> xs) | ||
132 | Lam_ e -> Lam_ (f (i+1) e) | ||
133 | Var_ k | i <= k -> Var_ (k + num) | ||
134 | | otherwise -> Var_ k | ||
135 | x@Int_{} -> x | ||
136 | Y_ a -> Y_ $ f i a | ||
137 | Op1_ op a -> Op1_ op (f i a) | ||
138 | Op2_ op a b -> Op2_ op (f i a) (f i b) | ||
139 | |||
140 | |||
141 | ups' a b = ups $ Up a b | ||
142 | |||
143 | ups :: Up -> [(FreeVars, Exp)] -> [(FreeVars, Exp)] | ||
144 | ups l [] = [] | ||
145 | ups l@(Up i _) xs@((s, e): es) | ||
146 | | dbGE i s = xs | ||
147 | | otherwise = eP (up l e) $ ups (incUp 1 l) es | ||
148 | |||
149 | incUp t (Up l n) = Up (l+t) n | ||
150 | |||
151 | eP x [] = [(getFreeVars x, x)] | ||
152 | eP x xs@((s, _):_) = (getFreeVars x <> lowerFreeVars s, x): xs | ||
153 | |||
154 | pattern EPP x <- (_, x) | ||
155 | |||
156 | --------------------------- | ||
157 | |||
158 | down i x | usedVar i x = Nothing | ||
159 | down i x = Just $ down_ i x | ||
160 | |||
161 | down_ i e@(Exp s x) | ||
162 | | dbGE i s = e | ||
163 | | otherwise = Exp (delVar i s) $ case x of | ||
164 | Var_ j | j > i -> Var_ $ j - 1 | ||
165 | | otherwise -> Var_ j | ||
166 | Lam_ e -> Lam_ $ down_ (i+1) e | ||
167 | Y_ e -> Y_ $ down_ i e | ||
168 | App_ a b -> App_ (down_ i a) (down_ i b) | ||
169 | Seq_ a b -> Seq_ (down_ i a) (down_ i b) | ||
170 | Con_ s k es -> Con_ s k $ (down_ i <$> es) | ||
171 | Case_ e es -> Case_ (down_ i e) $ map (second $ down_ i) es | ||
172 | Int_ i -> Int_ i | ||
173 | Op1_ o e -> Op1_ o $ down_ i e | ||
174 | Op2_ o e f -> Op2_ o (down_ i e) (down_ i f) | ||
175 | |||
176 | tryRemoves xs = tryRemoves_ (Var <$> freeVars xs) | ||
177 | tryRemoves_ [] dt = dt | ||
178 | tryRemoves_ (Var i: vs) dt | ||
179 | | Just dt' <- tryRemove_ i dt | ||
180 | = tryRemoves_ (catMaybes $ down i <$> vs) dt' | ||
181 | | otherwise = tryRemoves_ vs dt | ||
182 | |||
183 | tryRemove i x = fromMaybe x $ tryRemove_ i x | ||
184 | |||
185 | tryRemove_ i dt@(MSt xs e es) | ||
186 | | Just e' <- down i e | ||
187 | , Just xs' <- downUp i xs | ||
188 | , Just es' <- downDown i es | ||
189 | = Just $ MSt xs' e' es' | ||
190 | | otherwise | ||
191 | = Nothing | ||
192 | |||
193 | downEP i ( x) = down i x | ||
194 | downEP_ i (s, x) = (delVar i s, down_ i x) | ||
195 | |||
196 | downUp i [] = Just [] | ||
197 | downUp i x@((s, _): _) | ||
198 | | usedVar (i+1) s = Nothing | ||
199 | | otherwise = Just $ downUp_ i x | ||
200 | |||
201 | downUp_ i [] = [] | ||
202 | downUp_ i (x: xs) | ||
203 | | x' <- downEP_ (i+1) x | ||
204 | , xs' <- downUp_ (i+1) xs | ||
205 | = x': xs' | ||
206 | |||
207 | downDown i [] = Just [] | ||
208 | downDown 0 (_: xs) = Just xs | ||
209 | downDown i (x: xs) | ||
210 | | Just x' <- downEP (i-1) x | ||
211 | , Just xs' <- downDown (i-1) xs | ||
212 | = Just $ x': xs' | ||
213 | | otherwise = Nothing | ||
214 | |||
215 | --------------------------------------------------------------------- toolbox: machine monad | ||
216 | |||
217 | class Monad m => MachineMonad m where | ||
218 | traceStep :: String -> m () | ||
219 | collectSizeStat :: Int -> m () | ||
220 | |||
221 | instance MachineMonad Identity where | ||
222 | traceStep _ = return () | ||
223 | collectSizeStat _ = return () | ||
224 | |||
225 | instance MachineMonad IO where | ||
226 | traceStep s = return () | ||
227 | -- traceStep = putStrLn | ||
228 | collectSizeStat s = return () | ||
229 | |||
230 | instance MachineMonad (Writer [Int]) where | ||
231 | traceStep s = return () | ||
232 | collectSizeStat s = tell [s] | ||
233 | |||
234 | runMachineStat e = putStr $ unlines $ ppShow t: "--------": show (length w, w):[] | ||
235 | where | ||
236 | (t, w) = runWriter (hnf e :: Writer [Int] MSt) | ||
237 | |||
238 | runMachineIO e = do | ||
239 | t <- hnf e :: IO MSt | ||
240 | putStr $ unlines $ ppShow t: [] | ||
241 | |||
242 | runMachinePure e = putStr $ unlines $ ppShow t: [] | ||
243 | where | ||
244 | t = runIdentity $ hnf e | ||
245 | |||
246 | ----------------------------------------------------------- machine code begins here | ||
247 | |||
248 | -- big step | ||
249 | step :: MachineMonad m => MSt -> m MSt | ||
250 | step dt@(MSt t e vs) = case e of | ||
251 | |||
252 | Int{} -> return dt | ||
253 | |||
254 | Lam{} -> return dt | ||
255 | |||
256 | Con cn i xs | ||
257 | | lz /= 0 -> return $ MSt (ups' 1 lz t) (Con cn i xs') $ zs ++ vs -- share complex constructor arguments | ||
258 | | otherwise -> return dt | ||
259 | where | ||
260 | lz = length zs | ||
261 | (xs', concat -> zs) = unzip $ f 0 xs | ||
262 | f i [] = [] | ||
263 | f i (x: xs) | simple x = (up (Up 0 lz) x, []): f i xs | ||
264 | | otherwise = (Var i, [up (Up 0 (lz - i - 1)) x]): f (i+1) xs | ||
265 | |||
266 | Var i -> lookupHNF "var" (\e (Var i) -> e) i dt | ||
267 | |||
268 | Seq Int{} b -> stepMsg "seq" $ MSt t b vs | ||
269 | Seq a@Lam{} b -> stepMsg "seq" $ tryRemoves (getFreeVars a) $ MSt t b vs | ||
270 | Seq a@Con{} b -> stepMsg "seq" $ tryRemoves (getFreeVars a) $ MSt t b vs | ||
271 | Seq (Var i) _ -> lookupHNF' "seqvar" (\e (Seq _ b) -> b) i dt | ||
272 | Seq a b -> stepMsg "seqexp" $ MSt (ups' 1 1 t) (Seq (Var 0) $ up (Up 0 1) b) $ a: vs | ||
273 | |||
274 | -- TODO: handle recursive constants | ||
275 | Y (Lam x) -> stepMsg "Y" $ MSt (ups' 1 1 t) x $ e: vs | ||
276 | |||
277 | App (Lam x) b | usedVar 0 x | ||
278 | -> stepMsg "app" $ MSt (ups' 1 1 t) x $ b: vs | ||
279 | App (Lam x) b -> stepMsg "appdel" $ tryRemoves (getFreeVars b) $ MSt t x vs | ||
280 | App (Var i) _ -> lookupHNF' "appvar" (\e (App _ y) -> App e y) i dt | ||
281 | App a b -> stepMsg "appexp" $ MSt (ups' 1 1 t) (App (Var 0) $ up (Up 0 1) b) $ a: vs | ||
282 | |||
283 | Case (Con cn i es) cs -> stepMsg "case" $ tryRemoves (foldMap (getFreeVars . snd) $ delElem i cs) $ (MSt t (foldl App (snd $ cs !! i) es) vs) | ||
284 | Case (Var i) _ -> lookupHNF' "casevar" (\e (Case _ cs) -> Case e cs) i dt | ||
285 | Case v cs -> stepMsg "caseexp" $ MSt (ups' 1 1 t) (Case (Var 0) $ second (up (Up 0 1)) <$> cs) $ v: vs | ||
286 | |||
287 | Op2 op (Int e) (Int f) -> return $ MSt t (int op e f) vs | ||
288 | where | ||
289 | int Add a b = Int $ a + b | ||
290 | int Sub a b = Int $ a - b | ||
291 | int Mod a b = Int $ a `mod` b | ||
292 | int LessEq a b = if a <= b then T else F | ||
293 | int EqInt a b = if a == b then T else F | ||
294 | Op2 op (Var i) _ -> lookupHNF' "op2-1var" (\e (Op2 op _ y) -> Op2 op e y) i dt | ||
295 | Op2 op _ (Var i) -> lookupHNF' "op2-2var" (\e (Op2 op x _) -> Op2 op x e) i dt | ||
296 | Op2 op x@Int{} y -> stepMsg "op2" $ MSt (ups' 1 1 t) (Op2 op x (Var 0)) $ y: vs | ||
297 | Op2 op y x@Int{} -> stepMsg "op2" $ MSt (ups' 1 1 t) (Op2 op (Var 0) x) $ y: vs | ||
298 | Op2 op x y -> stepMsg "op2" $ MSt (ups' 1 2 t) (Op2 op (Var 0) (Var 1)) $ x: y: vs | ||
299 | |||
300 | stepMsg :: MachineMonad m => String -> MSt -> m MSt | ||
301 | stepMsg msg dt = do | ||
302 | traceStep $ ((msg ++ "\n") ++) $ show $ pShow dt | ||
303 | collectSizeStat $ size dt | ||
304 | step dt | ||
305 | |||
306 | hnf e = stepMsg "hnf" $ MSt [] e [] | ||
307 | |||
308 | size (MSt xs _ ys) = length xs + length ys | ||
309 | |||
310 | shiftL (MSt xs x (e: es)) = MSt (eP x xs) e es | ||
311 | shiftR (MSt (EPP x: xs) e es) = MSt xs x $ e: es | ||
312 | |||
313 | shiftLookup f n dt@(MSt _ e _) = repl $ iterate shiftR dt !! (n+1) where | ||
314 | repl (MSt xs z es) = MSt xs (f (up (Up 0 (n+1)) e) z) es | ||
315 | |||
316 | -- lookup var in head normal form | ||
317 | lookupHNF msg f i dt = tryRemove i . shiftLookup f i <$> stepMsg msg (iterate shiftL dt !! (i+1)) | ||
318 | |||
319 | -- lookup & step | ||
320 | lookupHNF' msg f i dt = stepMsg ("C " ++ msg) =<< lookupHNF msg f i dt | ||
321 | |||
322 | simple = \case | ||
323 | Var{} -> True | ||
324 | Int{} -> True | ||
325 | _ -> False | ||
326 | |||
327 | delElem i xs = take i xs ++ drop (i+1) xs | ||
328 | |||
329 | ---------------------------------------------------------------------------------------- examples | ||
330 | |||
331 | id_ = Lam (Var 0) | ||
332 | |||
333 | pattern F = Con "False" 0 [] | ||
334 | pattern T = Con "True" 1 [] | ||
335 | pattern Nil = Con "[]" 0 [] | ||
336 | pattern Cons a b = Con "Cons" 1 [a, b] | ||
337 | |||
338 | caseBool x f t = Case x [("False", f), ("True", t)] | ||
339 | caseList x n c = Case x [("[]", n), ("Cons", c)] | ||
340 | |||
341 | if_ b t f = caseBool b f t | ||
342 | |||
343 | not_ x = caseBool x T F | ||
344 | |||
345 | test = runMachinePure (id_ `App` id_ `App` id_ `App` id_ `App` Con "()" 0 []) | ||
346 | |||
347 | test' = runMachinePure (id_ `App` (id_ `App` Con "()" 0 [])) | ||
348 | |||
349 | foldr_ f e = Y $ Lam $ Lam $ caseList (Var 0) (up (Up 0 2) e) (Lam $ Lam $ up (Up 0 4) f `App` Var 1 `App` (Var 3 `App` Var 0)) | ||
350 | |||
351 | filter_ p = foldr_ (Lam $ Lam $ if_ (p `App` Var 1) (Cons (Var 1) (Var 0)) (Var 0)) Nil | ||
352 | |||
353 | and2 a b = if_ a b F | ||
354 | |||
355 | and_ = foldr_ (Lam $ Lam $ and2 (Var 1) (Var 0)) T | ||
356 | |||
357 | map_ f = foldr_ (Lam $ Lam $ Cons (f (Var 1)) (Var 0)) Nil | ||
358 | |||
359 | neq a b = not_ $ Op2 EqInt a b | ||
360 | |||
361 | from_ = Y $ Lam $ Lam $ Cons (Var 0) $ Var 1 `App` Op2 Add (Var 0) (Int 1) | ||
362 | |||
363 | idx xs n = caseList xs undefined $ Lam $ Lam $ if_ (Op2 EqInt n $ Int 0) (Var 1) $ idx (Var 0) (Op2 Sub n $ Int 1) | ||
364 | |||
365 | t = runMachinePure $ idx (from_ `App` Int 3) (Int 5) | ||
366 | |||
367 | takeWhile_ p xs = caseList xs Nil $ Lam $ Lam $ if_ (p (Var 1)) (Cons (Var 1) $ takeWhile_ p (Var 0)) Nil | ||
368 | |||
369 | sum_ = foldr_ (Lam $ Lam $ Op2 Add (Var 1) (Var 0)) (Int 0) | ||
370 | |||
371 | sum' = Y $ Lam $ Lam $ caseList (Var 0) (Int 0) $ Lam $ Lam $ Op2 Add (Var 1) $ Var 3 `App` Var 0 | ||
372 | |||
373 | infixl 4 `sApp` | ||
374 | |||
375 | sApp a b = Seq b (App a b) | ||
376 | |||
377 | {- | ||
378 | accsum acc [] = acc | ||
379 | accsum acc (x: xs) = let z = acc + x `seq` accsum z xs | ||
380 | -} | ||
381 | accsum = Y $ Lam $ Lam $ Lam $ caseList (Var 0) (Var 1) $ Lam $ Lam $ Var 4 `sApp` Op2 Add (Var 3) (Var 1) `App` Var 0 | ||
382 | |||
383 | fromTo = Y $ Lam $ Lam $ Lam $ Cons (Var 1) $ if_ (Op2 EqInt (Var 0) (Var 1)) Nil $ Var 2 `App` Op2 Add (Var 1) (Int 1) `App` Var 0 | ||
384 | |||
385 | t' n = sum' `App` (fromTo `App` Int 0 `App` Int n) -- takeWhile_ (\x -> Op2 LessEq x $ Int 3) (from_ `App` Int 0) | ||
386 | |||
387 | t'' n = accsum `App` Int 0 `App` (fromTo `App` Int 0 `App` Int n) -- takeWhile_ (\x -> Op2 LessEq x $ Int 3) (from_ `App` Int 0) | ||
388 | |||
389 | main = do | ||
390 | [b, n] <- getArgs | ||
391 | runMachineIO $ case b of | ||
392 | "lazy" -> t' $ read n | ||
393 | "seq" -> t'' $ read n | ||
394 | |||
395 | {- TODO | ||
396 | |||
397 | primes :: [Int] | ||
398 | primes = 2:3: filter (\n -> and $ map (\p -> n `mod` p /= 0) (takeWhile (\x -> x <= iSqrt n) primes)) (from 5) | ||
399 | |||
400 | |||
401 | main = primes !! 3000 | ||
402 | -} | ||