diff options
Diffstat (limited to 'lambda-calcul/haskell/src/Minilang')
| -rw-r--r-- | lambda-calcul/haskell/src/Minilang/IO.hs | 28 | ||||
| -rw-r--r-- | lambda-calcul/haskell/src/Minilang/Lambda/DeBruijn.hs | 43 | ||||
| -rw-r--r-- | lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs | 29 | ||||
| -rw-r--r-- | lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs | 14 |
4 files changed, 61 insertions, 53 deletions
diff --git a/lambda-calcul/haskell/src/Minilang/IO.hs b/lambda-calcul/haskell/src/Minilang/IO.hs index a045647..b2b3dcc 100644 --- a/lambda-calcul/haskell/src/Minilang/IO.hs +++ b/lambda-calcul/haskell/src/Minilang/IO.hs @@ -7,8 +7,8 @@ import Data.Text.Encoding encodeUtf8, ) import Data.Text.Encoding.Error (lenientDecode) -import Minilang.Lambda.DeBruijn (eval, toDeBruijn) -import Minilang.Lambda.Parser (desugar, parse, pretty) +import Minilang.Lambda.DeBruijn (eval, fromDeBruijn, toDeBruijn) +import Minilang.Lambda.Parser (desugar, parse, pretty, resugar) import System.IO (Handle) -- | Read a "program" from @hin@ handle, evaluate it and dump the result @@ -17,11 +17,19 @@ runEval :: Handle -> Handle -> IO () runEval hin hout = do programText <- decodeUtf8With lenientDecode <$> BS.hGetContents hin let parsed = parse programText - case parsed of - Left err -> print err - Right ast -> do - putStrLn $ Text.unpack $ "Evaluating " <> pretty ast - let termy = desugar ast - putStrLn $ "Desugared to " <> show termy - let term = toDeBruijn termy - print $ eval term + let result = + case parsed of + Left err -> Text.pack $ show err + Right ast -> + let evaluate = + pretty + . resugar + . fromDeBruijn + . eval + . toDeBruijn + . desugar + in evaluate ast + + BS.hPut + hout + (encodeUtf8 result) diff --git a/lambda-calcul/haskell/src/Minilang/Lambda/DeBruijn.hs b/lambda-calcul/haskell/src/Minilang/Lambda/DeBruijn.hs index 6b5b7a2..290839e 100644 --- a/lambda-calcul/haskell/src/Minilang/Lambda/DeBruijn.hs +++ b/lambda-calcul/haskell/src/Minilang/Lambda/DeBruijn.hs @@ -1,42 +1,57 @@ +{-# LANGUAGE LambdaCase #-} module Minilang.Lambda.DeBruijn where import Data.List (elemIndex) -import Data.Text (Text) +import Data.Text (Text, unpack, pack) import Minilang.Lambda.Eval (Term) import qualified Minilang.Lambda.Eval as Eval -data DeBruijn +data DeBruijn ann = FV Text - | Var Int - | Lam DeBruijn - | App DeBruijn DeBruijn + | Var ann Int + | Lam ann (DeBruijn ann) + | App (DeBruijn ann) (DeBruijn ann) deriving (Show, Read, Eq) +fromDeBruijn :: DeBruijn Text -> Term +fromDeBruijn = \case + FV x -> Eval.Var x + Var s _ -> Eval.Var s + Lam s body -> Eval.Lam s (fromDeBruijn body) + App f a -> Eval.App (fromDeBruijn f) (fromDeBruijn a) + -- Convert a term with named variables to De Bruijn indices -toDeBruijn :: Term -> DeBruijn +toDeBruijn :: Term -> DeBruijn Text toDeBruijn term = go term [] where go (Eval.Var x) env = case elemIndex x env of - Just idx -> Var idx + Just idx -> Var x idx Nothing -> FV x go (Eval.Lam x body) env = - Lam (go body (x : env)) + Lam x (go body (x : env)) go (Eval.App f a) env = App (go f env) (go a env) -eval :: DeBruijn -> DeBruijn +eval :: DeBruijn ann -> DeBruijn ann eval (App f a) = case eval f of - Lam body -> eval (substitute 0 a body) + Lam _ body -> eval (substitute 0 a body) f' -> App f' a eval term = term -substitute :: Int -> DeBruijn -> DeBruijn -> DeBruijn +substitute :: Int -> DeBruijn ann -> DeBruijn ann -> DeBruijn ann substitute n arg term = case term of FV x -> FV x - Var x + Var t x | x == n -> arg - | otherwise -> Var x - Lam body -> Lam (substitute (n + 1) arg body) + | otherwise -> Var t x + Lam x body -> Lam x (substitute (n + 1) arg body) App f a -> App (substitute n arg f) (substitute n arg a) + +pretty :: DeBruijn Text -> Text +pretty = \case + FV x -> x + Var s _ -> s + Lam s body -> "(lam (" <> s <> ") " <> pretty body <> ")" + App f a -> "(" <> pretty f <> " " <> pretty a <> ")" diff --git a/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs b/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs index 35f9460..cbbdc51 100644 --- a/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs +++ b/lambda-calcul/haskell/src/Minilang/Lambda/Eval.hs @@ -42,32 +42,3 @@ evalNeed (App f a) env = in case evalNeed f env of Abs x body env' -> evalNeed body ((x, a') : env') f' -> Ap f' a' - -x = - App - ( App - ( App - ( App - ( App - ( App - ( App - ( App - ( App - (Lam "False" (Lam "True" (Lam "If" (Lam "Zero" (Lam "Succ" (Lam "One" (Lam "Two" (Lam "Three" (Lam "IsZero" (App (Var "IsZero") (Var "Two"))))))))))) - (Lam "f" (Lam "t" (Var "f"))) - ) - (Lam "f" (Lam "t" (Var "t"))) - ) - (Lam "b" (Lam "x" (Lam "y" (App (App (Var "b") (Var "x")) (Var "y"))))) - ) - (Lam "z" (Lam "s" (Var "z"))) - ) - (Lam "n" (Lam "z" (Lam "s" (App (Var "s") (Var "n"))))) - ) - (App (Var "Succ") (Var "Zero")) - ) - (App (Var "Succ") (Var "One")) - ) - (App (Var "Succ") (Var "Two")) - ) - (Lam "n" (App (App (Var "n") (Var "True")) (Lam "m" (Var "False")))) diff --git a/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs b/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs index e52c981..fd02ebe 100644 --- a/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs +++ b/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs @@ -37,6 +37,20 @@ desugar = \case (Eval.App (desugar x) (desugar y)) rest +resugar :: Term -> AST +resugar = \case + Eval.Var s -> Sym s + Eval.Lam x body -> case resugar body of + Abs vars ast -> Abs (x : vars) ast + other -> Abs [x] other + Eval.App l r -> case resugar l of + App f a rest -> App f a (rest ++ [r']) + where + r' = resugar r + other -> App other r' [] + where + r' = resugar r + pretty :: AST -> Text pretty = \case Sym symb -> symb |
