Skip to content

Commit 419ab88

Browse files
committed
REPL completed
1 parent a05c436 commit 419ab88

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

UnTyLambda/REPL.hs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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

Comments
 (0)