1
+ {-# LANGUAGE ScopedTypeVariables #-}
2
+ -- REPL for untyped lambda calculus
3
+ module UnTyLambda.REPL where
4
+
5
+ import Prelude hiding (catch )
6
+ import Monstupar
7
+ import UnTyLambda.Interpreter
8
+ import Data.List
9
+
10
+ import Control.Exception
11
+
12
+ -- Парсим строку в терм
13
+ parseLambda :: Monstupar Char Term
14
+ parseLambda = do
15
+ atom <- parseAtom
16
+ spaces
17
+ other <- parseLambda'
18
+ return $ makeApp atom other
19
+
20
+ makeApp = foldl' App
21
+
22
+ parseLambda' = (do
23
+ atom <- parseAtom
24
+ spaces
25
+ atoms <- parseLambda'
26
+ return $ atom: atoms) <|> (ok >> return [] )
27
+
28
+ parseAtom = parseAbs <|> parseBraces <|> parseName
29
+
30
+ parseAbs = do
31
+ char ' \\ '
32
+ spaces
33
+ name <- parseVarName
34
+ spaces
35
+ char ' .'
36
+ spaces
37
+ expr <- parseLambda
38
+ return $ Lam name expr
39
+
40
+ parseBraces = do
41
+ char ' ('
42
+ spaces
43
+ expr <- parseLambda
44
+ spaces
45
+ char ' )'
46
+ return expr
47
+
48
+ parseName = do
49
+ name <- parseVarName
50
+ return $ Var name
51
+
52
+ parseVarName = do
53
+ c <- letter
54
+ cs <- many (letter <|> digit)
55
+ return $ c: cs
56
+
57
+ letter = oneOf $ [' a' .. ' z' ] ++ [' A' .. ' Z' ]
58
+ digit = oneOf [' 0' .. ' 9' ]
59
+ space = oneOf [' ' , ' \n ' , ' \r ' ]
60
+ spaces = many space
61
+ spaces1 = many1 space
62
+
63
+ --------------------------------------------------------------------------------
64
+ -- Заметье, что грамматика лямбда-выражений леворекурсивна.
65
+ -- Перед тем как бросаться кодить, сначала уберите леворекурсивность на бумаге,
66
+ -- а потом напишите получившуюся грамматику в EBNF вот сюда:
67
+ --
68
+ -- прямо сюда, да
69
+ -- Lambda = Atom Lambda'
70
+ -- Lambda' = Atom Lambda'
71
+ -- Atom = "\" Var "." Lambda
72
+ -- | "(" Lambda ")"
73
+ -- | Var
74
+ -- Var = letter (letter | digit)*
75
+ --------------------------------------------------------------------------------
76
+
77
+ -- Красиво печатаем терм (можно с лишними скобками, можно без)
78
+ prettyPrint :: Term -> String
79
+ prettyPrint (Var x) = x
80
+ prettyPrint (App f t) = prettyPrint f ++ " " ++ prettyPrint t
81
+ prettyPrint (Lam v t) = " (\\ " ++ v ++ " . " ++ prettyPrint t ++ " )"
82
+
83
+ -- Собственно сам REPL. Первый аргумент — максимальное число итераций при
84
+ -- попытке нормализации стратегией из второго аргумента.
85
+ replLoop :: Integer -> (Integer -> Term -> Term ) -> IO ()
86
+ replLoop patience strategy = do
87
+ putStr " > "
88
+ line <- getLine
89
+ case runParser parseLambda line of
90
+ Left _ -> putStrLn " Parse error"
91
+ Right (_, term) -> catch (
92
+ let newterm = eval term
93
+ in newterm `seq` putStrLn $ prettyPrint newterm) (
94
+ (\ (e :: SomeException ) -> (print e)))
95
+ replLoop patience strategy
96
+ where eval term = strategy patience term
97
+
98
+ -- Диалог с (replLoop 100 no) должен выглядеть так:
99
+ -- > \x . (\y . y) x x
100
+ -- \x . x x
0 commit comments