packages feed

lambda-calculator 2.0.0 → 3.0.0

raw patch · 55 files changed

+2254/−1564 lines, 55 filesdep +bytestringdep +mtldep +prettyprinterdep −Shellacdep −Shellac-readlinedep ~basedep ~optparse-applicativePVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring, mtl, prettyprinter, repline, rio, text

Dependencies removed: Shellac, Shellac-readline

Dependency ranges changed: base, optparse-applicative

API changes (from Hackage documentation)

- Language.Lambda: Abs :: name -> (LambdaExpr name) -> LambdaExpr name
- Language.Lambda: App :: (LambdaExpr name) -> (LambdaExpr name) -> LambdaExpr name
- Language.Lambda: Var :: name -> LambdaExpr name
- Language.Lambda: class PrettyPrint a
- Language.Lambda: data LambdaExpr name
- Language.Lambda: data ParseError :: *
- Language.Lambda: evalExpr :: Eq n => [n] -> LambdaExpr n -> LambdaExpr n
- Language.Lambda: evalString :: String -> Either ParseError (LambdaExpr String)
- Language.Lambda: parseExpr :: String -> Either ParseError (LambdaExpr String)
- Language.Lambda: prettyPrint :: PrettyPrint a => a -> String
- Language.Lambda: uniques :: [String]
- Language.Lambda.Eval: alphaConvert :: Eq n => [n] -> [n] -> LambdaExpr n -> LambdaExpr n
- Language.Lambda.Eval: betaReduce :: Eq n => [n] -> LambdaExpr n -> LambdaExpr n -> LambdaExpr n
- Language.Lambda.Eval: etaConvert :: Eq n => LambdaExpr n -> LambdaExpr n
- Language.Lambda.Eval: evalExpr :: Eq n => [n] -> LambdaExpr n -> LambdaExpr n
- Language.Lambda.Eval: freeVarsOf :: Eq n => LambdaExpr n -> [n]
- Language.Lambda.Eval: sub :: Eq n => n -> LambdaExpr n -> LambdaExpr n -> LambdaExpr n
- Language.Lambda.Expression: Abs :: name -> (LambdaExpr name) -> LambdaExpr name
- Language.Lambda.Expression: App :: (LambdaExpr name) -> (LambdaExpr name) -> LambdaExpr name
- Language.Lambda.Expression: Var :: name -> LambdaExpr name
- Language.Lambda.Expression: data LambdaExpr name
- Language.Lambda.Expression: instance GHC.Classes.Eq name => GHC.Classes.Eq (Language.Lambda.Expression.LambdaExpr name)
- Language.Lambda.Expression: instance GHC.Show.Show name => GHC.Show.Show (Language.Lambda.Expression.LambdaExpr name)
- Language.Lambda.Expression: instance Language.Lambda.Util.PrettyPrint.PrettyPrint a => Language.Lambda.Util.PrettyPrint.PrettyPrint (Language.Lambda.Expression.LambdaExpr a)
- Language.Lambda.Expression: pprAbs :: PrettyPrint n => PDoc String -> n -> LambdaExpr n -> PDoc String
- Language.Lambda.Expression: pprApp :: PrettyPrint n => PDoc String -> LambdaExpr n -> LambdaExpr n -> PDoc String
- Language.Lambda.Expression: pprExpr :: PrettyPrint n => PDoc String -> LambdaExpr n -> PDoc String
- Language.Lambda.Expression: uncurry :: n -> LambdaExpr n -> ([n], LambdaExpr n)
- Language.Lambda.Parser: parseExpr :: String -> Either ParseError (LambdaExpr String)
- Language.Lambda.Util.PrettyPrint: PDoc :: [s] -> PDoc s
- Language.Lambda.Util.PrettyPrint: add :: s -> PDoc s -> PDoc s
- Language.Lambda.Util.PrettyPrint: addSpace :: PDoc String -> PDoc String
- Language.Lambda.Util.PrettyPrint: append :: [s] -> PDoc s -> PDoc s
- Language.Lambda.Util.PrettyPrint: between :: PDoc s -> s -> s -> PDoc s -> PDoc s
- Language.Lambda.Util.PrettyPrint: betweenParens :: PDoc String -> PDoc String -> PDoc String
- Language.Lambda.Util.PrettyPrint: class PrettyPrint a
- Language.Lambda.Util.PrettyPrint: empty :: PDoc s
- Language.Lambda.Util.PrettyPrint: instance GHC.Base.Functor Language.Lambda.Util.PrettyPrint.PDoc
- Language.Lambda.Util.PrettyPrint: instance GHC.Base.Monoid (Language.Lambda.Util.PrettyPrint.PDoc s)
- Language.Lambda.Util.PrettyPrint: instance GHC.Classes.Eq s => GHC.Classes.Eq (Language.Lambda.Util.PrettyPrint.PDoc s)
- Language.Lambda.Util.PrettyPrint: instance GHC.Show.Show s => GHC.Show.Show (Language.Lambda.Util.PrettyPrint.PDoc s)
- Language.Lambda.Util.PrettyPrint: instance Language.Lambda.Util.PrettyPrint.PrettyPrint GHC.Base.String
- Language.Lambda.Util.PrettyPrint: instance Language.Lambda.Util.PrettyPrint.PrettyPrint s => Language.Lambda.Util.PrettyPrint.PrettyPrint (Language.Lambda.Util.PrettyPrint.PDoc s)
- Language.Lambda.Util.PrettyPrint: intercalate :: [[s]] -> [s] -> PDoc [s] -> PDoc [s]
- Language.Lambda.Util.PrettyPrint: lambda :: Char
- Language.Lambda.Util.PrettyPrint: newtype PDoc s
- Language.Lambda.Util.PrettyPrint: prettyPrint :: PrettyPrint a => a -> String
- Language.Lambda.Util.PrettyPrint: space :: Char
- Language.Lambda.Util.PrettyPrint: upperLambda :: Char
- Language.SystemF: Abs :: name -> (Ty ty) -> (SystemFExpr name ty) -> SystemFExpr name ty
- Language.SystemF: App :: (SystemFExpr name ty) -> (SystemFExpr name ty) -> SystemFExpr name ty
- Language.SystemF: TyAbs :: ty -> (SystemFExpr name ty) -> SystemFExpr name ty
- Language.SystemF: TyApp :: (SystemFExpr name ty) -> (Ty ty) -> SystemFExpr name ty
- Language.SystemF: Var :: name -> SystemFExpr name ty
- Language.SystemF: class PrettyPrint a
- Language.SystemF: data SystemFExpr name ty
- Language.SystemF: evalString :: String -> Either ParseError (SystemFExpr String String)
- Language.SystemF: parseExpr :: String -> Either ParseError (SystemFExpr String String)
- Language.SystemF: prettyPrint :: PrettyPrint a => a -> String
- Language.SystemF.Expression: Abs :: name -> (Ty ty) -> (SystemFExpr name ty) -> SystemFExpr name ty
- Language.SystemF.Expression: App :: (SystemFExpr name ty) -> (SystemFExpr name ty) -> SystemFExpr name ty
- Language.SystemF.Expression: TyAbs :: ty -> (SystemFExpr name ty) -> SystemFExpr name ty
- Language.SystemF.Expression: TyApp :: (SystemFExpr name ty) -> (Ty ty) -> SystemFExpr name ty
- Language.SystemF.Expression: TyArrow :: (Ty name) -> (Ty name) -> Ty name
- Language.SystemF.Expression: TyForAll :: name -> (Ty name) -> Ty name
- Language.SystemF.Expression: TyVar :: name -> Ty name
- Language.SystemF.Expression: Var :: name -> SystemFExpr name ty
- Language.SystemF.Expression: data SystemFExpr name ty
- Language.SystemF.Expression: data Ty name
- Language.SystemF.Expression: instance (GHC.Classes.Eq ty, GHC.Classes.Eq name) => GHC.Classes.Eq (Language.SystemF.Expression.SystemFExpr name ty)
- Language.SystemF.Expression: instance (GHC.Show.Show ty, GHC.Show.Show name) => GHC.Show.Show (Language.SystemF.Expression.SystemFExpr name ty)
- Language.SystemF.Expression: instance (Language.Lambda.Util.PrettyPrint.PrettyPrint n, Language.Lambda.Util.PrettyPrint.PrettyPrint t) => Language.Lambda.Util.PrettyPrint.PrettyPrint (Language.SystemF.Expression.SystemFExpr n t)
- Language.SystemF.Expression: instance GHC.Classes.Eq name => GHC.Classes.Eq (Language.SystemF.Expression.Ty name)
- Language.SystemF.Expression: instance GHC.Show.Show name => GHC.Show.Show (Language.SystemF.Expression.Ty name)
- Language.SystemF.Expression: instance Language.Lambda.Util.PrettyPrint.PrettyPrint n => Language.Lambda.Util.PrettyPrint.PrettyPrint (Language.SystemF.Expression.Ty n)
- Language.SystemF.Expression: pprAbs :: (PrettyPrint n, PrettyPrint t) => PDoc String -> n -> Ty t -> SystemFExpr n t -> PDoc String
- Language.SystemF.Expression: pprApp :: (PrettyPrint n, PrettyPrint t) => PDoc String -> SystemFExpr n t -> SystemFExpr n t -> PDoc String
- Language.SystemF.Expression: pprExpr :: (PrettyPrint n, PrettyPrint t) => PDoc String -> SystemFExpr n t -> PDoc String
- Language.SystemF.Expression: pprTAbs :: (PrettyPrint n, PrettyPrint t) => PDoc String -> t -> SystemFExpr n t -> PDoc String
- Language.SystemF.Expression: pprTApp :: (PrettyPrint n, PrettyPrint t) => PDoc String -> SystemFExpr n t -> Ty t -> PDoc String
- Language.SystemF.Expression: pprTy :: PrettyPrint n => PDoc String -> Bool -> Ty n -> PDoc String
- Language.SystemF.Expression: pprTyArrow :: PrettyPrint n => PDoc String -> Bool -> Ty n -> Ty n -> PDoc String
- Language.SystemF.Expression: pprTyArrow' :: Bool -> PDoc String -> PDoc String -> PDoc String
- Language.SystemF.Expression: pprTyForAll :: PrettyPrint n => PDoc String -> n -> Ty n -> PDoc String
- Language.SystemF.Expression: prettyPrint' :: PrettyPrint n => SystemFExpr n n -> String
- Language.SystemF.Expression: uncurryAbs :: n -> Ty t -> SystemFExpr n t -> ([(n, Ty t)], SystemFExpr n t)
- Language.SystemF.Expression: uncurryTAbs :: t -> SystemFExpr n t -> ([t], SystemFExpr n t)
- Language.SystemF.Parser: parseExpr :: String -> Either ParseError (SystemFExpr String String)
- Language.SystemF.Parser: parseType :: String -> Either ParseError (Ty String)
- Language.SystemF.TypeCheck: sub :: Eq n => n -> Ty n -> SystemFExpr n n -> SystemFExpr n n
- Language.SystemF.TypeCheck: subTy :: Eq n => n -> Ty n -> Ty n -> Ty n
- Language.SystemF.TypeCheck: tcAbs :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n -> Context n (Ty n) -> n -> Ty n -> SystemFExpr n n -> Either String (Ty n)
- Language.SystemF.TypeCheck: tcApp :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n -> Context n (Ty n) -> SystemFExpr n n -> SystemFExpr n n -> Either String (Ty n)
- Language.SystemF.TypeCheck: tcTyAbs :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n -> Context n (Ty n) -> n -> SystemFExpr n n -> Either String (Ty n)
- Language.SystemF.TypeCheck: tcTyApp :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n -> Context n (Ty n) -> SystemFExpr n n -> Ty n -> Either String (Ty n)
- Language.SystemF.TypeCheck: tcVar :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n -> Context n (Ty n) -> n -> Either String (Ty n)
- Language.SystemF.TypeCheck: tyMismatchMsg :: (PrettyPrint t, PrettyPrint t') => t -> t' -> String
- Language.SystemF.TypeCheck: type Context n t = Map n t
- Language.SystemF.TypeCheck: type UniqueSupply n = [n]
- Language.SystemF.TypeCheck: typecheck :: (Ord n, Eq n, PrettyPrint n) => UniqueSupply n -> Context n (Ty n) -> SystemFExpr n n -> Either String (Ty n)
- Language.SystemF.TypeCheck: unique :: UniqueSupply t -> Either String t
+ Language.Lambda.Shared.Errors: ImpossibleError :: LambdaException
+ Language.Lambda.Shared.Errors: InvalidLet :: Text -> LambdaException
+ Language.Lambda.Shared.Errors: ParseError :: Text -> LambdaException
+ Language.Lambda.Shared.Errors: TyMismatchError :: Text -> LambdaException
+ Language.Lambda.Shared.Errors: data LambdaException
+ Language.Lambda.Shared.Errors: instance GHC.Classes.Eq Language.Lambda.Shared.Errors.LambdaException
+ Language.Lambda.Shared.Errors: instance GHC.Exception.Type.Exception Language.Lambda.Shared.Errors.LambdaException
+ Language.Lambda.Shared.Errors: instance GHC.Show.Show Language.Lambda.Shared.Errors.LambdaException
+ Language.Lambda.Shared.Errors: instance RIO.Prelude.Display.Display Language.Lambda.Shared.Errors.LambdaException
+ Language.Lambda.Shared.Errors: isImpossibleError :: LambdaException -> Bool
+ Language.Lambda.Shared.Errors: isLambdaException :: LambdaException -> Bool
+ Language.Lambda.Shared.Errors: isLetError :: LambdaException -> Bool
+ Language.Lambda.Shared.Errors: isParseError :: LambdaException -> Bool
+ Language.Lambda.Shared.UniqueSupply: defaultUniques :: [Text]
+ Language.Lambda.SystemF: evalText :: Text -> Typecheck Text (SystemFExpr Text Text)
+ Language.Lambda.SystemF: type Globals = Map String (SystemFExpr String String)
+ Language.Lambda.SystemF.Expression: Abs :: name -> Ty ty -> SystemFExpr name ty -> SystemFExpr name ty
+ Language.Lambda.SystemF.Expression: App :: SystemFExpr name ty -> SystemFExpr name ty -> SystemFExpr name ty
+ Language.Lambda.SystemF.Expression: TyAbs :: ty -> SystemFExpr name ty -> SystemFExpr name ty
+ Language.Lambda.SystemF.Expression: TyApp :: SystemFExpr name ty -> Ty ty -> SystemFExpr name ty
+ Language.Lambda.SystemF.Expression: TyArrow :: Ty name -> Ty name -> Ty name
+ Language.Lambda.SystemF.Expression: TyForAll :: name -> Ty name -> Ty name
+ Language.Lambda.SystemF.Expression: TyVar :: name -> Ty name
+ Language.Lambda.SystemF.Expression: Var :: name -> SystemFExpr name ty
+ Language.Lambda.SystemF.Expression: data SystemFExpr name ty
+ Language.Lambda.SystemF.Expression: data Ty name
+ Language.Lambda.SystemF.Expression: instance (GHC.Classes.Eq name, GHC.Classes.Eq ty) => GHC.Classes.Eq (Language.Lambda.SystemF.Expression.SystemFExpr name ty)
+ Language.Lambda.SystemF.Expression: instance (GHC.Show.Show name, GHC.Show.Show ty) => GHC.Show.Show (Language.Lambda.SystemF.Expression.SystemFExpr name ty)
+ Language.Lambda.SystemF.Expression: instance (Prettyprinter.Internal.Pretty name, Prettyprinter.Internal.Pretty ty) => Prettyprinter.Internal.Pretty (Language.Lambda.SystemF.Expression.SystemFExpr name ty)
+ Language.Lambda.SystemF.Expression: instance GHC.Classes.Eq name => GHC.Classes.Eq (Language.Lambda.SystemF.Expression.Ty name)
+ Language.Lambda.SystemF.Expression: instance GHC.Show.Show name => GHC.Show.Show (Language.Lambda.SystemF.Expression.Ty name)
+ Language.Lambda.SystemF.Expression: instance Prettyprinter.Internal.Pretty name => Prettyprinter.Internal.Pretty (Language.Lambda.SystemF.Expression.Ty name)
+ Language.Lambda.SystemF.Expression: prettyPrint :: Pretty pretty => pretty -> Text
+ Language.Lambda.SystemF.Expression: upperLambda :: Char
+ Language.Lambda.SystemF.Parser: parseExpr :: Text -> Either ParseError (SystemFExpr Text Text)
+ Language.Lambda.SystemF.Parser: parseType :: Text -> Either ParseError (Ty Text)
+ Language.Lambda.SystemF.State: TypecheckState :: Context name -> [name] -> TypecheckState name
+ Language.Lambda.SystemF.State: [tsContext] :: TypecheckState name -> Context name
+ Language.Lambda.SystemF.State: [tsUniques] :: TypecheckState name -> [name]
+ Language.Lambda.SystemF.State: context :: Lens' (TypecheckState name) (Context name)
+ Language.Lambda.SystemF.State: data TypecheckState name
+ Language.Lambda.SystemF.State: execTypecheck :: Typecheck name result -> TypecheckState name -> Either LambdaException result
+ Language.Lambda.SystemF.State: getContext :: Typecheck name (Context name)
+ Language.Lambda.SystemF.State: getUniques :: Typecheck name [name]
+ Language.Lambda.SystemF.State: mkTypecheckState :: [name] -> TypecheckState name
+ Language.Lambda.SystemF.State: modifyContext :: (Context name -> Context name) -> Typecheck name ()
+ Language.Lambda.SystemF.State: modifyUniques :: ([name] -> [name]) -> Typecheck name ()
+ Language.Lambda.SystemF.State: runTypecheck :: Typecheck name result -> TypecheckState name -> Either LambdaException (result, TypecheckState name)
+ Language.Lambda.SystemF.State: setContext :: Context name -> Typecheck name ()
+ Language.Lambda.SystemF.State: setUniques :: [name] -> Typecheck name ()
+ Language.Lambda.SystemF.State: type Context name = Map name (Ty name)
+ Language.Lambda.SystemF.State: type Typecheck name = StateT (TypecheckState name) (Except LambdaException)
+ Language.Lambda.SystemF.State: uniques :: Lens' (TypecheckState name) [name]
+ Language.Lambda.SystemF.State: unsafeExecTypecheck :: Typecheck name result -> TypecheckState name -> result
+ Language.Lambda.SystemF.State: unsafeRunTypecheck :: Typecheck name result -> TypecheckState name -> (result, TypecheckState name)
+ Language.Lambda.SystemF.TypeCheck: substitute :: Eq n => Ty n -> n -> SystemFExpr n n -> SystemFExpr n n
+ Language.Lambda.SystemF.TypeCheck: substituteTy :: Eq name => Ty name -> name -> Ty name -> Ty name
+ Language.Lambda.SystemF.TypeCheck: tyMismatchError :: (Pretty t1, Pretty t2) => t1 -> t2 -> LambdaException
+ Language.Lambda.SystemF.TypeCheck: type Context' n t = Map n t
+ Language.Lambda.SystemF.TypeCheck: type UniqueSupply n = [n]
+ Language.Lambda.SystemF.TypeCheck: typecheck :: (Ord name, Pretty name) => SystemFExpr name name -> Typecheck name (Ty name)
+ Language.Lambda.SystemF.TypeCheck: typecheckAbs :: (Ord name, Pretty name) => name -> Ty name -> SystemFExpr name name -> Typecheck name (Ty name)
+ Language.Lambda.SystemF.TypeCheck: typecheckApp :: (Ord name, Pretty name) => SystemFExpr name name -> SystemFExpr name name -> Typecheck name (Ty name)
+ Language.Lambda.SystemF.TypeCheck: typecheckTyAbs :: (Ord name, Pretty name) => name -> SystemFExpr name name -> Typecheck name (Ty name)
+ Language.Lambda.SystemF.TypeCheck: typecheckTyApp :: (Ord name, Pretty name) => SystemFExpr name name -> Ty name -> Typecheck name (Ty name)
+ Language.Lambda.SystemF.TypeCheck: typecheckVar :: Ord name => name -> Typecheck name (Ty name)
+ Language.Lambda.SystemF.TypeCheck: unique :: Typecheck name name
+ Language.Lambda.Untyped: defaultUniques :: [Text]
+ Language.Lambda.Untyped: evalText :: Text -> Eval Text (LambdaExpr Text)
+ Language.Lambda.Untyped: execEvalText :: Text -> Globals Text -> Either LambdaException (LambdaExpr Text)
+ Language.Lambda.Untyped: runEvalText :: Text -> Globals Text -> Either LambdaException (LambdaExpr Text, EvalState Text)
+ Language.Lambda.Untyped: unsafeExecEvalText :: Text -> Globals Text -> LambdaExpr Text
+ Language.Lambda.Untyped.Eval: EvalState :: Globals name -> [name] -> EvalState name
+ Language.Lambda.Untyped.Eval: [esGlobals] :: EvalState name -> Globals name
+ Language.Lambda.Untyped.Eval: [esUniques] :: EvalState name -> [name]
+ Language.Lambda.Untyped.Eval: alphaConvert :: Eq name => [name] -> LambdaExpr name -> Eval name (LambdaExpr name)
+ Language.Lambda.Untyped.Eval: betaReduce :: (Eq name, Pretty name) => LambdaExpr name -> LambdaExpr name -> Eval name (LambdaExpr name)
+ Language.Lambda.Untyped.Eval: data EvalState name
+ Language.Lambda.Untyped.Eval: etaConvert :: Eq n => LambdaExpr n -> LambdaExpr n
+ Language.Lambda.Untyped.Eval: evalExpr :: (Pretty name, Ord name) => LambdaExpr name -> Eval name (LambdaExpr name)
+ Language.Lambda.Untyped.Eval: freeVarsOf :: Eq n => LambdaExpr n -> [n]
+ Language.Lambda.Untyped.Eval: subGlobals :: Ord name => Map name (LambdaExpr name) -> LambdaExpr name -> LambdaExpr name
+ Language.Lambda.Untyped.Expression: Abs :: name -> LambdaExpr name -> LambdaExpr name
+ Language.Lambda.Untyped.Expression: App :: LambdaExpr name -> LambdaExpr name -> LambdaExpr name
+ Language.Lambda.Untyped.Expression: Let :: name -> LambdaExpr name -> LambdaExpr name
+ Language.Lambda.Untyped.Expression: Var :: name -> LambdaExpr name
+ Language.Lambda.Untyped.Expression: data LambdaExpr name
+ Language.Lambda.Untyped.Expression: instance GHC.Classes.Eq name => GHC.Classes.Eq (Language.Lambda.Untyped.Expression.LambdaExpr name)
+ Language.Lambda.Untyped.Expression: instance GHC.Show.Show name => GHC.Show.Show (Language.Lambda.Untyped.Expression.LambdaExpr name)
+ Language.Lambda.Untyped.Expression: instance Prettyprinter.Internal.Pretty name => Prettyprinter.Internal.Pretty (Language.Lambda.Untyped.Expression.LambdaExpr name)
+ Language.Lambda.Untyped.Expression: lambda :: Char
+ Language.Lambda.Untyped.Expression: prettyPrint :: Pretty name => LambdaExpr name -> Text
+ Language.Lambda.Untyped.Parser: parseExpr :: Text -> Either ParseError (LambdaExpr Text)
+ Language.Lambda.Untyped.State: EvalState :: Globals name -> [name] -> EvalState name
+ Language.Lambda.Untyped.State: [esGlobals] :: EvalState name -> Globals name
+ Language.Lambda.Untyped.State: [esUniques] :: EvalState name -> [name]
+ Language.Lambda.Untyped.State: data EvalState name
+ Language.Lambda.Untyped.State: execEval :: Eval name result -> EvalState name -> Either LambdaException result
+ Language.Lambda.Untyped.State: getGlobals :: Eval name (Globals name)
+ Language.Lambda.Untyped.State: getUniques :: Eval name [name]
+ Language.Lambda.Untyped.State: globals :: Lens' (EvalState name) (Globals name)
+ Language.Lambda.Untyped.State: mkEvalState :: [name] -> EvalState name
+ Language.Lambda.Untyped.State: runEval :: Eval name result -> EvalState name -> Either LambdaException (result, EvalState name)
+ Language.Lambda.Untyped.State: setGlobals :: Globals name -> Eval name ()
+ Language.Lambda.Untyped.State: setUniques :: [name] -> Eval name ()
+ Language.Lambda.Untyped.State: type Eval name = StateT (EvalState name) (Except LambdaException)
+ Language.Lambda.Untyped.State: type Globals name = Map name (LambdaExpr name)
+ Language.Lambda.Untyped.State: uniques :: Lens' (EvalState name) [name]
+ Language.Lambda.Untyped.State: unsafeExecEval :: Eval name result -> EvalState name -> result
+ Language.Lambda.Untyped.State: unsafeRunEval :: Eval name result -> EvalState name -> (result, EvalState name)

Files

+ app/CliOptions.hs view
@@ -0,0 +1,41 @@+module CliOptions+  ( CliOptions(..),+    Language(..),+    parseCliOptions+  ) where++import RIO++import Options.Applicative hiding (command, ParseError())++data CliOptions = CliOptions {+  language :: Language,+  version :: Bool+}++-- | Supported Languages:+-- +--    * Untyped Lambda Calculus+--    * System F+data Language +  = Untyped+  | SystemF++parseCliOptions :: IO CliOptions+parseCliOptions = execParser opts+  where opts = info+          (helper <*> cliParser)+          (briefDesc <> progDesc "A Lambda Calculus Interpreter")++cliParser :: Parser CliOptions+cliParser = CliOptions +  <$> flag Untyped SystemF language+  <*> switch version+  where language = long "system-f"+          <> short 'f'+          <> internal -- this is a secret feature+          <> help "Use the System F interpreter"++        version = long "version"+          <> short 'v'+          <> help "Print the version"
app/Main.hs view
@@ -1,107 +1,22 @@ module Main where -import Data.Version--import Data.Semigroup-import Options.Applicative hiding (ParseError)-import System.Console.Shell-import System.Console.Shell.ShellMonad-import System.Console.Shell.Backend.Readline (readlineBackend)-+import CliOptions (CliOptions(..), parseCliOptions)+import Repl (runRepl) import qualified Paths_lambda_calculator as P -import Language.Lambda-import Language.Lambda.Util.PrettyPrint-import Language.SystemF+import Data.Version+import RIO  main :: IO ()-main = execParser opts >>= runShell'-  where opts = info (helper <*> cliParser)-                    (briefDesc <> progDesc "A Lambda Calculus Interpreter")---- Option Parsing-data CliOptions = CliOptions {-  language :: Eval Language,-  version :: Bool-  }---- Supported Languages:--- ---  * Untyped Lambda Calculus---  * System F-data Language -  = Untyped-  | SystemF---- The result of an evaluation-type Result a = Either a -- An error-                       a -- The result---- Represent a language together with its evaluation function-data Eval a = Eval a (String -> Result String)--untyped :: Eval Language-untyped = Eval Untyped eval-  where eval = fromEvalString Language.Lambda.evalString--systemf :: Eval Language-systemf = Eval SystemF eval-  where eval = fromEvalString Language.SystemF.evalString---- Take a typed evaluation function and return a function that returns a result--- --- For example:---   (String -> Either ParseError (LambdaExpr String)) -> (String -> Result String)---   (String -> Either ParseError (SystemFExpr String String)) -> (String -> Result String)-fromEvalString :: (Show s, PrettyPrint p)-               => (String -> Either s p)-               -> (String -> Result String)-fromEvalString f = either (Left . show) (Right . prettyPrint) . f--cliParser :: Parser CliOptions-cliParser = CliOptions -  <$> flag untyped systemf (long "system-f" <> -                            short 'f' <> -                            internal <>    -- this is a secret feature-                            help "Use the System F interpreter")--  <*> switch (long "version" <> -              short 'v' <> -              help "Print the version")---- Interactive Shell-runShell' :: CliOptions -> IO ()-runShell' CliOptions{version=True} = putStrLn version'-runShell' CliOptions{language=Eval lang eval} -  = runShell (mkShellDesc lang eval) readlineBackend ()--mkShellDesc :: Language -            -> (String -> Result String)-            -> ShellDescription ()-mkShellDesc language f = shellDesc' $ mkShellDescription commands (eval f)-  where shellDesc' d = d {-          greetingText = Just shellGreeting,-          prompt = shellPrompt language-          }--shellGreeting :: String-shellGreeting = "Lambda Calculator (" ++ version' ++ ")\nType :h for help\n"-  -shellPrompt :: Language -> s -> IO String-shellPrompt language _ = return $ prefix language : " > "-  where prefix Untyped = lambda-        prefix SystemF = upperLambda--commands :: [ShellCommand s]-commands = [-  exitCommand "q",-  helpCommand "h"-  ]--eval :: (String -> Result String) -> String -> Sh s' ()-eval f = either shellPutErrLn shellPutStrLn . f+main = runSimpleApp $ do+  CliOptions{..} <- liftIO parseCliOptions --- Get the current version-version' :: String-version' = showVersion P.version- +  if version+    then+      logInfo $ "Lambda Calculator (" <> version' <> ")"+    else+      liftIO $ runRepl language+    +-- | Get the current version+version' :: Utf8Builder+version' = fromString $ showVersion P.version
+ app/Repl.hs view
@@ -0,0 +1,11 @@+module Repl (runRepl) where++import CliOptions (Language(..))+import Repl.SystemF (runSystemFRepl)+import Repl.Untyped (runUntypedRepl)++import RIO++runRepl :: Language -> IO ()+runRepl SystemF = runSystemFRepl+runRepl Untyped = runUntypedRepl
+ app/Repl/Shared.hs view
@@ -0,0 +1,59 @@+module Repl.Shared where++import CliOptions (Language(..))+import Paths_lambda_calculator (version)+import Language.Lambda.Shared.Errors (LambdaException())+import Language.Lambda.Shared.UniqueSupply (defaultUniques)+import Language.Lambda.SystemF++import Data.Text (singleton)+import Data.Text.IO (putStrLn)+import Data.Version (showVersion)+import RIO+import RIO.State+import RIO.Text (pack, unpack)+import System.Console.Repline+import Control.Monad.Except+import qualified Data.Map as M++mkReplOpts banner command = ReplOpts+  { banner = banner,+    command = command,+    options = commands,+    prefix = Just ':',+    multilineCommand = Nothing,+    tabComplete = Custom completer,+    initialiser = initializer,+    finaliser = return Exit+  }++prompt :: Applicative ap => Text -> HaskelineT ap Text+prompt prefix = pure $ prefix <> " > "++commands :: (MonadIO m, MonadThrow m) => [(String, String -> HaskelineT m ())]+commands+  = [ ("h", help'),+      ("help", help'),+      ("q", quit'),+      ("quit", quit')+    ]+  where help' = const helpCommand+        quit' = const abort++completer :: Monad m => CompletionFunc m+completer (left, _) = pure (left, []) -- No tab completion++initializer :: MonadIO io => HaskelineT io ()+initializer = liftIO $ putStrLn greeting+  where greeting = "Lambda Calculator ("+          <> version'+          <> ")\nType :h for help\n"++helpCommand :: MonadIO io => HaskelineT io ()+helpCommand = liftIO $ putStrLn banner+  where banner = " Commands available: \n\n"+          <> "    :help, :h\tShow this help\n"+          <> "    :quit, :q\tQuit\n"++version' :: Text+version' = fromString $ showVersion version
+ app/Repl/SystemF.hs view
@@ -0,0 +1,40 @@+module Repl.SystemF (runSystemFRepl) where++import Language.Lambda.Shared.Errors (LambdaException())+import Language.Lambda.Shared.UniqueSupply (defaultUniques)+import Language.Lambda.SystemF+import Repl.Shared++import Data.Text (singleton)+import Data.Text.IO (putStrLn)+import RIO+import RIO.State+import RIO.Text (pack, unpack)+import System.Console.Repline+import Control.Monad.Except (ExceptT(..), runExceptT)++type EvalT name m+  = StateT (TypecheckState name)+      (ExceptT LambdaException m)++type Repl a = HaskelineT (EvalT Text IO) a++runSystemFRepl :: IO ()+runSystemFRepl+  = void . runExceptT . evalStateT (evalReplOpts replOpts) $ initialState+  where replOpts = mkReplOpts banner' $ evalSystemF . pack+        initialState = mkTypecheckState defaultUniques++banner' :: MultiLine -> Repl String+banner' _ = unpack <$> prompt (singleton upperLambda)++evalSystemF :: Text -> Repl ()+evalSystemF input = do+  state' <- get++  let res = runTypecheck (evalText input) state'+  case res of+    Left err -> liftIO . putStrLn . pack . show $ err+    Right (res', newState) -> do+      put newState+      liftIO . putStrLn . prettyPrint $ res'
+ app/Repl/Untyped.hs view
@@ -0,0 +1,50 @@+module Repl.Untyped (runUntypedRepl) where++import Language.Lambda.Shared.Errors (LambdaException())+import Language.Lambda.Shared.UniqueSupply (defaultUniques)+import Language.Lambda.Untyped+import Repl.Shared++import Data.Text (singleton)+import Data.Text.IO (putStrLn)+import RIO+import RIO.State+import RIO.Text (pack, unpack)+import System.Console.Repline+import Control.Monad.Except++type EvalT name m+  = StateT (EvalState name)+      (ExceptT LambdaException m)++type Repl a = HaskelineT (EvalT Text IO) a++runUntypedRepl :: IO ()+runUntypedRepl+  = void . runExceptT . evalStateT (evalReplOpts replOpts) $ initialState+  where replOpts = ReplOpts+          { banner = const $ unpack <$> prompt',+            command = evalLambda . pack,+            options = commands,+            prefix = Just ':',+            multilineCommand = Nothing,+            tabComplete = Custom completer,+            initialiser = initializer,+            finaliser = return Exit+          }++        initialState = mkEvalState defaultUniques++prompt' :: Repl Text+prompt' = prompt $ singleton lambda++evalLambda :: Text -> Repl ()+evalLambda input = do+  state' <- get+  +  let res = runEval (evalText input) state'+  case res of+    Left err -> liftIO . putStrLn . textDisplay $ err+    Right (res', newState) -> do+      put newState+      liftIO . putStrLn . prettyPrint $ res'
lambda-calculator.cabal view
@@ -1,84 +1,269 @@-name:                lambda-calculator-version:             2.0.0-synopsis:            A lambda calculus interpreter-description:         Please see README.md-homepage:            https://github.com/sgillespie/lambda-calculus#readme-license:             MIT-license-file:        LICENSE-author:              Sean D Gillespie-maintainer:          sean@mistersg.net-copyright:           2016 Sean Gillespie-category:            LambdaCalculus,Language,Teaching-build-type:          Simple--- extra-source-files:-cabal-version:       >=1.10--library-  hs-source-dirs:      src-  exposed-modules:     Language.Lambda,-                       Language.Lambda.Expression,-                       Language.Lambda.Eval,-                       Language.Lambda.Parser,--                       Language.Lambda.Util.PrettyPrint,+cabal-version: 1.12 -                       Language.SystemF,-                       Language.SystemF.Expression,-                       Language.SystemF.Parser,-                       Language.SystemF.TypeCheck-  build-depends:       base >= 4.9 && < 5,-                       containers,-                       parsec-  default-language:    Haskell2010+-- This file has been generated from package.yaml by hpack version 0.34.7.+--+-- see: https://github.com/sol/hpack+--+-- hash: 089fe9b55bbab6cbfceb1623b5f1eb4f8c706b39fa51ad2d87957cefea80301c -executable lambda-calculator-  hs-source-dirs:      app-  main-is:             Main.hs-  other-modules:       Paths_lambda_calculator-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N-  build-depends:       base >= 4.9,-                       lambda-calculator,-                       optparse-applicative >= 0.13,-                       Shellac,-                       Shellac-readline-  default-language:    Haskell2010+name:           lambda-calculator+version:        3.0.0+synopsis:       A lambda calculus interpreter+description:    Please see README.md+category:       LambdaCalculus,Language,Teaching+homepage:       https://github.com/sgillespie/lambda-calculus#readme+bug-reports:    https://github.com/sgillespie/lambda-calculus/issues+author:         Sean D Gillespie+maintainer:     sean@mistersg.net+copyright:      2016 Sean Gillespie+license:        MIT+license-file:   LICENSE+build-type:     Simple -test-suite lambda-calculus-test-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             Spec.hs-  other-modules:       Language.LambdaSpec,-                       Language.Lambda.Examples.BoolSpec,-                       Language.Lambda.Examples.NatSpec,-                       Language.Lambda.Examples.PairSpec,-                       Language.Lambda.ExpressionSpec,-                       Language.Lambda.EvalSpec,-                       Language.Lambda.HspecUtils,-                       Language.Lambda.ParserSpec,+source-repository head+  type: git+  location: https://github.com/sgillespie/lambda-calculus -                       Language.Lambda.Util.PrettyPrintSpec,+library+  exposed-modules:+      Language.Lambda.Shared.Errors+      Language.Lambda.Shared.UniqueSupply+      Language.Lambda.Untyped+      Language.Lambda.Untyped.Expression+      Language.Lambda.Untyped.Eval+      Language.Lambda.Untyped.Parser+      Language.Lambda.Untyped.State+      Language.Lambda.SystemF+      Language.Lambda.SystemF.Expression+      Language.Lambda.SystemF.Parser+      Language.Lambda.SystemF.State+      Language.Lambda.SystemF.TypeCheck+  other-modules:+      Language.Lambda+      Paths_lambda_calculator+  hs-source-dirs:+      src+  default-extensions:+      BangPatterns+      ConstraintKinds+      DataKinds+      DefaultSignatures+      DeriveDataTypeable+      DeriveFoldable+      DeriveFunctor+      DeriveGeneric+      DeriveTraversable+      DoAndIfThenElse+      EmptyDataDecls+      ExistentialQuantification+      FlexibleContexts+      FlexibleInstances+      FunctionalDependencies+      GADTs+      GeneralizedNewtypeDeriving+      InstanceSigs+      KindSignatures+      LambdaCase+      MultiParamTypeClasses+      MultiWayIf+      NamedFieldPuns+      PartialTypeSignatures+      PatternGuards+      PolyKinds+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      StandaloneDeriving+      TupleSections+      TypeFamilies+      TypeSynonymInstances+      ViewPatterns+      NoImplicitPrelude+      OverloadedStrings+  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints+  build-depends:+      base >=4.9 && <5+    , containers+    , mtl+    , parsec+    , prettyprinter+    , rio+  default-language: Haskell2010 -                       Language.SystemFSpec,-                       Language.SystemF.ExpressionSpec,-                       Language.SystemF.ParserSpec,-                       Language.SystemF.TypeCheckSpec-  build-depends:       base < 5,-                       lambda-calculator,-                       containers,-                       hspec,-                       HUnit-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N-  default-language:    Haskell2010+executable lambda-calculator+  main-is: Main.hs+  other-modules:+      CliOptions+      Repl+      Repl.Shared+      Repl.SystemF+      Repl.Untyped+      Paths_lambda_calculator+  hs-source-dirs:+      app+  default-extensions:+      BangPatterns+      ConstraintKinds+      DataKinds+      DefaultSignatures+      DeriveDataTypeable+      DeriveFoldable+      DeriveFunctor+      DeriveGeneric+      DeriveTraversable+      DoAndIfThenElse+      EmptyDataDecls+      ExistentialQuantification+      FlexibleContexts+      FlexibleInstances+      FunctionalDependencies+      GADTs+      GeneralizedNewtypeDeriving+      InstanceSigs+      KindSignatures+      LambdaCase+      MultiParamTypeClasses+      MultiWayIf+      NamedFieldPuns+      PartialTypeSignatures+      PatternGuards+      PolyKinds+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      StandaloneDeriving+      TupleSections+      TypeFamilies+      TypeSynonymInstances+      ViewPatterns+      NoImplicitPrelude+      OverloadedStrings+  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.9 && <5+    , bytestring+    , containers+    , lambda-calculator+    , mtl+    , optparse-applicative+    , prettyprinter+    , repline+    , rio+    , text+  default-language: Haskell2010  test-suite lambda-calculus-lint-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             HLint.hs-  build-depends:       base <= 5,-                       hlint-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N-  default-language:    Haskell2010+  type: exitcode-stdio-1.0+  main-is: HLint.hs+  hs-source-dirs:+      scripts+  default-extensions:+      BangPatterns+      ConstraintKinds+      DataKinds+      DefaultSignatures+      DeriveDataTypeable+      DeriveFoldable+      DeriveFunctor+      DeriveGeneric+      DeriveTraversable+      DoAndIfThenElse+      EmptyDataDecls+      ExistentialQuantification+      FlexibleContexts+      FlexibleInstances+      FunctionalDependencies+      GADTs+      GeneralizedNewtypeDeriving+      InstanceSigs+      KindSignatures+      LambdaCase+      MultiParamTypeClasses+      MultiWayIf+      NamedFieldPuns+      PartialTypeSignatures+      PatternGuards+      PolyKinds+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      StandaloneDeriving+      TupleSections+      TypeFamilies+      TypeSynonymInstances+      ViewPatterns+      ImplicitPrelude+  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.9 && <5+    , hlint+    , mtl+    , prettyprinter+    , rio+  default-language: Haskell2010 -source-repository head-  type:     git-  location: https://github.com/sgillespie/lambda-calculus+test-suite lambda-calculus-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Language.Lambda.SystemF.ExpressionSpec+      Language.Lambda.SystemF.ParserSpec+      Language.Lambda.SystemF.TypeCheckSpec+      Language.Lambda.SystemFSpec+      Language.Lambda.Untyped.EvalSpec+      Language.Lambda.Untyped.Examples.BoolSpec+      Language.Lambda.Untyped.Examples.NatSpec+      Language.Lambda.Untyped.Examples.PairSpec+      Language.Lambda.Untyped.ExpressionSpec+      Language.Lambda.Untyped.HspecUtils+      Language.Lambda.Untyped.ParserSpec+      Language.Lambda.UntypedSpec+      Paths_lambda_calculator+  hs-source-dirs:+      test+  default-extensions:+      BangPatterns+      ConstraintKinds+      DataKinds+      DefaultSignatures+      DeriveDataTypeable+      DeriveFoldable+      DeriveFunctor+      DeriveGeneric+      DeriveTraversable+      DoAndIfThenElse+      EmptyDataDecls+      ExistentialQuantification+      FlexibleContexts+      FlexibleInstances+      FunctionalDependencies+      GADTs+      GeneralizedNewtypeDeriving+      InstanceSigs+      KindSignatures+      LambdaCase+      MultiParamTypeClasses+      MultiWayIf+      NamedFieldPuns+      PartialTypeSignatures+      PatternGuards+      PolyKinds+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      StandaloneDeriving+      TupleSections+      TypeFamilies+      TypeSynonymInstances+      ViewPatterns+  ghc-options: -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      HUnit+    , base >=4.9 && <5+    , containers+    , hspec+    , lambda-calculator+    , mtl+    , prettyprinter+    , rio+  default-language: Haskell2010
+ scripts/HLint.hs view
@@ -0,0 +1,16 @@+module Main (main) where++import Language.Haskell.HLint (hlint)+import System.Exit (exitFailure, exitSuccess)++arguments :: [String]+arguments = [ +  "app",+  "src",+  "test"+  ]++main :: IO ()+main = hlint arguments >>= main'+  where main' [] = exitSuccess+        main' _  = exitFailure
src/Language/Lambda.hs view
@@ -1,26 +1,5 @@-{-# LANGUAGE FlexibleInstances #-}-module Language.Lambda (-  LambdaExpr(..),-  ParseError(..),-  PrettyPrint(..),-  evalExpr,-  evalString,-  parseExpr,-  uniques,+module Language.Lambda+  ( module Language.Lambda.Shared.Errors   ) where -import Control.Monad-import Text.Parsec--import Language.Lambda.Eval-import Language.Lambda.Expression-import Language.Lambda.Parser-import Language.Lambda.Util.PrettyPrint--evalString :: String -> Either ParseError (LambdaExpr String)-evalString = fmap (evalExpr uniques) . parseExpr--uniques :: [String]-uniques = concatMap (\p -> map (:p) . reverse $ ['a'..'z']) suffix-  where suffix = "" : map show [(0::Int)..]-+import Language.Lambda.Shared.Errors
− src/Language/Lambda/Eval.hs
@@ -1,56 +0,0 @@-module Language.Lambda.Eval where--import Data.List-import Data.Maybe--import Language.Lambda.Expression--evalExpr :: Eq n => [n] -> LambdaExpr n -> LambdaExpr n-evalExpr uniqs (Abs name expr) = Abs name . evalExpr uniqs $ expr-evalExpr _     expr@(Var _)    = expr-evalExpr uniqs (App e1   e2)   = betaReduce uniqs (evalExpr uniqs e1)-                                                  (evalExpr uniqs e2)--betaReduce :: Eq n => [n] -> LambdaExpr n -> LambdaExpr n -> LambdaExpr n-betaReduce uniqs (App e1 e1') e2 = App (betaReduce uniqs e1 e1') e2-betaReduce _     expr@(Var _) e2 = App expr e2-betaReduce uniqs (Abs n  e1)  e2 = evalExpr uniqs . sub n e1' $ e2-  where fvs = freeVarsOf e2-        e1' = alphaConvert uniqs fvs e1--alphaConvert :: Eq n => [n] -> [n] -> LambdaExpr n -> LambdaExpr n-alphaConvert uniqs freeVars (Abs name body)-  | name `elem` freeVars = Abs uniq . sub name body . Var $ uniq-  | otherwise            = Abs name . alphaConvert uniqs freeVars $ body-  where uniq = fromMaybe name (find (`notElem` freeVars) uniqs)-alphaConvert _ _ e = e--etaConvert :: Eq n => LambdaExpr n -> LambdaExpr n-etaConvert (Abs n (App e1 (Var n')))-  | n == n'   = etaConvert e1-  | otherwise = Abs n (App (etaConvert e1) (Var n'))-etaConvert (Abs n e@(Abs _ _)) -  -- If `etaConvert e == e` then etaConverting it will create an infinite loop-  | e == e'   = Abs n e'-  | otherwise = etaConvert (Abs n e')-  where e' = etaConvert e-etaConvert (Abs n expr) = Abs n (etaConvert expr)-etaConvert (App e1 e2)  = App (etaConvert e1) (etaConvert e2)-etaConvert expr@(Var _) = expr--sub :: Eq n => n -> LambdaExpr n -> LambdaExpr n -> LambdaExpr n-sub name b@(Var name') expr-  | name == name' = expr-  | otherwise     = b--sub name b@(Abs name' expr') expr-  | name == name' = b-  | otherwise     = Abs name' (sub name expr' expr)--sub name (App e1 e2) expr = App (sub name e1 expr)-                                (sub name e2 expr)--freeVarsOf :: Eq n => LambdaExpr n -> [n]-freeVarsOf (Abs n expr) = filter (/=n) . freeVarsOf $ expr-freeVarsOf (App e1 e2)  = freeVarsOf e1 ++ freeVarsOf e2-freeVarsOf (Var n)      = [n]
− src/Language/Lambda/Expression.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-module Language.Lambda.Expression where--import Prelude hiding (abs, uncurry)--import Language.Lambda.Util.PrettyPrint--data LambdaExpr name-  = Var name-  | App (LambdaExpr name) (LambdaExpr name)-  | Abs name (LambdaExpr name)-  deriving (Eq, Show)---- Pretty printing-instance PrettyPrint a => PrettyPrint (LambdaExpr a) where-  prettyPrint = prettyPrint . pprExpr empty---- Pretty print a lambda expression-pprExpr :: PrettyPrint n => PDoc String -> LambdaExpr n -> PDoc String-pprExpr pdoc (Var n)      = prettyPrint n `add` pdoc-pprExpr pdoc (Abs n body) = pprAbs pdoc n body-pprExpr pdoc (App e1 e2)  = pprApp pdoc e1 e2---- Pretty print an abstraction -pprAbs :: PrettyPrint n => PDoc String -> n -> LambdaExpr n -> PDoc String-pprAbs pdoc n body-  = between vars' [lambda] ". " (pprExpr pdoc body')-  where (vars, body') = uncurry n body-        vars' = intercalate (map prettyPrint vars) " " empty---- Pretty print an application-pprApp :: PrettyPrint n-        => PDoc String-        -> LambdaExpr n-        -> LambdaExpr n-        -> PDoc String-pprApp pdoc e1@(Abs _ _) e2@(Abs _ _) = betweenParens (pprExpr pdoc e1) pdoc-  `mappend` addSpace (betweenParens (pprExpr pdoc e2) pdoc)-pprApp pdoc e1 e2@(App _ _) = pprExpr pdoc e1-  `mappend` addSpace (betweenParens (pprExpr pdoc e2) pdoc)-pprApp pdoc e1 e2@(Abs _ _) = pprExpr pdoc e1-  `mappend` addSpace (betweenParens (pprExpr pdoc e2) pdoc)-pprApp pdoc e1@(Abs _ _) e2 = betweenParens (pprExpr pdoc e1) pdoc-  `mappend` addSpace (pprExpr pdoc e2)-pprApp pdoc e1 e2-  = pprExpr pdoc e1 `mappend` addSpace (pprExpr pdoc e2)--uncurry :: n -> LambdaExpr n -> ([n], LambdaExpr n)-uncurry n = uncurry' [n]-  where uncurry' ns (Abs n' body') = uncurry' (n':ns) body'-        uncurry' ns body'          = (reverse ns, body')
− src/Language/Lambda/Parser.hs
@@ -1,46 +0,0 @@-module Language.Lambda.Parser (parseExpr) where--import Control.Monad-import Prelude hiding (abs, curry, id)--import Text.Parsec-import Text.Parsec.String--import Language.Lambda.Expression--parseExpr :: String -> Either ParseError (LambdaExpr String)-parseExpr = parse (whitespace *> expr <* eof) ""--expr :: Parser (LambdaExpr String)-expr = try app <|> term--term :: Parser (LambdaExpr String)-term = abs <|> var <|> parens--var :: Parser (LambdaExpr String)-var = Var <$> identifier--abs :: Parser (LambdaExpr String)-abs = curry <$> idents <*> expr-  where idents = symbol '\\' *> many1 identifier <* symbol '.'-        curry = flip (foldr Abs)--app :: Parser (LambdaExpr String)-app = chainl1 term (return App)--parens :: Parser (LambdaExpr String)-parens = symbol '(' *> expr <* symbol ')'--lexeme :: Parser a -> Parser a-lexeme p =  p <* whitespace--whitespace :: Parser ()-whitespace = void . many . oneOf $ " \t"--identifier :: Parser String-identifier = lexeme ((:) <$> first <*> many rest)-  where first = letter <|> char '_'-        rest  = first <|> digit--symbol :: Char -> Parser ()-symbol = void . lexeme . char
+ src/Language/Lambda/Shared/Errors.hs view
@@ -0,0 +1,61 @@+module Language.Lambda.Shared.Errors+  ( LambdaException(..),+    isLambdaException,+    isLetError,+    isParseError,+    isImpossibleError+  ) where++import RIO++data LambdaException+  -- | An expression that cannot be parsed+  -- Examples:+  --+  --     \x y+  --     = y+  = ParseError Text++  -- | A let binding nested in another expression+  -- Examples:+  --+  --     \x. let y = z+  --     x (let y = z)+  | InvalidLet Text -- ^ A let binding nested in another expression++  -- | The expected type does not match the actual type+  -- Examples:+  --+  --     (\x: X. x) (y:Y)+  | TyMismatchError Text++  -- | A catch-all error that indicates a bug in this project+  | ImpossibleError+  deriving (Eq, Typeable)++instance Exception LambdaException++instance Display LambdaException where+  textDisplay (ParseError txt) = "Parse error " <> txt+  textDisplay (InvalidLet txt) = "Illegal nested let: " <> txt+  textDisplay ImpossibleError = "An impossible error occurred! Please file a bug."++instance Show LambdaException where+  show = show . textDisplay++-- | Returns true if the passed in value is a LamdbaExpression. Can be used, for example,+-- as a `shouldThrow` matcher+isLambdaException :: LambdaException -> Bool+isLambdaException _ = True++isLetError :: LambdaException -> Bool+isLetError (InvalidLet _) = True+isLetError _ = False++isParseError :: LambdaException -> Bool+isParseError (ParseError _) = True+isParseError _ = False++isImpossibleError :: LambdaException -> Bool+isImpossibleError ImpossibleError = True+isImpossibleError _ = False
+ src/Language/Lambda/Shared/UniqueSupply.hs view
@@ -0,0 +1,9 @@+module Language.Lambda.Shared.UniqueSupply where++import RIO+import RIO.Text (pack)++defaultUniques :: [Text]+defaultUniques = map pack strings+  where strings = concatMap (\p -> map (:p) . reverse $ ['a'..'z']) suffix+        suffix = "" : map show [(0::Int)..]
+ src/Language/Lambda/SystemF.hs view
@@ -0,0 +1,26 @@+module Language.Lambda.SystemF (+  Globals(),+  evalText,++  module Language.Lambda.SystemF.Expression,+  module Language.Lambda.SystemF.Parser,+  module Language.Lambda.SystemF.State+  ) where++import Control.Monad.Except+import RIO+import qualified RIO.Text as Text+import qualified Data.Map as Map++import Language.Lambda.Shared.Errors+import Language.Lambda.SystemF.Expression+import Language.Lambda.SystemF.Parser+import Language.Lambda.SystemF.State++type Globals = Map.Map String (SystemFExpr String String)++evalText :: Text -> Typecheck Text (SystemFExpr Text Text)+evalText text = case parseExpr text of+  Left err -> throwError $ ParseError $ Text.pack $ show err+  Right res -> return res+
+ src/Language/Lambda/SystemF/Expression.hs view
@@ -0,0 +1,124 @@+module Language.Lambda.SystemF.Expression+  ( SystemFExpr(..),+    Ty(..),+    prettyPrint,+    upperLambda+  ) where++import Data.Monoid+import Prettyprinter+import Prettyprinter.Render.Text (renderStrict)+import RIO++data SystemFExpr name ty+  -- | Variable: `x`+  = Var name+  -- | Function application: `x y`+  | App (SystemFExpr name ty) (SystemFExpr name ty)+  -- | Lambda abstraction: `\x: X. x`+  | Abs name (Ty ty) (SystemFExpr name ty)+  -- | Type Abstraction: `\X. body`+  | TyAbs ty (SystemFExpr name ty)                  +  -- | Type Application: `x [X]`+  | TyApp (SystemFExpr name ty) (Ty ty)+  deriving (Eq, Show)++data Ty name+  = TyVar name                  -- ^ Type variable (T)+  | TyArrow (Ty name) (Ty name) -- ^ Type arrow    (T -> U)+  | TyForAll name (Ty name)     -- ^ Universal type (forall T. X)+  deriving (Eq, Show)++instance (Pretty name, Pretty ty) => Pretty (SystemFExpr name ty) where+  pretty (Var name) = pretty name+  pretty (App e1 e2) = prettyApp e1 e2+  pretty (Abs name ty body) = prettyAbs name ty body+  pretty (TyAbs ty body) = prettyTyAbs ty body+  pretty (TyApp expr ty) = prettyTyApp expr ty++instance Pretty name => Pretty (Ty name) where+  pretty = prettyTy False++prettyPrint :: Pretty pretty => pretty -> Text+prettyPrint expr = renderStrict docStream+  where docStream = layoutPretty defaultLayoutOptions (pretty expr)++upperLambda :: Char+upperLambda = 'Λ'++prettyApp+  :: (Pretty name, Pretty ty)+  => SystemFExpr name ty+  -> SystemFExpr name ty+  -> Doc a+prettyApp e1@Abs{} e2@Abs{} = parens (pretty e1) <+> parens (pretty e2)+prettyApp e1@Abs{} e2 = parens (pretty e1) <+> pretty e2+prettyApp e1 e2@Abs{} = pretty e1 <+> parens (pretty e2)+prettyApp e1 e2@App{} = pretty e1 <+> parens (pretty e2)+prettyApp e1 e2 = pretty e1 <+> pretty e2++prettyAbs+  :: (Pretty name, Pretty ty)+  => name+  -> Ty ty+  -> SystemFExpr name ty+  -> Doc ann+prettyAbs name ty body+  = lambda+    <+> hsep (map (uncurry prettyArg) names)+    <> dot+    <+> pretty body'+  where (names, body') = uncurryAbs name ty body++prettyTyAbs :: (Pretty name, Pretty ty) => ty -> SystemFExpr name ty -> Doc ann+prettyTyAbs name body = upperLambda' <+> hsep (map pretty names) <> dot+    <+> pretty body'+  where (names, body') = uncurryTyAbs name body+prettyTyApp :: (Pretty name, Pretty ty) => SystemFExpr name ty -> Ty ty -> Doc ann+prettyTyApp expr ty = pretty expr <+> brackets (pretty ty)++prettyTy :: Pretty name => Bool -> Ty name -> Doc ann+prettyTy _ (TyVar name) = pretty name+prettyTy compact (TyArrow t1 t2) = prettyTyArrow compact t1 t2+prettyTy compact (TyForAll name ty) = prettyTyForAll compact name ty++prettyTyArrow :: Pretty name => Bool -> Ty name -> Ty name -> Doc ann+prettyTyArrow compact (TyArrow t1 t2) t3+  = prettyTyArrow' compact compositeTy $ prettyTy compact t3+  where compositeTy = parens $ prettyTyArrow compact t1 t2++prettyTyArrow compact t1 t2+  = prettyTyArrow' compact (prettyTy compact t1) (prettyTy compact t2)++prettyTyForAll :: Pretty name => Bool -> name -> Ty name -> Doc ann+prettyTyForAll compact name ty+  = "forall"+  <+> pretty name <> dot+  <+> prettyTy compact ty++lambda :: Doc ann+lambda = pretty 'λ'++prettyArg :: (Pretty name, Pretty ty) => name -> Ty ty -> Doc ann+prettyArg name (TyArrow t1 t2)+  = pretty name <> colon <> parens (prettyTyArrow True t1 t2)+prettyArg name ty = pretty name <> colon <> pretty ty++upperLambda' :: Doc ann+upperLambda' = pretty upperLambda++prettyTyArrow' :: Bool -> Doc ann -> Doc ann -> Doc ann+prettyTyArrow' compact doc1 doc2 = doc1 `add'` "->" `add'` doc2+  where add'+          | compact = (<>) +          | otherwise = (<+>)++uncurryAbs :: n -> Ty t -> SystemFExpr n t -> ([(n, Ty t)], SystemFExpr n t)+uncurryAbs name ty = uncurry' [(name, ty)] +  where uncurry' ns (Abs n' t' body') = uncurry' ((n', t'):ns) body'+        uncurry' ns body'             = (reverse ns, body')++uncurryTyAbs :: t -> SystemFExpr n t -> ([t], SystemFExpr n t)+uncurryTyAbs ty = uncurry' [ty]+  where uncurry' ts (TyAbs t' body') = uncurry' (t':ts) body'+        uncurry' ts body'            = (reverse ts, body')
+ src/Language/Lambda/SystemF/Parser.hs view
@@ -0,0 +1,88 @@+module Language.Lambda.SystemF.Parser (+  parseExpr,+  parseType+  ) where++import Control.Monad+import Data.Functor+import RIO hiding ((<|>), abs, many, try)+import qualified RIO.Text as Text++import Text.Parsec+import Text.Parsec.Text++import Language.Lambda.SystemF.Expression++parseExpr :: Text -> Either ParseError (SystemFExpr Text Text)+parseExpr = parse (whitespace *> expr <* eof) ""++parseType :: Text -> Either ParseError (Ty Text)+parseType = parse (whitespace *> ty <* eof) ""++-- Parse expressions+expr :: Parser (SystemFExpr Text Text)+expr = try tyapp <|> try app <|> term++app :: Parser (SystemFExpr Text Text)+app = chainl1 term (return App)++tyapp :: Parser (SystemFExpr Text Text)+tyapp = TyApp+      <$> term+      <*> ty'+  where ty' = symbol '[' *> ty <* symbol ']'++term :: Parser (SystemFExpr Text Text)+term = try abs <|> tyabs <|> var <|> parens expr++var :: Parser (SystemFExpr Text Text)+var = Var <$> exprId++abs :: Parser (SystemFExpr Text Text)+abs = curry'+    <$> (symbol '\\' *> many1 args <* symbol '.') +    <*> expr+  where args = (,) <$> (exprId <* symbol ':') <*> ty+        curry' = flip . foldr . uncurry $ Abs++tyabs :: Parser (SystemFExpr Text Text)+tyabs = curry' <$> args <*> expr+  where args = symbol '\\' *> many1 typeId <* symbol '.'+        curry' = flip (foldr TyAbs)++-- Parse type expressions+ty :: Parser (Ty Text)+ty = try arrow++arrow :: Parser (Ty Text)+arrow = chainr1 tyterm (symbol' "->" $> TyArrow)++tyterm :: Parser (Ty Text)+tyterm = tyvar <|> parens ty++tyvar :: Parser (Ty Text)+tyvar = TyVar <$> typeId++parens :: Parser a -> Parser a+parens p = symbol '(' *> p <* symbol ')'++identifier :: Parser Char -> Parser Text+identifier firstChar = lexeme $ Text.cons <$> first' <*> (Text.pack <$> many rest)+  where first' = firstChar <|> char '_'+        rest = first' <|> digit++typeId, exprId :: Parser Text+typeId = identifier upper+exprId = identifier lower++whitespace :: Parser ()+whitespace = void . many . oneOf $ " \t"++symbol :: Char -> Parser ()+symbol = void . lexeme . char++symbol' :: Text -> Parser ()+symbol' = void . lexeme . string . Text.unpack++lexeme :: Parser a -> Parser a+lexeme p = p <* whitespace
+ src/Language/Lambda/SystemF/State.hs view
@@ -0,0 +1,89 @@+module Language.Lambda.SystemF.State+  ( TypecheckState(..),+    Typecheck(),+    Context(),+    runTypecheck,+    execTypecheck,+    unsafeRunTypecheck,+    unsafeExecTypecheck,+    mkTypecheckState,+    context,+    uniques,+    getContext,+    getUniques,+    modifyContext,+    modifyUniques,+    setContext,+    setUniques+  ) where++import Language.Lambda.Shared.Errors (LambdaException(..))+import Language.Lambda.SystemF.Expression (Ty(..))++import Control.Monad.Except (Except(), runExcept)+import RIO+import RIO.State+import qualified RIO.Map as Map++data TypecheckState name = TypecheckState+  { tsContext :: Context name,+    tsUniques :: [name]+  }++type Typecheck name+  = StateT (TypecheckState name)+      (Except LambdaException)++type Context name = Map name (Ty name)++runTypecheck+  :: Typecheck name result+  -> TypecheckState name+  -> Either LambdaException (result, TypecheckState name)+runTypecheck computation = runExcept . runStateT computation++execTypecheck+  :: Typecheck name result+  -> TypecheckState name+  -> Either LambdaException result+execTypecheck computation = runExcept . evalStateT computation++unsafeRunTypecheck+  :: Typecheck name result+  -> TypecheckState name+  -> (result, TypecheckState name)+unsafeRunTypecheck computation state' = either impureThrow id tcResult+  where tcResult = runTypecheck computation state'++unsafeExecTypecheck :: Typecheck name result -> TypecheckState name -> result+unsafeExecTypecheck computation state' = either impureThrow id tcResult+  where tcResult = execTypecheck computation state'++mkTypecheckState :: [name] -> TypecheckState name+mkTypecheckState = TypecheckState Map.empty++uniques :: Lens' (TypecheckState name) [name]+uniques f state' = (\uniques' -> state' { tsUniques = uniques' })+  <$> f (tsUniques state')++context :: Lens' (TypecheckState name) (Context name)+context f state' = (\context' -> state' { tsContext = context' })+  <$> f (tsContext state')++getUniques :: Typecheck name [name]+getUniques = gets (^. uniques)++getContext :: Typecheck name (Context name)+getContext = gets (^. context)++modifyContext :: (Context name -> Context name) -> Typecheck name ()+modifyContext f = modify $ context %~ f++modifyUniques :: ([name] -> [name]) -> Typecheck name ()+modifyUniques f = modify $ uniques %~ f++setUniques :: [name] -> Typecheck name ()+setUniques uniques' = modify (& uniques .~ uniques')++setContext :: Context name -> Typecheck name ()+setContext context' = modify (& context .~ context')
+ src/Language/Lambda/SystemF/TypeCheck.hs view
@@ -0,0 +1,122 @@+module Language.Lambda.SystemF.TypeCheck where++import Language.Lambda.Shared.Errors (LambdaException(..))+import Language.Lambda.SystemF.Expression+import Language.Lambda.SystemF.State++import Control.Monad.Except (MonadError(..))+import Prettyprinter+import RIO+import qualified RIO.List as List+import qualified RIO.Map as Map++type UniqueSupply n = [n]+type Context' n t = Map n t++-- TODO: name/ty different types+typecheck+  :: (Ord name, Pretty name)+  => SystemFExpr name name+  -> Typecheck name (Ty name)+typecheck (Var v) = typecheckVar v+typecheck (Abs n t body) = typecheckAbs n t body+typecheck (App e1 e2) = typecheckApp e1 e2+typecheck (TyAbs t body) = typecheckTyAbs t body+typecheck (TyApp e ty) = typecheckTyApp e ty++typecheckVar :: Ord name => name -> Typecheck name (Ty name)+typecheckVar var = getContext >>= defaultToFreshTyVar . Map.lookup var+  where defaultToFreshTyVar (Just v) = return v+        defaultToFreshTyVar Nothing = TyVar <$> unique++typecheckAbs+  :: (Ord name, Pretty name)+  => name+  -> Ty name+  -> SystemFExpr name name+  -> Typecheck name (Ty name)+typecheckAbs name ty body+  = modifyContext (Map.insert name ty)+    >> TyArrow ty <$> typecheck body++typecheckApp+  :: (Ord name, Pretty name)+  => SystemFExpr name name+  -> SystemFExpr name name+  -> Typecheck name (Ty name)+typecheckApp e1 e2 = do+  -- Typecheck expressions+  t1 <- typecheck e1+  t2 <- typecheck e2++  -- Verify the type of t1 is an Arrow+  (t1AppInput, t1AppOutput) <- case t1 of+    (TyArrow appInput appOutput) -> return (appInput, appOutput)+    t1' -> throwError $ tyMismatchError t1' t1++  -- Verify the output of e1 matches the type of e2+  if t1AppInput == t2+    then return t1AppOutput+    else throwError $ tyMismatchError (TyArrow t2 t1AppOutput) (TyArrow t1 t1AppOutput)++typecheckTyAbs+  :: (Ord name, Pretty name)+  => name+  -> SystemFExpr name name+  -> Typecheck name (Ty name)+typecheckTyAbs ty body+  = modifyContext (Map.insert ty (TyVar ty))+    >> TyForAll ty <$> typecheck body++typecheckTyApp+  :: (Ord name, Pretty name)+  => SystemFExpr name name+  -> Ty name+  -> Typecheck name (Ty name)+typecheckTyApp (TyAbs t expr) ty = typecheck $ substitute ty t expr+typecheckTyApp expr _ = typecheck expr++unique :: Typecheck name name+unique = getUniques >>= fromJust' . List.headMaybe+  where fromJust' (Just u) = return u+        fromJust' Nothing = throwError ImpossibleError++substitute+  :: Eq n+  => Ty n+  -> n+  -> SystemFExpr n n+  -> SystemFExpr n n+substitute ty name (App e1 e2) = App (substitute ty name e1) (substitute ty name e2)+substitute ty name (Abs n ty' e) = Abs n (substituteTy ty name ty') (substitute ty name e)+substitute ty name (TyAbs ty' e) = TyAbs ty' (substitute ty name e) +substitute ty name (TyApp e ty') = TyApp (substitute ty name e) (substituteTy ty name ty')+substitute _ _ expr = expr++substituteTy+  :: Eq name+  => Ty name+  -> name+  -> Ty name+  -> Ty name+substituteTy ty name (TyArrow t1 t2) +  = TyArrow (substituteTy ty name t1) (substituteTy ty name t2)+substituteTy ty name ty'@(TyVar name') +  | name == name' = ty+  | otherwise     = ty'+substituteTy _ name t2@(TyForAll name' t2') +  | name == name' = t2+  | otherwise     = TyForAll name' (substituteTy t2 name t2')+++tyMismatchError+  :: (Pretty t1, Pretty t2)+  => t1+  -> t2+  -> LambdaException+tyMismatchError expected actual+  = TyMismatchError+  $ "Couldn't match expected type "+  <> prettyPrint expected+  <> " with actual type "+  <> prettyPrint actual
+ src/Language/Lambda/Untyped.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE FlexibleInstances #-}+module Language.Lambda.Untyped (+  evalText,+  runEvalText,+  execEvalText,+  unsafeExecEvalText,+  defaultUniques,++  module Language.Lambda.Untyped.Expression,+  module Language.Lambda.Untyped.Eval,+  module Language.Lambda.Untyped.Parser,+  module Language.Lambda.Untyped.State+  ) where++import Control.Monad.Except+import Data.Either+import RIO+import qualified RIO.Text as Text++import Language.Lambda.Shared.Errors+import Language.Lambda.Shared.UniqueSupply (defaultUniques)+import Language.Lambda.Untyped.Eval+import Language.Lambda.Untyped.Expression+import Language.Lambda.Untyped.Parser+import Language.Lambda.Untyped.State++evalText :: Text -> Eval Text (LambdaExpr Text)+evalText = either throwParseError evalExpr' . parseExpr+  where throwParseError = throwError . ParseError . Text.pack . show+        evalExpr' = evalExpr++runEvalText+  :: Text+  -> Globals Text+  -> Either LambdaException (LambdaExpr Text, EvalState Text)+runEvalText input globals' = runEval (evalText input) (mkState globals')++execEvalText+  :: Text+  -> Globals Text+  -> Either LambdaException (LambdaExpr Text)+execEvalText input globals' = execEval (evalText input) (mkState globals')++unsafeExecEvalText+  :: Text+  -> Globals Text+  -> LambdaExpr Text+unsafeExecEvalText input globals'+  = unsafeExecEval (evalText input) (mkState globals')++mkState :: Globals Text -> EvalState Text+mkState = flip EvalState defaultUniques
+ src/Language/Lambda/Untyped/Eval.hs view
@@ -0,0 +1,121 @@+module Language.Lambda.Untyped.Eval+  ( EvalState(..),+    evalExpr,+    subGlobals,+    betaReduce,+    alphaConvert,+    etaConvert,+    freeVarsOf+  ) where++import Control.Monad.Except+import Prettyprinter+import RIO+import RIO.List (find)+import qualified RIO.Map as Map++import Language.Lambda.Shared.Errors+import Language.Lambda.Untyped.Expression+import Language.Lambda.Untyped.State++-- | Evaluate an expression+evalExpr :: (Pretty name, Ord name) => LambdaExpr name -> Eval name (LambdaExpr name)+evalExpr (Let name expr) = do+  globals' <- getGlobals+  result <- evalExpr' $ subGlobals globals' expr++  setGlobals $ Map.insert name result globals'++  return $ Let name result++evalExpr expr = do+  globals' <- getGlobals+  evalExpr' $ subGlobals globals' expr++-- | Evaluate an expression; does not support `let`+evalExpr' :: (Eq name, Pretty name) => LambdaExpr name -> Eval name (LambdaExpr name)+evalExpr' expr@(Var _) = return expr+evalExpr' (Abs name expr) = Abs name <$> evalExpr' expr+evalExpr' (App e1 e2) = do+  e1' <- evalExpr' e1+  e2' <- evalExpr' e2+  betaReduce e1' e2'+evalExpr' expr@(Let _ _) = throwError . InvalidLet . prettyPrint $ expr++-- | Look up free vars that have global bindings and substitute them+subGlobals+  :: Ord name+  => Map name (LambdaExpr name)+  -> LambdaExpr name+  -> LambdaExpr name+subGlobals globals' expr@(Var x) = Map.findWithDefault expr x globals'+subGlobals globals' (App e1 e2) = App (subGlobals globals' e1) (subGlobals globals' e2)+subGlobals globals' (Abs name expr) = Abs name expr'+  where expr'+          | Map.member name globals' = expr+          | otherwise = subGlobals globals' expr+subGlobals _ expr = expr++-- | Function application+betaReduce+  :: (Eq name, Pretty name)+  => LambdaExpr name+  -> LambdaExpr name+  -> Eval name (LambdaExpr name)+betaReduce expr@(Var _) e2 = return $ App expr e2+betaReduce (App e1 e1') e2 = do+  reduced <- betaReduce e1 e1'+  return $ App reduced e2+betaReduce (Abs n e1) e2 = do+  e1' <- alphaConvert (freeVarsOf e2) e1+  evalExpr' $ substitute e1' n e2+betaReduce _ _ = throwError ImpossibleError++-- | Rename abstraction parameters to avoid name captures+alphaConvert :: Eq name => [name] -> LambdaExpr name -> Eval name (LambdaExpr name)+alphaConvert freeVars (Abs name body) = do+  uniques' <- getUniques+  let nextVar = fromMaybe name $ find (`notElem` freeVars) uniques'++  if name `elem` freeVars+    then return $ Abs nextVar (substitute body name (Var nextVar))+    else Abs name <$> alphaConvert freeVars body++alphaConvert _ expr = return expr++-- | Eliminite superfluous abstractions+etaConvert :: Eq n => LambdaExpr n -> LambdaExpr n+etaConvert (Abs n (App e1 (Var n')))+  | n == n'   = etaConvert e1+  | otherwise = Abs n (App (etaConvert e1) (Var n'))+etaConvert (Abs n e@(Abs _ _)) +  -- If `etaConvert e == e` then etaConverting it will create an infinite loop+  | e == e'   = Abs n e'+  | otherwise = etaConvert (Abs n e')+  where e' = etaConvert e+etaConvert (Abs n expr) = Abs n (etaConvert expr)+etaConvert (App e1 e2)  = App (etaConvert e1) (etaConvert e2)+etaConvert expr = expr++-- | Substitute an expression for a variable name in another expression+substitute :: Eq name => LambdaExpr name -> name -> LambdaExpr name -> LambdaExpr name+substitute subExpr@(Var name) subName inExpr+  | name == subName = inExpr+  | otherwise = subExpr++substitute subExpr@(Abs name expr) subName inExpr+  | name == subName = subExpr+  | otherwise = Abs name (substitute expr subName inExpr)++substitute (App e1 e2) subName inExpr+  = App (sub e1) (sub e2)+  where sub expr = substitute expr subName inExpr++substitute _ _ expr = expr++-- | Find the free variables in an expression+freeVarsOf :: Eq n => LambdaExpr n -> [n]+freeVarsOf (Abs n expr) = filter (/=n) . freeVarsOf $ expr+freeVarsOf (App e1 e2)  = freeVarsOf e1 ++ freeVarsOf e2+freeVarsOf (Var n)      = [n]+freeVarsOf _ = []
+ src/Language/Lambda/Untyped/Expression.hs view
@@ -0,0 +1,57 @@+module Language.Lambda.Untyped.Expression+  ( LambdaExpr(..),+    lambda,+    prettyPrint+  ) where++import RIO+import Prettyprinter+import Prettyprinter.Render.Text (renderStrict)++data LambdaExpr name+  = Var name                                -- ^ Variables+  | App (LambdaExpr name) (LambdaExpr name) -- ^ Application+  | Abs name (LambdaExpr name)              -- ^ Abstractions+  | Let name (LambdaExpr name)              -- ^ Let bindings+  deriving (Eq, Show)++instance Pretty name => Pretty (LambdaExpr name) where+  pretty (Var name) = pretty name+  pretty (Abs name body) = prettyAbs name body+  pretty (App e1 e2) = prettyApp e1 e2+  pretty (Let name body) = prettyLet name body++prettyPrint :: Pretty name => LambdaExpr name -> Text+prettyPrint expr = renderStrict docStream+  where docStream = layoutPretty defaultLayoutOptions (pretty expr)++lambda :: Char+lambda = 'λ'++prettyAbs :: Pretty name => name -> LambdaExpr name -> Doc a+prettyAbs name body+  = lambda' <> hsep (map pretty names) <> dot+    <+> pretty body'+  where (names, body') = uncurryAbs name body++prettyApp :: Pretty name => LambdaExpr name -> LambdaExpr name -> Doc a+prettyApp e1@(Abs _ _) e2@(Abs _ _) = parens (pretty e1) <+> parens (pretty e2)+prettyApp e1@(Abs _ _) e2 = parens (pretty e1) <+> pretty e2+prettyApp e1 e2@(Abs _ _) = pretty e1 <+> parens (pretty e2)+prettyApp e1 e2@(App _ _) = pretty e1 <+> parens (pretty e2)+prettyApp e1 e2 = pretty e1 <+> pretty e2++prettyLet :: Pretty name => name -> LambdaExpr name -> Doc a+prettyLet name body+  = pretty ("let"::Text)+    <+> pretty name+    <+> "="+    <+> pretty body++lambda' :: Doc ann+lambda' = pretty lambda++uncurryAbs :: n -> LambdaExpr n -> ([n], LambdaExpr n)+uncurryAbs n = uncurry' [n]+  where uncurry' ns (Abs n' body') = uncurry' (n':ns) body'+        uncurry' ns body'          = (reverse ns, body')
+ src/Language/Lambda/Untyped/Parser.hs view
@@ -0,0 +1,57 @@+module Language.Lambda.Untyped.Parser+  ( parseExpr,+    module Text.Parsec+  ) where++import Control.Monad+import RIO hiding ((<|>), abs, curry, many, try)+import qualified RIO.Text as Text++import Text.Parsec+import Text.Parsec.Text++import Language.Lambda.Untyped.Expression++parseExpr :: Text -> Either ParseError (LambdaExpr Text)+parseExpr = parse (whitespace *> expr <* eof) ""++expr :: Parser (LambdaExpr Text)+expr = try app <|> term++term :: Parser (LambdaExpr Text)+term = let' <|> abs <|> var <|> parens++var :: Parser (LambdaExpr Text)+var = Var <$> identifier++abs :: Parser (LambdaExpr Text)+abs = curry <$> idents <*> expr+  where idents = symbol '\\' *> many1 identifier <* symbol '.'+        curry = flip (foldr Abs)++app :: Parser (LambdaExpr Text)+app = chainl1 term (return App)++let' :: Parser (LambdaExpr Text)+let' = Let <$> ident <*> expr+  where ident = keyword "let" *> identifier <* symbol '='++parens :: Parser (LambdaExpr Text)+parens = symbol '(' *> expr <* symbol ')'++lexeme :: Parser a -> Parser a+lexeme p =  p <* whitespace++whitespace :: Parser ()+whitespace = void . many . oneOf $ " \t"++identifier :: Parser Text+identifier = lexeme $ Text.cons <$> first' <*> (Text.pack <$> many rest)+  where first' = letter <|> char '_'+        rest  = first' <|> digit++symbol :: Char -> Parser ()+symbol = void . lexeme . char++keyword :: Text -> Parser ()+keyword = void . lexeme . string . Text.unpack
+ src/Language/Lambda/Untyped/State.hs view
@@ -0,0 +1,88 @@+module Language.Lambda.Untyped.State+  ( EvalState(..),+    Eval(),+    Globals(),+    runEval,+    execEval,+    unsafeExecEval,+    unsafeRunEval,+    globals,+    uniques,+    mkEvalState,+    getGlobals,+    getUniques,+    setGlobals,+    setUniques+  ) where++import Language.Lambda.Shared.Errors+import Language.Lambda.Untyped.Expression ++import Control.Monad.Except+import RIO+import RIO.State+import qualified RIO.Map as Map++-- | The evaluation state+data EvalState name = EvalState+  { esGlobals :: Globals name,+    esUniques :: [name] -- ^ Unused unique names+  }++-- | A stateful computation+type Eval name+  = StateT (EvalState name)+      (Except LambdaException)++-- | A mapping of global variables to expressions+type Globals name = Map name (LambdaExpr name)++-- | Run an evalualation+runEval :: Eval name result -> EvalState name -> Either LambdaException (result, EvalState name)+runEval computation = runExcept . runStateT computation++-- | Run an evalualation, throwing away the final state+execEval :: Eval name result -> EvalState name -> Either LambdaException result+execEval computation = runExcept . evalStateT computation++-- | Run an evaluation. If the result is an error, throws it+unsafeRunEval :: Eval name result -> EvalState name -> (result, EvalState name)+unsafeRunEval computation state'+  = case runEval computation state' of+      Left err -> error $ show err+      Right res -> res+  +-- | Run an evaluation, throwing away the final state. If the result is an error, throws it+unsafeExecEval:: Eval name result -> EvalState name -> result+unsafeExecEval computation state'+  = case execEval computation state' of+      Left err -> impureThrow err+      Right res -> res++-- | Create an EvalState+mkEvalState :: [name] -> EvalState name+mkEvalState = EvalState Map.empty++globals :: Lens' (EvalState name) (Globals name)+globals f state'+  = (\globals' -> state' { esGlobals = globals' })+  <$> f (esGlobals state')++uniques :: Lens' (EvalState name) [name]+uniques f state'+  = (\uniques' -> state' { esUniques = uniques' })+  <$> f (esUniques state')++-- | Access globals from the state monad+getGlobals :: Eval name (Globals name)+getGlobals = gets (^. globals)++-- | Access unique supply from state monad+getUniques :: Eval name [name]+getUniques = gets (^. uniques)++setGlobals :: Globals name -> Eval name ()+setGlobals globals' = modify (& globals .~ globals')++setUniques :: [name] -> Eval name ()+setUniques uniques' = modify (& uniques .~ uniques')
− src/Language/Lambda/Util/PrettyPrint.hs
@@ -1,53 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-module Language.Lambda.Util.PrettyPrint where--import qualified Data.List as L--class PrettyPrint a where-  prettyPrint :: a -> String--instance PrettyPrint String where-  prettyPrint = id-  -newtype PDoc s = PDoc [s]-  deriving (Eq, Show)--instance PrettyPrint s => PrettyPrint (PDoc s) where-  prettyPrint (PDoc ls) = concatMap prettyPrint ls--instance Monoid (PDoc s) where-  mempty = empty-  (PDoc p1) `mappend` (PDoc p2) = PDoc $ p1 ++ p2--instance Functor PDoc where-  fmap f (PDoc ls) = PDoc (fmap f ls)--empty :: PDoc s-empty = PDoc []--add :: s -> PDoc s -> PDoc s-add s (PDoc ps) = PDoc (s:ps)--append :: [s] -> PDoc s -> PDoc s-append =  mappend . PDoc--between :: PDoc s -> s -> s -> PDoc s -> PDoc s-between (PDoc str) start end pdoc = PDoc ((start:str) ++ [end]) `mappend` pdoc--betweenParens :: PDoc String -> PDoc String -> PDoc String-betweenParens doc = between doc "(" ")"--intercalate :: [[s]] -> [s] -> PDoc [s] -> PDoc [s]-intercalate ss sep = add $ L.intercalate sep ss--addSpace :: PDoc String -> PDoc String-addSpace = add [space]-  -space :: Char-space = ' '--lambda :: Char-lambda = 'λ'--upperLambda :: Char-upperLambda = 'Λ'
− src/Language/SystemF.hs
@@ -1,16 +0,0 @@-module Language.SystemF (-  PrettyPrint(..),-  SystemFExpr(..),-  evalString,-  parseExpr-  ) where--import Text.Parsec--import Language.Lambda.Util.PrettyPrint-import Language.SystemF.Expression-import Language.SystemF.Parser--evalString :: String -> Either ParseError (SystemFExpr String String)-evalString = parseExpr-
− src/Language/SystemF/Expression.hs
@@ -1,145 +0,0 @@-module Language.SystemF.Expression where--import Data.Monoid--import Language.Lambda.Util.PrettyPrint--data SystemFExpr name ty-  = Var name                                        -- Variable-  | App (SystemFExpr name ty) (SystemFExpr name ty) -- Application-  | Abs name (Ty ty) (SystemFExpr name ty)          -- Abstraction-  | TyAbs ty (SystemFExpr name ty)                  -- Type Abstraction-                                                    -- \X. body--  | TyApp (SystemFExpr name ty) (Ty ty)             -- Type Application-                                                    -- x [X]-  deriving (Eq, Show)--data Ty name-  = TyVar name                  -- Type variable (T)-  | TyArrow (Ty name) (Ty name) -- Type arrow    (T -> U)-  | TyForAll name (Ty name)     -- Universal type (forall T. X)-  deriving (Eq, Show)---- Pretty printing-instance (PrettyPrint n, PrettyPrint t) => PrettyPrint (SystemFExpr n t) where-  prettyPrint = prettyPrint . pprExpr empty--instance PrettyPrint n => PrettyPrint (Ty n) where-  prettyPrint = prettyPrint . pprTy empty True---- Same as prettyPrint, but we assume the same type for names and types. Useful--- for testing.-prettyPrint' :: PrettyPrint n => SystemFExpr n n -> String-prettyPrint' = prettyPrint---- Pretty print a system f expression-pprExpr :: (PrettyPrint n, PrettyPrint t) -        => PDoc String -        -> SystemFExpr n t-        -> PDoc String-pprExpr pdoc (Var n)        = prettyPrint n `add` pdoc-pprExpr pdoc (App e1 e2)    = pprApp pdoc e1 e2-pprExpr pdoc (Abs n t body) = pprAbs pdoc n t body-pprExpr pdoc (TyAbs t body) = pprTAbs pdoc t body-pprExpr pdoc (TyApp e ty)   = pprTApp pdoc e ty---- Pretty print an application-pprApp :: (PrettyPrint n, PrettyPrint t)-       => PDoc String-       -> SystemFExpr n t-       -> SystemFExpr n t-       -> PDoc String-pprApp pdoc e1@Abs{} e2@Abs{} = betweenParens (pprExpr pdoc e1) pdoc-  `mappend` addSpace (betweenParens (pprExpr pdoc e2) pdoc)-pprApp pdoc e1 e2@App{} = pprExpr pdoc e1-  `mappend` addSpace (betweenParens (pprExpr pdoc e2) pdoc)-pprApp pdoc e1 e2@Abs{} = pprExpr pdoc e1-  `mappend` addSpace (betweenParens (pprExpr pdoc e2) pdoc)-pprApp pdoc e1@Abs{} e2 = betweenParens (pprExpr pdoc e1) pdoc-  `mappend` addSpace (pprExpr pdoc e2)-pprApp pdoc e1 e2-  = pprExpr pdoc e1 `mappend` addSpace (pprExpr pdoc e2)--pprTApp :: (PrettyPrint n, PrettyPrint t)-        => PDoc String-        -> SystemFExpr n t-        -> Ty t-        -> PDoc String-pprTApp pdoc expr ty = expr' `mappend` addSpace (between ty' "[" "]" empty)-  where expr' = pprExpr pdoc expr-        ty' = add (prettyPrint ty) empty---- Pretty print an abstraction-pprAbs :: (PrettyPrint n, PrettyPrint t)-       => PDoc String-       -> n-       -> Ty t-       -> SystemFExpr n t-       -> PDoc String-pprAbs pdoc name ty body = between vars' lambda' ". " (pprExpr pdoc body')-  where (vars, body') = uncurryAbs name ty body-        vars' = intercalate (map (uncurry pprArg) vars) " " empty-        lambda' = [lambda, space]--        pprArg n t = prettyPrint n ++ (':':pprArg' t)-        pprArg' t@(TyVar _)     = prettyPrint t-        pprArg' t@(TyArrow _ _) = prettyPrint $ betweenParens (pprTy empty False t) empty---- Pretty print types-pprTy :: PrettyPrint n-      => PDoc String-      -> Bool -- Add a space between arrows?-      -> Ty n-      -> PDoc String-pprTy pdoc space (TyVar n) = prettyPrint n `add` pdoc-pprTy pdoc space (TyArrow a b) = pprTyArrow pdoc space a b-pprTy pdoc _     (TyForAll n t) =  pprTyForAll pdoc n t--pprTyArrow :: PrettyPrint n-           => PDoc String-           -> Bool -- Add a space between arrows?-           -> Ty n-           -> Ty n-           -> PDoc String-pprTyArrow pdoc space a@(TyVar _) b = pprTyArrow' space (pprTy pdoc space a) -                                                        (pprTy pdoc space b)-pprTyArrow pdoc space (TyArrow a1 a2) b = pprTyArrow' space a' (pprTy pdoc space b)-  where a' = betweenParens (pprTyArrow pdoc space a1 a2) empty--pprTyArrow' :: Bool -- Add a space between arrows?-            -> PDoc String-            -> PDoc String-            -> PDoc String-pprTyArrow' space a b = a <> arrow <> b-  where arrow | space     = " -> " `add` empty-              | otherwise = "->" `add` empty--pprTyForAll :: PrettyPrint n-            => PDoc String-            -> n-            -> Ty n-            -> PDoc String-pprTyForAll pdoc n t = prefix <> prettyPrint t `add` pdoc-  where prefix = between (prettyPrint n `add` empty) "forall " ". " empty---- Pretty print a type abstraction-pprTAbs :: (PrettyPrint n, PrettyPrint t)-        => PDoc String-        -> t-        -> SystemFExpr n t-        -> PDoc String-pprTAbs pdoc ty body = between vars' lambda' ". " (pprExpr pdoc body')-  where (vars, body') = uncurryTAbs ty body-        vars' = intercalate (map prettyPrint vars) " " empty-        lambda' = [upperLambda, space]--uncurryAbs :: n -> Ty t -> SystemFExpr n t -> ([(n, Ty t)], SystemFExpr n t)-uncurryAbs name ty = uncurry' [(name, ty)] -  where uncurry' ns (Abs n' t' body') = uncurry' ((n', t'):ns) body'-        uncurry' ns body'             = (reverse ns, body')--uncurryTAbs :: t -> SystemFExpr n t -> ([t], SystemFExpr n t)-uncurryTAbs ty = uncurry' [ty]-  where uncurry' ts (TyAbs t' body') = uncurry' (t':ts) body'-        uncurry' ts body'            = (reverse ts, body')
− src/Language/SystemF/Parser.hs
@@ -1,86 +0,0 @@-module Language.SystemF.Parser (-  parseExpr,-  parseType-  ) where--import Control.Monad-import Prelude hiding (abs)--import Text.Parsec-import Text.Parsec.String--import Language.SystemF.Expression--parseExpr :: String -> Either ParseError (SystemFExpr String String)-parseExpr = parse (whitespace *> expr <* eof) ""--parseType :: String -> Either ParseError (Ty String)-parseType = parse (whitespace *> ty <* eof) ""---- Parse expressions-expr :: Parser (SystemFExpr String String)-expr = try tyapp <|> try app <|> term--app :: Parser (SystemFExpr String String)-app = chainl1 term (return App)--tyapp :: Parser (SystemFExpr String String)-tyapp = TyApp-      <$> term-      <*> ty'-  where ty' = symbol '[' *> ty <* symbol ']'--term :: Parser (SystemFExpr String String)-term = try abs <|> tyabs <|> var <|> parens expr--var :: Parser (SystemFExpr String String)-var = Var <$> exprId--abs :: Parser (SystemFExpr String String)-abs = curry -    <$> (symbol '\\' *> many1 args <* symbol '.') -    <*> expr-  where args = (,) <$> (exprId <* symbol ':') <*> ty-        curry = flip . foldr . uncurry $ Abs--tyabs :: Parser (SystemFExpr String String)-tyabs = curry <$> args <*> expr-  where args = symbol '\\' *> many1 typeId <* symbol '.'-        curry = flip (foldr TyAbs)---- Parse type expressions-ty :: Parser (Ty String)-ty = try arrow--arrow :: Parser (Ty String)-arrow = chainr1 tyterm (symbol' "->" *> return TyArrow)--tyterm :: Parser (Ty String)-tyterm = tyvar <|> parens ty--tyvar :: Parser (Ty String)-tyvar = TyVar <$> typeId--parens :: Parser a -> Parser a-parens p = symbol '(' *> p <* symbol ')'--identifier :: Parser Char -> Parser String-identifier firstChar = lexeme ((:) <$> first <*> many rest)-  where first = firstChar <|> char '_'-        rest = first <|> digit--typeId, exprId :: Parser String-typeId = identifier upper-exprId = identifier lower--whitespace :: Parser ()-whitespace = void . many . oneOf $ " \t"--symbol :: Char -> Parser ()-symbol = void . lexeme . char--symbol' :: String -> Parser ()-symbol' = void . lexeme . string--lexeme :: Parser a -> Parser a-lexeme p = p <* whitespace
− src/Language/SystemF/TypeCheck.hs
@@ -1,119 +0,0 @@-module Language.SystemF.TypeCheck where--import Data.Map-import Prelude hiding (lookup)--import Language.Lambda.Util.PrettyPrint-import Language.SystemF.Expression--type UniqueSupply n = [n]-type Context n t = Map n t--typecheck :: (Ord n, Eq n, PrettyPrint n)-          => UniqueSupply n -          -> Context n (Ty n)-          -> SystemFExpr n n -          -> Either String (Ty n)-typecheck uniqs ctx (Var v)        = tcVar uniqs ctx v-typecheck uniqs ctx (Abs n t body) = tcAbs uniqs ctx n t body-typecheck uniqs ctx (App e1 e2)    = tcApp uniqs ctx e1 e2-typecheck uniqs ctx (TyAbs t body) = tcTyAbs uniqs ctx t body-typecheck uniqs ctx (TyApp e ty)   = tcTyApp uniqs ctx e ty--tcVar :: (Ord n, Eq n, PrettyPrint n)-      => UniqueSupply n-      -> Context n (Ty n)-      -> n-      -> Either String (Ty n)-tcVar uniqs ctx var = maybe (TyVar <$> unique uniqs) return (lookup var ctx)--tcAbs :: (Ord n, Eq n, PrettyPrint n)-      => UniqueSupply n-      -> Context n (Ty n)-      -> n-      -> Ty n-      -> SystemFExpr n n-      -> Either String (Ty n)-tcAbs uniqs ctx name ty body = TyArrow ty <$> typecheck uniqs ctx' body-  where ctx' = insert name ty ctx--tcApp :: (Ord n, Eq n, PrettyPrint n)-      => UniqueSupply n-      -> Context n (Ty n)-      -> SystemFExpr n n-      -> SystemFExpr n n-      -> Either String (Ty n)-tcApp uniqs ctx e1 e2 = do-    t1 <- typecheck uniqs ctx e1-    t2 <- typecheck uniqs ctx e2--    -- Unwrap t1; Should be (t2 -> *)-    (t2', t3) <- either genMismatchVar return (arrow t1)--    if t2' == t2-      then return t3-      else Left $ tyMismatchMsg (TyArrow t2 t3) (TyArrow t1 t3)--  where genMismatchVar expected = tyMismatchMsg expected <$> unique uniqs >>= Left-        arrow (TyArrow t1 t2) = return (t1, t2)-        arrow t               = Left t--tcTyAbs :: (Ord n, Eq n, PrettyPrint n)-        => UniqueSupply n-        -> Context n (Ty n)-        -> n-        -> SystemFExpr n n-        -> Either String (Ty n)-tcTyAbs uniqs ctx ty body = TyForAll ty <$> typecheck uniqs ctx' body-  where ctx' = insert ty (TyVar ty) ctx--tcTyApp :: (Ord n, Eq n, PrettyPrint n)-        => UniqueSupply n-        -> Context n (Ty n)-        -> SystemFExpr n n-        -> Ty n-        -> Either String (Ty n)-tcTyApp uniqs ctx (TyAbs t expr) ty = typecheck uniqs ctx expr'-  where expr' = sub t ty expr-tcTyApp uniqs ctx expr ty = typecheck uniqs ctx expr---- Utilities-unique :: UniqueSupply t-       -> Either String t-unique (u:_) = return u-unique _     = fail "Unique supply ran out"--sub :: Eq n-    => n-    -> Ty n-    -> SystemFExpr n n-    -> SystemFExpr n n-sub name ty (App e1 e2)   = App (sub name ty e1) (sub name ty e2)-sub name ty (Abs n ty' e) = Abs n (subTy name ty ty') (sub name ty e)-sub name ty (TyAbs ty' e) = TyAbs ty' (sub name ty e) -sub name ty (TyApp e ty') = TyApp (sub name ty e) (subTy name ty ty')-sub name ty expr = expr--subTy :: Eq n-      => n-      -> Ty n-      -> Ty n-      -> Ty n-subTy name ty (TyArrow t1 t2) -  = TyArrow (subTy name ty t1) (subTy name ty t2)-subTy name ty ty'@(TyVar name') -  | name == name' = ty-  | otherwise     = ty'-subTy name t1 t2@(TyForAll name' t2') -  | name == name' = t2-  | otherwise     = TyForAll name' (subTy name t2 t2')---tyMismatchMsg :: (PrettyPrint t, PrettyPrint t')-              => t-              -> t'-              -> String-tyMismatchMsg expected actual = "Couldn't match expected type " ++-                                prettyPrint expected ++-                                " with actual type " ++-                                prettyPrint actual
− test/HLint.hs
@@ -1,16 +0,0 @@-module Main (main) where--import Language.Haskell.HLint (hlint)-import System.Exit (exitFailure, exitSuccess)--arguments :: [String]-arguments = [ -  "app",-  "src",-  "test"-  ]--main :: IO ()-main = hlint arguments >>= main'-  where main' [] = exitSuccess-        main' _  = exitFailure
− test/Language/Lambda/EvalSpec.hs
@@ -1,110 +0,0 @@-module Language.Lambda.EvalSpec where--import Test.Hspec--import Language.Lambda-import Language.Lambda.Eval-import Language.Lambda.Expression--spec :: Spec-spec = do-  describe "evalExpr" $ do-    let evalExpr' = evalExpr uniques-    -    it "beta reduces" $ do-      let expr = App (Abs "x" (Var "x")) (Var "z")-      evalExpr' expr `shouldBe` Var "z"--    it "reduces multiple applications" $ do-      let expr = App (App (Abs "f" (Abs "x" (App (Var "f") (Var "x")))) (Var "g")) (Var "y")-      evalExpr' expr `shouldBe` App (Var "g") (Var "y")--    it "reduces inner redexes" $ do-      let expr = Abs "x" (App (Abs "y" (Var "y")) (Var "x"))-      evalExpr' expr `shouldBe` Abs "x" (Var "x")--    it "reduces with name captures" $ do-      let expr = App (Abs "f" (Abs "x" (App (Var "f") (Var "x"))))-                     (Abs "f" (Var "x"))-      evalExpr' expr `shouldBe` Abs "z" (Var "x")--  describe "betaReduce" $ do-    let betaReduce' = betaReduce []-    -    it "reduces simple applications" $ do-      let e1 = Abs "x" (Var "x")-          e2 = Var "y"-      betaReduce' e1 e2 `shouldBe` Var "y"--    it "reduces nested abstractions" $ do-      let e1 = Abs "x" (Abs "y" (Var "x"))-          e2 = Var "z"-      betaReduce' e1 e2 `shouldBe` Abs "y" (Var "z")--    it "reduces inner applications" $ do-      let e1 = Abs "f" (App (Var "f") (Var "x"))-          e2 = Var "g"-      betaReduce' e1 e2 `shouldBe` App (Var "g") (Var "x")--    it "does not reduce unreducible expression" $ do-      let e1 = Var "x"-          e2 = Var "y"-      betaReduce' e1 e2 `shouldBe` App (Var "x") (Var "y")--    it "does not reduce irreducible chained applications" $ do-      let e1 = App (Var "x") (Var "y")-          e2 = Var "z"-      betaReduce' e1 e2 `shouldBe` App (App (Var "x") (Var "y")) (Var "z")--    it "does not sub shadowed bindings" $ do-      let e1 = Abs "x" (Abs "x" (Var "x"))-          e2 = Var "z"-      betaReduce' e1 e2 `shouldBe` Abs "x" (Var "x")--  describe "alphaConvert" $ do-    it "alpha converts simple expressions" $ do-      let freeVars = ["x"]-          expr = Abs "x" (Var "x")-          uniques = ["y"]-      alphaConvert uniques freeVars expr `shouldBe` Abs "y" (Var "y")-  -    it "avoids captures" $ do-      let freeVars = ["x"]-          expr = Abs "x" (Var "x")-          uniques = ["x", "y"]-      alphaConvert uniques freeVars expr `shouldBe` Abs "y" (Var "y")--  describe "etaConvert" $ do-    it "eta converts simple expressions" $ do-      let expr = Abs "x" $ App (Var "f") (Var "x")-      etaConvert expr `shouldBe` Var "f" --    it "eta converts nested applications" $ do-      let expr = Abs "y" $ App (App (Var "f") (Var "x")) (Var "y")-      etaConvert expr `shouldBe` App (Var "f") (Var "x")--      let expr' = Abs "x" $ Abs "y" (App (App (Var "f") (Var "x")) (Var "y"))-      etaConvert expr' `shouldBe` Var "f" --      let expr'' = Abs "x" (Abs "y" (App (Var "y") (Var "x")))-      etaConvert expr'' `shouldBe` expr''--      let expr''' = Abs "f" (Abs "x" (Var "x"))-      etaConvert expr''' `shouldBe` expr'''--    it "ignores non-eta convertable expressions" $ do-      let expr = Abs "x" $ Var "x"-      etaConvert expr `shouldBe` expr--  describe "freeVarsOf" $ do-    it "Returns simple vars" $-      freeVarsOf (Var "x") `shouldBe` ["x"]-  -    it "Does not return bound vars" $-      freeVarsOf (Abs "x" (Var "x")) `shouldBe` []--    it "Returns nested simple vars" $-      freeVarsOf (Abs "x" (Var "y")) `shouldBe` ["y"]--    it "Returns applied simple vars" $-      freeVarsOf (App (Var "x") (Var "y")) `shouldBe` ["x", "y"]
− test/Language/Lambda/Examples/BoolSpec.hs
@@ -1,108 +0,0 @@-module Language.Lambda.Examples.BoolSpec where--import Test.Hspec--import Language.Lambda.HspecUtils--spec :: Spec-spec = describe "Bool" $ do-  -- Bool is the definition of Booleans. We represent bools-  -- using Church Encodings:-  ---  -- true:  \t f. t-  -- false: \t f. f-  describe "and" $ do-    -- The function and takes two Bools and returns true-    -- iff both arguments are true-    -- -    -- and(true,  true)  = true-    -- and(false, true)  = false-    -- and(true,  false) = false-    -- and(false, false) = false-    ---    -- and is defined by-    -- and = \x y. x y x-    it "true and true = true" $-      "(\\x y. x y x) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"--    it "true and false = false" $-      "(\\x y. x y x) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. f"-      -    it "false and true = false" $-      "(\\x y. x y x) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. f"--    it "false and false = false" $-      "(\\x y. x y x) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"--    it "false and p = false" $-      "(\\x y. x y x) (\\t f. f) p" `shouldEvalTo` "\\t f. f"--    it "true and p = false" $-      "(\\x y. x y x) (\\t f. t) p" `shouldEvalTo` "p"--  describe "or" $ do-    -- or takes two Bools and returns true iff either argument is true-    -- -    -- or(true,  true)  = true-    -- or(true,  false) = true-    -- or(false, true)  = true-    -- or(false, false) = false-    ---    -- or is defined by-    -- or = \x y. x x y-    it "true or true = true" $-      "(\\x y. x x y) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"-    -    it "true or false = true" $-      "(\\x y. x x y) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. t"-      -    it "false or true = true" $-      "(\\x y. x x y) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. t"--    it "false or false = false" $-      "(\\x y. x x y) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"--    it "true or p = true" $-      "(\\x y. x x y) (\\t f. t) p" `shouldEvalTo` "\\t f. t"--    it "false or p = p" $-      "(\\x y. x x y) (\\t f. f) p" `shouldEvalTo` "p"-      --  describe "not" $ do-    -- not takes a Bool and returns its opposite value-    ---    -- not(true)  = false-    -- not(false) = true-    ---    -- not is defined by-    -- not = \x. x (\t f. f) (\t f. t)-    it "not true = false" $-      "(\\x. x (\\t f. f) (\\t f. t)) \\t f. t" `shouldEvalTo` "\\t f. f"--    it "not false = true" $-      "(\\x. x (\\t f. f) (\\t f. t)) \\t f. f" `shouldEvalTo` "\\t f. t"-      -  describe "if" $ do-    -- if takes a Bool and two values. If returns the first value-    -- if the Bool is true, and the second otherwise. In other words,-    -- if p x y = if p then x else y-    ---    -- if(true,  x, y) = x-    -- if(false, x, y) = y-    -- -    -- if is defined by-    -- if = \p x y. p x y-    it "if true 0 1 = 0" $-      "(\\p x y. p x y) (\\t f. t) (\\f x. x) (\\f x. f x)"-        `shouldEvalTo` "\\f x. x"--    it "if false 0 1 = 1" $-      "(\\p x y. p x y) (\\t f. f) (\\f x. x) (\\f x. f x)"-        `shouldEvalTo` "\\f x. f x"--    it "it true p q = p" $-      "(\\p x y. p x y) (\\t f. t) p q" `shouldEvalTo` "p"--    it "it false p q = q" $-      "(\\p x y. p x y) (\\t f. f) p q" `shouldEvalTo` "q"
− test/Language/Lambda/Examples/NatSpec.hs
@@ -1,102 +0,0 @@-module Language.Lambda.Examples.NatSpec where--import Test.Hspec--import Language.Lambda.HspecUtils--spec :: Spec-spec = describe "Nat" $ do-  -- Nat is the definition of natural numbers. More precisely, Nat-  -- is the set of nonnegative integers.  We represent nats using-  -- Church Encodings:-  ---  -- 0: \f x. x-  -- 1: \f x. f x-  -- 2: \f x. f (f x)-  -- ...and so on--  describe "successor" $ do-    -- successor is a function that adds 1-    -- succ(0) = 1-    -- succ(1) = 2-    -- ... and so forth-    ---    -- successor is defined by-    -- succ = \n f x. f (n f x)-    it "succ 0 = 1" $-      "(\\n f x. f (n f x)) (\\f x. x)" `shouldEvalTo` "\\f x. f x"--    it "succ 1 = 2" $-      "(\\n f x. f (n f x)) (\\f x. f x)" `shouldEvalTo` "\\f x. f (f x)"--  describe "add" $ do-    -- add(m, n) = m + n-    ---    -- It is defined by applying successor m times on n:-    -- add = \m n f x. m f (n f x)-    it "add 0 2 = 2" $-      "(\\m n f x. m f (n f x)) (\\f x. x) (\\f x. f (f x))"-        `shouldEvalTo` "\\f x. f (f x)"--    it "add 3 2 = 5" $-      "(\\m n f x. m f (n f x)) (\\f x. f (f (f x))) (\\f x. f (f x))"-        `shouldEvalTo` "\\f x. f (f (f (f (f x))))"--    -- Here, we use `\f x. n f x` instead of `n`. This is because-    -- I haven't implemented eta conversion-    it "add 0 n = n" $-      "(\\m n f x. m f (n f x)) (\\f x. x) n"-        `shouldEvalTo` "\\f x. n f x"--  describe "multiply" $ do-    -- multiply(m, n) = m * n-    ---    -- multiply is defined by applying add m times-    -- multiply = \m n f x. m (n f x) x)-    ---    -- Using eta conversion, we can omit the parameter x-    -- multiply = \m n f. m (n f)-    it "multiply 0 2 = 0" $-      "(\\m n f. m (n f)) (\\f x. x) (\\f x. f (f x))"-        `shouldEvalTo` "\\f x. x"--    it "multiply 2 3 = 6" $-      "(\\m n f. m (n f)) (\\f x. f (f x)) (\\f x. f (f (f x)))"-        `shouldEvalTo` "\\f x. f (f (f (f (f (f x)))))"--    it "multiply 0 n = 0" $-      "(\\m n f. m (n f)) (\\f x. x) n"-        `shouldEvalTo` "\\f x. x"--    it "multiply 1 n = n" $-      "(\\m n f. m (n f)) (\\f x. f x) n"-        `shouldEvalTo` "\\f x. n f x"--  describe "power" $ do-    -- The function power raises m to the power of n.-    -- power(m, n) = m^n-    ---    -- power is defined by applying multiply n times-    -- power = \m n f x. (n m) f x-    ---    -- Using eta conversion again, we can omit the parameter f-    -- power = \m n = n m--    -- NOTE: Here we use the first form to get more predictable-    -- variable names. Otherwise, alpha conversion will choose a random-    -- unique variable.-    it "power 0 1 = 0" $-      "(\\m n f x. (n m) f x) (\\f x. x) (\\f x. f x)"-        `shouldEvalTo` "\\f x. x"--    it "power 2 3 = 8" $-      "(\\m n f x. (n m) f x) (\\f x. f (f x)) (\\f x. f (f (f x)))"-        `shouldEvalTo` "\\f x. f (f (f (f (f (f (f (f x)))))))"--    it "power n 0 = 1" $-      "(\\m n f x. (n m) f x) n (\\f x. x)"-        `shouldEvalTo` "\\f x. f x"--    it "power n 1 = n" $-      "(\\m n f x. (n m) f x) n (\\f x. f x)"-        `shouldEvalTo` "\\f x. n f x"
− test/Language/Lambda/Examples/PairSpec.hs
@@ -1,38 +0,0 @@-module Language.Lambda.Examples.PairSpec where--import Language.Lambda.HspecUtils--import Test.Hspec--spec :: Spec-spec = describe "Pair" $ do-  -- Pair is the definition of tuples with two items. Pairs,-  -- again are represented using Church Encodings:-  ---  -- pair = \x y f. f x y-  describe "first" $ do-    -- The function first returns the first item in a pair-    -- first(x, y) = x-    ---    -- first is defined by-    -- first = \p. p (\t f. t)-    it "first 0 1 = 0" $-      "(\\p. p (\\t f. t)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"-        `shouldEvalTo` "\\f x. x"--    it "first x y = x" $-      "(\\p. p (\\t f. t)) ((\\x y f. f x y) x y)" `shouldEvalTo` "x"--  describe "second" $ do-    -- The function second returns the second item in a pair-    -- second(x, y) = y-    ---    -- second is defined by-    -- second = \p. p (\t f. f)-    it "second 0 1 = 1" $-      "(\\p. p (\\t f. f)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"-        `shouldEvalTo` "\\f x. f x"--    it "second x y = y" $ do-      "(\\p. p (\\t f. f)) ((\\x y f. f x y) x y)" `shouldEvalTo` "y"-      "(\\p. p (\\x y z. x)) ((\\x y z f. f x y z) x y z)" `shouldEvalTo` "x"
− test/Language/Lambda/ExpressionSpec.hs
@@ -1,39 +0,0 @@-module Language.Lambda.ExpressionSpec where--import Test.Hspec--import Language.Lambda.Expression-import Language.Lambda.Util.PrettyPrint--spec :: Spec-spec = describe "prettyPrint" $ do-    it "prints simple variables" $ -      prettyPrint (Var "x") `shouldBe` "x"--    it "prints simple abstractions" $-      prettyPrint (Abs "x" (Var "x")) `shouldBe` "λx. x"--    it "prints simple applications" $-      prettyPrint (App (Var "a") (Var "b"))-        `shouldBe` "a b"--    it "prints nested abstractions" $-      prettyPrint (Abs "f" (Abs "x" (Var "x")))-        `shouldBe` "λf x. x"--    it "prints nested applications" $-      prettyPrint (App (App (Var "f") (Var "x")) (Var "y"))-        `shouldBe` "f x y"--    it "prints parenthesized applications" $ do-      prettyPrint (App (Var "f") (App (Var "x") (Var "y")))-        `shouldBe` "f (x y)"--      prettyPrint (App (Abs "x" (Var "x")) (Var "y"))-        `shouldBe` "(λx. x) y"--      prettyPrint (App (Var "x") (Abs "f" (Var "f")))-        `shouldBe` "x (λf. f)"-      -      prettyPrint (App (Abs "f" (Var "f")) (Abs "g" (Var "g")))-        `shouldBe` "(λf. f) (λg. g)"
− test/Language/Lambda/HspecUtils.hs
@@ -1,11 +0,0 @@-module Language.Lambda.HspecUtils where--import Test.Hspec--import Language.Lambda--shouldEvalTo :: String -> String -> Expectation-shouldEvalTo s1 = shouldBe (eval s1) . eval--eval :: String -> Either ParseError (LambdaExpr String)-eval = evalString
− test/Language/Lambda/ParserSpec.hs
@@ -1,53 +0,0 @@-module Language.Lambda.ParserSpec (spec) where--import Data.Either--import Test.Hspec--import Language.Lambda.Expression-import Language.Lambda.Parser--spec :: Spec-spec = describe "parseExpr" $ do-  it "parses simple variables" $-    parseExpr "x" `shouldBe` Right (Var "x")--  it "parses parenthesized variables" $-    parseExpr "(x)" `shouldBe` Right (Var "x")--  it "parses simple abstractions" $-    parseExpr "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))--  it "parses nested abstractions" $-    parseExpr "\\f a. a" `shouldBe` Right (Abs "f" (Abs "a" (Var "a")))--  it "parses simple applications" $-    parseExpr "f x" `shouldBe` Right (App (Var "f") (Var "x"))--  it "parses chained applications" $-    parseExpr "f x y" `shouldBe` Right (App (App (Var "f") (Var "x")) (Var "y"))--  it "parses complex expressions" $ do-    let exprs = [-          "\\f x. f x",-          "(\\p x y. y) (\\p x y. x)",-          "f (\\x. x)",-          "(\\x . f x) g y",-          "(\\f . (\\ x y. f x y) f x y) w x y"-          ]-    -    mapM_ (flip shouldSatisfy isRight . parseExpr) exprs--  it "does not parse trailing errors" $-    parseExpr "x +" `shouldSatisfy` isLeft--  it "ignores whitespace" $ do-    let exprs = [-          " x ",-          " \\ x . x ",-          " ( x ) "-          ]-    -    mapM_ (flip shouldSatisfy isRight . parseExpr) exprs-            -
+ test/Language/Lambda/SystemF/ExpressionSpec.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE OverloadedStrings, NoImplicitPrelude #-}+module Language.Lambda.SystemF.ExpressionSpec where++import RIO+import Test.Hspec++import Language.Lambda.SystemF.Expression++spec :: Spec+spec = describe "prettyPrint" $ do+  let prettyPrint' :: SystemFExpr Text Text -> Text+      prettyPrint' = prettyPrint++      prettyPrintTy :: Ty Text -> Text+      prettyPrintTy = prettyPrint+  +  it "prints simple variables" $+    prettyPrint' (Var "x") `shouldBe` "x"++  it "prints simple applications" $+    prettyPrint' (App (Var "a") (Var "b")) `shouldBe` "a b"++  it "prints simple abstractions" $ +    prettyPrint' (Abs "x" (TyVar "T") (Var "x")) `shouldBe` "λ x:T. x"++  it "prints simple type abstractions" $+    prettyPrint' (TyAbs "X" (Var "x")) `shouldBe` "Λ X. x"++  it "prints simple type applications" $ +    prettyPrint' (TyApp (Var "t") (TyVar "T")) `shouldBe` "t [T]"++  it "prints nested abstractions" $+    prettyPrint' (Abs "f" (TyVar "F") (Abs "x" (TyVar "X") (Var "x")))+      `shouldBe` "λ f:F x:X. x"++  it "prints abstractions with composite types" $ do+    prettyPrint' (Abs "f" (TyArrow (TyVar "X") (TyVar "Y")) (Var "f"))+      `shouldBe ` "λ f:(X->Y). f"++    prettyPrint' (Abs "f" (TyArrow (TyVar "X") (TyArrow (TyVar "Y") (TyVar "Z"))) (Var "f"))+      `shouldBe ` "λ f:(X->Y->Z). f"++  it "prints nested type abstractions" $+    prettyPrint' (TyAbs "A" (TyAbs "B" (Var "x")))+      `shouldBe` "Λ A B. x"++  it "prints nested applications" $+    prettyPrint' (App (App (Var "f") (Var "x")) (Var "y"))+      `shouldBe` "f x y"++  it "prints parenthesized applications" $ do+    prettyPrint' (App (Var "w") (App (Var "x") (Var "y")))+      `shouldBe` "w (x y)"++    prettyPrint' (App (Abs "t" (TyVar "T") (Var "t")) (Var "x"))+      `shouldBe` "(λ t:T. t) x"++    prettyPrint' (App (Abs "f" (TyVar "F") (Var "f")) (Abs "g" (TyVar "G") (Var "g")))+      `shouldBe` "(λ f:F. f) (λ g:G. g)"++  it "prints simple types" $+    prettyPrintTy (TyVar "X") `shouldBe` "X"++  it "print simple arrow types" $+    prettyPrintTy (TyArrow (TyVar "A") (TyVar "B")) `shouldBe` "A -> B"++  it "prints simple forall types" $+    prettyPrintTy (TyForAll "X" (TyVar "X")) `shouldBe` "forall X. X"++  it "prints chained arrow types" $+    prettyPrintTy (TyArrow (TyVar "X") (TyArrow (TyVar "Y") (TyVar "Z")))+      `shouldBe` "X -> Y -> Z"++  it "prints nested arrow types" $+    prettyPrintTy (TyArrow (TyArrow (TyVar "T") (TyVar "U")) (TyVar "V"))+      `shouldBe` "(T -> U) -> V"++  it "prints complex forall types" $+    prettyPrintTy (TyForAll "A" (TyArrow (TyVar "A") (TyVar "A")))+      `shouldBe` "forall A. A -> A"++  it "prints nested forall types" $+    prettyPrintTy (TyForAll "W" +                  (TyForAll "X" +                    (TyArrow (TyVar "W") (TyArrow (TyVar "X") (TyVar "Y")))))+      `shouldBe` "forall W. forall X. W -> X -> Y"+
+ test/Language/Lambda/SystemF/ParserSpec.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.SystemF.ParserSpec (spec) where++import Data.Either++import RIO+import Test.Hspec++import Language.Lambda.SystemF.Expression+import Language.Lambda.SystemF.Parser++spec :: Spec+spec = do+  describe "parseExpr" $ do+    it "parses simple variables" $+      parseExpr "x" `shouldBe` Right (Var "x")++    it "parses parenthesized variables" $+      parseExpr "(x)" `shouldBe` Right (Var "x")++    it "parses simple abstractions" $+      parseExpr "\\x:T. x" `shouldBe` Right (Abs "x" (TyVar "T") (Var "x"))++    it "parses simple type abstractions" $+      parseExpr "\\X. x" `shouldBe` Right (TyAbs "X" (Var "x"))++    it "parses simple type applications" $ +      parseExpr "x [T]" `shouldBe` Right (TyApp (Var "x") (TyVar "T"))++    it "parses nested abstractions" $+      parseExpr "\\a:A b:B. b" +        `shouldBe` Right (Abs "a" (TyVar "A") (Abs "b" (TyVar "B") (Var "b")))++    it "parses abstractions with arrow types" $+      parseExpr "\\f:(T->U). f"+        `shouldBe` Right (Abs "f" (TyArrow (TyVar "T") (TyVar "U")) (Var "f"))++    it "parses simple applications" $+      parseExpr "f x" `shouldBe` Right (App (Var "f") (Var "x"))++    it "parses chained applications" $+      parseExpr "a b c" `shouldBe` Right (App (App (Var "a") (Var "b")) (Var "c"))++    it "parses complex expressions"  $ do+      let exprs = [+            "\\f:(A->B) x:B. f x",+            "(\\p:(X->Y->Z) x:X y:Y. y) (\\p:(A->B->C) x:B y:C. x)",+            "f (\\x:T. x)",+            "(\\ x:X . f x) g y",+            "(\\f:(X->Y) . (\\ x:X y:Y. f x y) f x y) w x y",+            "(\\x:T. x) [U]"+            ]++      mapM_ (flip shouldSatisfy isRight . parseExpr) exprs++    it "does not parse trailing errors" $+      parseExpr "x +" `shouldSatisfy` isLeft++    it "ignores whitespace" $ do+      let exprs = [+            " x ",+            " \\ x : X. x ",+            " ( x ) "+            ]++      mapM_ (flip shouldSatisfy isRight . parseExpr) exprs+  +  describe "parseType" $ do+    it "parses simple variables" $+      parseType "X" `shouldBe` Right (TyVar "X")++    it "parses parenthesized variables" $+      parseType "(T)" `shouldBe` Right (TyVar "T")++    it "parses simple arrow types" $+      parseType "A -> B" `shouldBe` Right (TyArrow (TyVar "A") (TyVar "B")) ++    it "parses parenthesized arrow types" $+      parseType "((X)->(Y))" `shouldBe` Right (TyArrow (TyVar "X") (TyVar "Y"))++    it "parses nested arrow types" $ do+      parseType "T -> U -> V" +        `shouldBe` Right (TyArrow (TyVar "T") (TyArrow (TyVar "U") (TyVar "V")))++      parseType "(W -> V) -> U"+        `shouldBe` Right (TyArrow (TyArrow (TyVar "W") (TyVar "V")) (TyVar "U"))
+ test/Language/Lambda/SystemF/TypeCheckSpec.hs view
@@ -0,0 +1,71 @@+module Language.Lambda.SystemF.TypeCheckSpec (spec) where++import Data.Either+import Data.Map+import Prettyprinter+import Test.Hspec++import Language.Lambda.Shared.Errors+import Language.Lambda.SystemF.Expression+import Language.Lambda.SystemF.State+import Language.Lambda.SystemF.TypeCheck++tc uniqs ctx expr = execTypecheck (typecheck expr) (TypecheckState (fromList ctx) uniqs)++spec :: Spec+spec = describe "typecheck" $ do+  it "typechecks simple variables in context" $+    tc [] [("x", TyVar "X")] (Var "x") `shouldBe` Right (TyVar "X")++  it "typechecks simple variables not in context" $ +    tc ["A"] [] (Var "x") `shouldBe` Right (TyVar "A")++  it "typechecks simple abstractions" $+    tc [] [] (Abs "x" (TyVar "A") (Var "x")) +      `shouldBe` Right (TyArrow (TyVar "A") (TyVar "A"))++  it "typechecks simple applications" $ do+    let ctx = [+          ("f", TyArrow (TyVar "T") (TyVar "U")),+          ("a", TyVar "T")+          ]++    tc [] ctx (App (Var "f") (Var "a")) `shouldBe` Right (TyVar "U")++  it "apply variable to variable fails" $ do+    let ctx = [+          ("a", TyVar "A"),+          ("b", TyVar "B")+          ]++    tc ["C"] ctx (App (Var "a") (Var "b")) +      `shouldSatisfy` isLeft++  it "apply arrow to variable of wrong type fails" $ do+    let ctx = [+          ("f", TyArrow (TyVar "F") (TyVar "G")),+          ("b", TyVar "B")+          ]++    tc [] ctx (App (Var "f") (Var "b")) `shouldSatisfy` isLeft++  it "typechecks simple type abstractions" $+    tc ["A"] [] (TyAbs "X" (Var "x")) `shouldBe` Right (TyForAll "X" (TyVar "A"))++  it "typechecks type abstractions with simple abstraction" $+    tc [] [] (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) +      `shouldBe` Right (TyForAll "X" (TyArrow (TyVar "X") (TyVar "X")))++  it "typechecks type abstractions with application" $+    tc [] [("y", TyVar "Y")] +      (App (TyApp (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) (TyVar "Y")) +           (Var "y"))+      `shouldBe` Right (TyVar "Y")++  it "typechecks simple type applications" $+    tc [] [("x", TyVar "A")] (TyApp (TyAbs "X" (Var "x")) (TyVar "X"))+      `shouldBe` Right (TyVar "A")++  it "typechecks type applications with simple abstraction" $+    tc [] [] (TyApp (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) (TyVar "Y"))+      `shouldBe` Right (TyArrow (TyVar "Y") (TyVar "Y"))
+ test/Language/Lambda/SystemFSpec.hs view
@@ -0,0 +1,9 @@+module Language.Lambda.SystemFSpec where++import Test.Hspec++import Language.Lambda.SystemF++spec :: Spec+spec = describe "evalString" $ +  return ()
+ test/Language/Lambda/Untyped/EvalSpec.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.Untyped.EvalSpec where++import Data.Map (fromList)+import RIO+import Test.Hspec++import Language.Lambda.Shared.Errors+import Language.Lambda.Untyped+import Language.Lambda.Untyped.Eval+import Language.Lambda.Untyped.State++spec :: Spec+spec = do+  describe "evalExpr" $ do+    let evalExpr' expr = execEval (evalExpr expr) (mkEvalState defaultUniques)++    it "beta reduces" $ do+      let expr = App (Abs "x" (Var "x")) (Var "z")+      evalExpr' expr `shouldBe` Right (Var "z")++    it "reduces multiple applications" $ do+      let expr = App (App (Abs "f" (Abs "x" (App (Var "f") (Var "x")))) (Var "g")) (Var "y")+      evalExpr' expr `shouldBe` Right (App (Var "g") (Var "y"))++    it "reduces inner redexes" $ do+      let expr = Abs "x" (App (Abs "y" (Var "y")) (Var "x"))+      evalExpr' expr `shouldBe` Right (Abs "x" (Var "x"))++    it "reduces with name captures" $ do+      let expr = App (Abs "f" (Abs "x" (App (Var "f") (Var "x"))))+                     (Abs "f" (Var "x"))+      evalExpr' expr `shouldBe` Right (Abs "z" (Var "x"))++    it "reduces let bodies" $ do+      let expr = Let "x" $ App (Abs "y" (Var "y")) (Var "z")+      evalExpr' expr `shouldBe` Right (Let "x" (Var "z"))++    it "let expressions update state" $ do+      let res = flip unsafeExecEval (mkEvalState defaultUniques) $ do+            _ <- evalExpr $ Let "w" (Var "x")+            evalExpr $ Var "w"++      res `shouldBe` Var "x"++    it "nested let expressions fail" $ do+      let res = flip unsafeExecEval (mkEvalState defaultUniques) $ do+            evalExpr $ Let "x" (Let "y" (Var "z"))+      evaluate res `shouldThrow` isLetError++  describe "subGlobals" $ do+    let globals' :: Map String (LambdaExpr String)+        globals' = fromList [("w", Var "x")] +        subGlobals' = subGlobals globals'+    +    it "subs simple variables" $+      subGlobals' (Var "w") `shouldBe` Var "x"++    it "does not sub shadowed bindings" $ do+      let expr = Abs "w" (Var "w")+      subGlobals' expr `shouldBe` expr++    xit "does not capture globals" $ do+      let expr = Abs "x" (Var "w")+      subGlobals' expr `shouldBe` Abs "a" (Var "x")++  describe "betaReduce" $ do+    let betaReduce' :: LambdaExpr Text -> LambdaExpr Text -> LambdaExpr Text+        betaReduce' e1 e2 = unsafeExecEval (betaReduce e1 e2) (mkEvalState [])+    +    it "reduces simple applications" $ do+      let e1 = Abs "x" (Var "x")+          e2 = Var "y"+      betaReduce' e1 e2 `shouldBe` Var "y"++    it "reduces nested abstractions" $ do+      let e1 = Abs "x" (Abs "y" (Var "x"))+          e2 = Var "z"+      betaReduce' e1 e2 `shouldBe` Abs "y" (Var "z")++    it "reduces inner applications" $ do+      let e1 = Abs "f" (App (Var "f") (Var "x"))+          e2 = Var "g"+      betaReduce' e1 e2 `shouldBe` App (Var "g") (Var "x")++    it "does not reduce unreducible expression" $ do+      let e1 = Var "x"+          e2 = Var "y"+      betaReduce' e1 e2 `shouldBe` App (Var "x") (Var "y")++    it "does not reduce irreducible chained applications" $ do+      let e1 = App (Var "x") (Var "y")+          e2 = Var "z"+      betaReduce' e1 e2 `shouldBe` App (App (Var "x") (Var "y")) (Var "z")++    it "does not sub shadowed bindings" $ do+      let e1 = Abs "x" (Abs "x" (Var "x"))+          e2 = Var "z"+      betaReduce' e1 e2 `shouldBe` Abs "x" (Var "x")++  describe "alphaConvert" $ do+    let alphaConvert' :: [Text] -> [Text] -> LambdaExpr Text -> LambdaExpr Text+        alphaConvert' uniques' fvs expr+          = unsafeExecEval (alphaConvert fvs expr) (mkEvalState uniques')+    +    it "alpha converts simple expressions" $ do+      let freeVars = ["x"] :: [Text]+          expr = Abs "x" (Var "x")+          uniques' = ["y"]+      alphaConvert' uniques' freeVars expr `shouldBe` Abs "y" (Var "y")+  +    it "avoids captures" $ do+      let freeVars = ["x"]+          expr = Abs "x" (Var "x")+          uniques' = ["x", "y"]+      alphaConvert' uniques' freeVars expr `shouldBe` Abs "y" (Var "y")++  describe "etaConvert" $ do+    it "eta converts simple expressions" $ do+      let expr :: LambdaExpr Text+          expr = Abs "x" $ App (Var "f") (Var "x") :: LambdaExpr Text+      etaConvert expr `shouldBe` Var "f" ++    it "eta converts nested applications" $ do+      let expr :: LambdaExpr Text+          expr = Abs "y" $ App (App (Var "f") (Var "x")) (Var "y")+      etaConvert expr `shouldBe` App (Var "f") (Var "x")++      let expr' :: LambdaExpr Text+          expr' = Abs "x" $ Abs "y" (App (App (Var "f") (Var "x")) (Var "y"))+      etaConvert expr' `shouldBe` Var "f" ++      let expr'' :: LambdaExpr Text+          expr'' = Abs "x" (Abs "y" (App (Var "y") (Var "x")))+      etaConvert expr'' `shouldBe` expr''++      let expr''' :: LambdaExpr Text+          expr''' = Abs "f" (Abs "x" (Var "x"))+      etaConvert expr''' `shouldBe` expr'''++    it "ignores non-eta convertable expressions" $ do+      let expr :: LambdaExpr Text+          expr = Abs "x" $ Var "x"+      etaConvert expr `shouldBe` expr++  describe "freeVarsOf" $ do+    let freeVarsOf' :: LambdaExpr Text -> [Text]+        freeVarsOf' = freeVarsOf+    +    it "Returns simple vars" $+      freeVarsOf' (Var "x") `shouldBe` ["x"]+  +    it "Does not return bound vars" $+      freeVarsOf' (Abs "x" (Var "x")) `shouldBe` []++    it "Returns nested simple vars" $+      freeVarsOf' (Abs "x" (Var "y")) `shouldBe` ["y"]++    it "Returns applied simple vars" $+      freeVarsOf' (App (Var "x") (Var "y")) `shouldBe` ["x", "y"]
+ test/Language/Lambda/Untyped/Examples/BoolSpec.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.Untyped.Examples.BoolSpec where++import RIO+import Test.Hspec++import Language.Lambda.Untyped.HspecUtils++spec :: Spec+spec = describe "Bool" $ do+  -- Bool is the definition of Booleans. We represent bools+  -- using Church Encodings:+  --+  -- true:  \t f. t+  -- false: \t f. f+  describe "and" $ do+    -- The function and takes two Bools and returns true+    -- iff both arguments are true+    -- +    -- and(true,  true)  = true+    -- and(false, true)  = false+    -- and(true,  false) = false+    -- and(false, false) = false+    --+    -- and is defined by+    -- and = \x y. x y x+    it "true and true = true" $+      "(\\x y. x y x) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"++    it "true and false = false" $+      "(\\x y. x y x) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. f"+      +    it "false and true = false" $+      "(\\x y. x y x) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. f"++    it "false and false = false" $+      "(\\x y. x y x) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"++    it "false and p = false" $+      "(\\x y. x y x) (\\t f. f) p" `shouldEvalTo` "\\t f. f"++    it "true and p = false" $+      "(\\x y. x y x) (\\t f. t) p" `shouldEvalTo` "p"++  describe "or" $ do+    -- or takes two Bools and returns true iff either argument is true+    -- +    -- or(true,  true)  = true+    -- or(true,  false) = true+    -- or(false, true)  = true+    -- or(false, false) = false+    --+    -- or is defined by+    -- or = \x y. x x y+    it "true or true = true" $+      "(\\x y. x x y) (\\t f. t) (\\t f. t)" `shouldEvalTo` "\\t f. t"+    +    it "true or false = true" $+      "(\\x y. x x y) (\\t f. t) (\\t f. f)" `shouldEvalTo` "\\t f. t"+      +    it "false or true = true" $+      "(\\x y. x x y) (\\t f. f) (\\t f. t)" `shouldEvalTo` "\\t f. t"++    it "false or false = false" $+      "(\\x y. x x y) (\\t f. f) (\\t f. f)" `shouldEvalTo` "\\t f. f"++    it "true or p = true" $+      "(\\x y. x x y) (\\t f. t) p" `shouldEvalTo` "\\t f. t"++    it "false or p = p" $+      "(\\x y. x x y) (\\t f. f) p" `shouldEvalTo` "p"+      ++  describe "not" $ do+    -- not takes a Bool and returns its opposite value+    --+    -- not(true)  = false+    -- not(false) = true+    --+    -- not is defined by+    -- not = \x. x (\t f. f) (\t f. t)+    it "not true = false" $+      "(\\x. x (\\t f. f) (\\t f. t)) \\t f. t" `shouldEvalTo` "\\t f. f"++    it "not false = true" $+      "(\\x. x (\\t f. f) (\\t f. t)) \\t f. f" `shouldEvalTo` "\\t f. t"+      +  describe "if" $ do+    -- if takes a Bool and two values. If returns the first value+    -- if the Bool is true, and the second otherwise. In other words,+    -- if p x y = if p then x else y+    --+    -- if(true,  x, y) = x+    -- if(false, x, y) = y+    -- +    -- if is defined by+    -- if = \p x y. p x y+    it "if true 0 1 = 0" $+      "(\\p x y. p x y) (\\t f. t) (\\f x. x) (\\f x. f x)"+        `shouldEvalTo` "\\f x. x"++    it "if false 0 1 = 1" $+      "(\\p x y. p x y) (\\t f. f) (\\f x. x) (\\f x. f x)"+        `shouldEvalTo` "\\f x. f x"++    it "it true p q = p" $+      "(\\p x y. p x y) (\\t f. t) p q" `shouldEvalTo` "p"++    it "it false p q = q" $+      "(\\p x y. p x y) (\\t f. f) p q" `shouldEvalTo` "q"
+ test/Language/Lambda/Untyped/Examples/NatSpec.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.Untyped.Examples.NatSpec where++import RIO+import Test.Hspec++import Language.Lambda.Untyped.HspecUtils++spec :: Spec+spec = describe "Nat" $ do+  -- Nat is the definition of natural numbers. More precisely, Nat+  -- is the set of nonnegative integers.  We represent nats using+  -- Church Encodings:+  --+  -- 0: \f x. x+  -- 1: \f x. f x+  -- 2: \f x. f (f x)+  -- ...and so on++  describe "successor" $ do+    -- successor is a function that adds 1+    -- succ(0) = 1+    -- succ(1) = 2+    -- ... and so forth+    --+    -- successor is defined by+    -- succ = \n f x. f (n f x)+    it "succ 0 = 1" $+      "(\\n f x. f (n f x)) (\\f x. x)" `shouldEvalTo` "\\f x. f x"++    it "succ 1 = 2" $+      "(\\n f x. f (n f x)) (\\f x. f x)" `shouldEvalTo` "\\f x. f (f x)"++  describe "add" $ do+    -- add(m, n) = m + n+    --+    -- It is defined by applying successor m times on n:+    -- add = \m n f x. m f (n f x)+    it "add 0 2 = 2" $+      "(\\m n f x. m f (n f x)) (\\f x. x) (\\f x. f (f x))"+        `shouldEvalTo` "\\f x. f (f x)"++    it "add 3 2 = 5" $+      "(\\m n f x. m f (n f x)) (\\f x. f (f (f x))) (\\f x. f (f x))"+        `shouldEvalTo` "\\f x. f (f (f (f (f x))))"++    -- Here, we use `\f x. n f x` instead of `n`. This is because+    -- I haven't implemented eta conversion+    it "add 0 n = n" $+      "(\\m n f x. m f (n f x)) (\\f x. x) n"+        `shouldEvalTo` "\\f x. n f x"++  describe "multiply" $ do+    -- multiply(m, n) = m * n+    --+    -- multiply is defined by applying add m times+    -- multiply = \m n f x. m (n f x) x)+    --+    -- Using eta conversion, we can omit the parameter x+    -- multiply = \m n f. m (n f)+    it "multiply 0 2 = 0" $+      "(\\m n f. m (n f)) (\\f x. x) (\\f x. f (f x))"+        `shouldEvalTo` "\\f x. x"++    it "multiply 2 3 = 6" $+      "(\\m n f. m (n f)) (\\f x. f (f x)) (\\f x. f (f (f x)))"+        `shouldEvalTo` "\\f x. f (f (f (f (f (f x)))))"++    it "multiply 0 n = 0" $+      "(\\m n f. m (n f)) (\\f x. x) n"+        `shouldEvalTo` "\\f x. x"++    it "multiply 1 n = n" $+      "(\\m n f. m (n f)) (\\f x. f x) n"+        `shouldEvalTo` "\\f x. n f x"++  describe "power" $ do+    -- The function power raises m to the power of n.+    -- power(m, n) = m^n+    --+    -- power is defined by applying multiply n times+    -- power = \m n f x. (n m) f x+    --+    -- Using eta conversion again, we can omit the parameter f+    -- power = \m n = n m++    -- NOTE: Here we use the first form to get more predictable+    -- variable names. Otherwise, alpha conversion will choose a random+    -- unique variable.+    it "power 0 1 = 0" $+      "(\\m n f x. (n m) f x) (\\f x. x) (\\f x. f x)"+        `shouldEvalTo` "\\f x. x"++    it "power 2 3 = 8" $+      "(\\m n f x. (n m) f x) (\\f x. f (f x)) (\\f x. f (f (f x)))"+        `shouldEvalTo` "\\f x. f (f (f (f (f (f (f (f x)))))))"++    it "power n 0 = 1" $+      "(\\m n f x. (n m) f x) n (\\f x. x)"+        `shouldEvalTo` "\\f x. f x"++    it "power n 1 = n" $+      "(\\m n f x. (n m) f x) n (\\f x. f x)"+        `shouldEvalTo` "\\f x. n f x"
+ test/Language/Lambda/Untyped/Examples/PairSpec.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.Untyped.Examples.PairSpec where++import Language.Lambda.Untyped.HspecUtils++import RIO+import Test.Hspec++spec :: Spec+spec = describe "Pair" $ do+  -- Pair is the definition of tuples with two items. Pairs,+  -- again are represented using Church Encodings:+  --+  -- pair = \x y f. f x y+  describe "first" $ do+    -- The function first returns the first item in a pair+    -- first(x, y) = x+    --+    -- first is defined by+    -- first = \p. p (\t f. t)+    it "first 0 1 = 0" $+      "(\\p. p (\\t f. t)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"+        `shouldEvalTo` "\\f x. x"++    it "first x y = x" $+      "(\\p. p (\\t f. t)) ((\\x y f. f x y) x y)" `shouldEvalTo` "x"++  describe "second" $ do+    -- The function second returns the second item in a pair+    -- second(x, y) = y+    --+    -- second is defined by+    -- second = \p. p (\t f. f)+    it "second 0 1 = 1" $+      "(\\p. p (\\t f. f)) ((\\x y f. f x y) (\\f x. x) (\\f x. f x))"+        `shouldEvalTo` "\\f x. f x"++    it "second x y = y" $ do+      "(\\p. p (\\t f. f)) ((\\x y f. f x y) x y)" `shouldEvalTo` "y"+      "(\\p. p (\\x y z. x)) ((\\x y z f. f x y z) x y z)" `shouldEvalTo` "x"
+ test/Language/Lambda/Untyped/ExpressionSpec.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.Untyped.ExpressionSpec where++import Language.Lambda.Untyped.Expression++import RIO+import Test.Hspec++spec :: Spec+spec = describe "prettyPrint" $ do+    let prettyPrint' :: LambdaExpr Text -> Text+        prettyPrint' = prettyPrint+  +    it "prints simple variables" $+      prettyPrint' (Var "x") `shouldBe` "x"++    it "prints simple abstractions" $+      prettyPrint' (Abs "x" (Var "x")) `shouldBe` "λx. x"++    it "prints simple applications" $+      prettyPrint' (App (Var "a") (Var "b"))+        `shouldBe` "a b"++    it "prints simple let expressions" $+      prettyPrint' (Let "x" (Var "y")) `shouldBe` "let x = y"++    it "prints nested abstractions" $+      prettyPrint' (Abs "f" (Abs "x" (Abs "y" (Var "x"))))+        `shouldBe` "λf x y. x"++    it "prints nested applications" $+      prettyPrint' (App (App (Var "f") (Var "x")) (Var "y"))+        `shouldBe` "f x y"++    it "prints parenthesized applications" $ do+      prettyPrint' (App (Var "f") (App (Var "x") (Var "y")))+        `shouldBe` "f (x y)"++      prettyPrint' (App (Abs "x" (Var "x")) (Var "y"))+        `shouldBe` "(λx. x) y"++      prettyPrint' (App (Var "x") (Abs "f" (Var "f")))+        `shouldBe` "x (λf. f)"+      +      prettyPrint' (App (Abs "f" (Var "f")) (Abs "g" (Var "g")))+        `shouldBe` "(λf. f) (λg. g)"++    it "prints complex let expressions" $+      prettyPrint' (Let "x" (Abs "a" (Abs "b" (App (Var "a") (Var "b")))))+        `shouldBe` "let x = λa b. a b"
+ test/Language/Lambda/Untyped/HspecUtils.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE NoImplicitPrelude #-}+module Language.Lambda.Untyped.HspecUtils where++import RIO+import Test.Hspec++import Language.Lambda.Shared.Errors+import Language.Lambda.Untyped++shouldEvalTo :: Text -> Text -> Expectation+shouldEvalTo s1 = shouldBe (eval s1) . eval++eval :: Text -> Either LambdaException (LambdaExpr Text)+eval input = execEval (evalText input) (mkEvalState defaultUniques)
+ test/Language/Lambda/Untyped/ParserSpec.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.Untyped.ParserSpec (spec) where++import Language.Lambda.Untyped.Expression+import Language.Lambda.Untyped.Parser++import Data.Either+import Test.Hspec+import RIO++spec :: Spec+spec = describe "parseExpr" $ do+  it "parses simple variables" $+    parseExpr "x" `shouldBe` Right (Var "x")++  it "parses parenthesized variables" $+    parseExpr "(x)" `shouldBe` Right (Var "x")++  it "parses simple abstractions" $+    parseExpr "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))++  it "parses nested abstractions" $+    parseExpr "\\f a. a" `shouldBe` Right (Abs "f" (Abs "a" (Var "a")))++  it "parses simple applications" $+    parseExpr "f x" `shouldBe` Right (App (Var "f") (Var "x"))++  it "parses chained applications" $+    parseExpr "f x y" `shouldBe` Right (App (App (Var "f") (Var "x")) (Var "y"))++  it "parses simple let expressions" $+    parseExpr "let x = z" `shouldBe` Right (Let "x" (Var "z"))++  it "parses complex expressions" $ do+    let exprs = [+          "\\f x. f x",+          "(\\p x y. y) (\\p x y. x)",+          "f (\\x. x)",+          "(\\x . f x) g y",+          "(\\f . (\\ x y. f x y) f x y) w x y",+          "let x = \\f x. f x"+          ]+    +    mapM_ (flip shouldSatisfy isRight . parseExpr) exprs++  it "does not parse trailing errors" $+    parseExpr "x +" `shouldSatisfy` isLeft++  it "ignores whitespace" $ do+    let exprs = [+          " x ",+          " \\ x . x ",+          " ( x ) "+          ]+    +    mapM_ (flip shouldSatisfy isRight . parseExpr) exprs
+ test/Language/Lambda/UntypedSpec.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE NoImplicitPrelude, OverloadedStrings #-}+module Language.Lambda.UntypedSpec where++import RIO+import qualified RIO.Map as Map+import qualified RIO.Text as Text+import Test.Hspec++import Language.Lambda.Untyped+import Language.Lambda.Untyped.HspecUtils++spec :: Spec+spec = do+  describe "evalText" $ do+    it "evaluates simple text" $ do+      eval "x" `shouldBe` Right (Var "x")+      eval "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))+      eval "f y" `shouldBe` Right (App (Var "f") (Var "y"))++    it "reduces simple applications" $+      eval "(\\x .x) y" `shouldBe` Right (Var "y")++    it "reduces applications with nested redexes" $+      eval "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))++  describe "runEvalText" $ do+    let runEvalText' input = fst <$> runEvalText input Map.empty+    +    it "evaluates simple strings" $ do+      runEvalText' "x" `shouldBe` Right (Var "x")+      runEvalText' "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))+      runEvalText' "f y" `shouldBe` Right (App (Var "f") (Var "y"))++    it "reduces simple applications" $+      runEvalText' "(\\x .x) y" `shouldBe` Right (Var "y")++    it "reduces applications with nested redexes" $+      runEvalText' "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))++  describe "execEvalText" $ do+    let execEvalText' input = execEvalText input Map.empty+    +    it "evaluates simple texts" $ do+      execEvalText' "x" `shouldBe` Right (Var "x")+      execEvalText' "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))+      execEvalText' "f y" `shouldBe` Right (App (Var "f") (Var "y"))++    it "reduces simple applications" $+      execEvalText' "(\\x .x) y" `shouldBe` Right (Var "y")++    it "reduces applications with nested redexes" $+      execEvalText' "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))++  describe "unsafeExecEvalText" $ do+    let unsafeExecEvalText' input = unsafeExecEvalText input Map.empty+    +    it "evaluates simple texts" $ do+      unsafeExecEvalText' "x" `shouldBe` Var "x"+      unsafeExecEvalText' "\\x. x" `shouldBe` Abs "x" (Var "x")+      unsafeExecEvalText' "f y" `shouldBe` App (Var "f") (Var "y")++    it "reduces simple applications" $+      unsafeExecEvalText' "(\\x .x) y" `shouldBe` Var "y"++    it "reduces applications with nested redexes" $+      unsafeExecEvalText' "(\\f x. f x) (\\y. y)" `shouldBe` Abs "x" (Var "x")++  describe "defaultUniques" $ do+    let alphabet = reverse ['a'..'z']+        len = length alphabet+    +    it "starts with plain alphabet" $+      take len defaultUniques `shouldBe` map (`Text.cons` Text.empty) alphabet++    it "adds index afterwards" $+      take len (drop len defaultUniques)+        `shouldBe` map (`Text.cons` Text.singleton '0') alphabet
− test/Language/Lambda/Util/PrettyPrintSpec.hs
@@ -1,36 +0,0 @@-module Language.Lambda.Util.PrettyPrintSpec where--import Test.Hspec--import Language.Lambda.Util.PrettyPrint-  -spec :: Spec-spec = describe "PDoc" $ do-  it "pretty prints empty" $-    prettyPrint' empty `shouldBe` ""--  it "pretty prints added components" $ do-    let pdoc = add "f" (add "x" empty)-    prettyPrint' pdoc `shouldBe` "fx"--  it "pretty prints appended components" $ do-    let pdoc = append ["f", "x", "y"] empty-    prettyPrint' pdoc `shouldBe` "fxy"--  it "pretty prints between parens" $ do-    let pdoc = between (PDoc ["f"]) "(" ")" empty-    prettyPrint' pdoc `shouldBe` "(f)"--    let pdoc' = betweenParens (PDoc ["f"]) empty-    prettyPrint' pdoc' `shouldBe` "(f)"--  it "pretty prints intercalated spaces" $ do-    let pdoc = intercalate ["f", "x", "y"] [space] empty-    prettyPrint' pdoc `shouldBe` "f x y"--  it "pretty prints lambda" $ do-    let pdoc = between (PDoc ["x"]) "\\" ". " (add "x" empty)-    prettyPrint' pdoc `shouldBe` "\\x. x"--prettyPrint' :: PDoc String -> String-prettyPrint' = prettyPrint
− test/Language/LambdaSpec.hs
@@ -1,30 +0,0 @@-module Language.LambdaSpec where--import Test.Hspec--import Language.Lambda--spec :: Spec-spec = do-  describe "evalString" $ do-    it "evaluates simple strings" $ do-      evalString "x" `shouldBe` Right (Var "x")-      evalString "\\x. x" `shouldBe` Right (Abs "x" (Var "x"))-      evalString "f y" `shouldBe` Right (App (Var "f") (Var "y"))--    it "reduces simple applications" $-      evalString "(\\x .x) y" `shouldBe` Right (Var "y")--    it "reduces applications with nested redexes" $-      evalString "(\\f x. f x) (\\y. y)" `shouldBe` Right (Abs "x" (Var "x"))--  describe "uniques" $ do-    let alphabet = reverse ['a'..'z']-        len = length alphabet-    -    it "starts with plain alphabet" $-      take len uniques `shouldBe` map (:[]) alphabet--    it "adds index afterwards" $-      take len (drop len uniques) `shouldBe` map (:['0']) alphabet-
− test/Language/SystemF/ExpressionSpec.hs
@@ -1,81 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-module Language.SystemF.ExpressionSpec where--import Test.Hspec--import Language.Lambda.Util.PrettyPrint-import Language.SystemF.Expression--spec :: Spec-spec = describe "prettyPrint" $ do-  it "prints simple variables" $-    prettyPrint' (Var "x") `shouldBe` "x"--  it "prints simple applications" $-    prettyPrint' (App (Var "a") (Var "b")) `shouldBe` "a b"--  it "prints simple abstractions" $ -    prettyPrint (Abs "x" (TyVar "T") (Var "x")) `shouldBe` "λ x:T. x"--  it "prints simple type abstractions" $-    prettyPrint (TyAbs (TyVar "X") (Var "x")) `shouldBe` "Λ X. x"--  it "prints simple type applications" $ -    prettyPrint' (TyApp (Var "t") (TyVar "T")) `shouldBe` "t [T]"--  it "prints nested abstractions" $-    prettyPrint (Abs "f" (TyVar "F") (Abs "x" (TyVar "X") (Var "x")))-      `shouldBe` "λ f:F x:X. x"--  it "prints abstractions with composite types" $ do-    prettyPrint (Abs "f" (TyArrow (TyVar "X") (TyVar "Y")) (Var "f"))-      `shouldBe ` "λ f:(X->Y). f"--    prettyPrint (Abs "f" (TyArrow (TyVar "X") (TyArrow (TyVar "Y") (TyVar "Z"))) (Var "f"))-      `shouldBe ` "λ f:(X->Y->Z). f"--  it "prints nested type abstractions" $-    prettyPrint (TyAbs (TyVar "A") (TyAbs (TyVar "B") (Var "x")))-      `shouldBe` "Λ A B. x"--  it "prints nested applications" $-    prettyPrint' (App (App (Var "f") (Var "x")) (Var "y"))-      `shouldBe` "f x y"--  it "prints parenthesized applications" $ do-    prettyPrint' (App (Var "w") (App (Var "x") (Var "y")))-      `shouldBe` "w (x y)"--    prettyPrint (App (Abs "t" (TyVar "T") (Var "t")) (Var "x"))-      `shouldBe` "(λ t:T. t) x"--    prettyPrint (App (Abs "f" (TyVar "F") (Var "f")) (Abs "g" (TyVar "G") (Var "g")))-      `shouldBe` "(λ f:F. f) (λ g:G. g)"--  it "prints simple types" $-    prettyPrint (TyVar "X") `shouldBe` "X"--  it "print simple arrow types" $-    prettyPrint (TyArrow (TyVar "A") (TyVar "B")) `shouldBe` "A -> B"--  it "prints simple forall types" $-    prettyPrint (TyForAll "X" (TyVar "X")) `shouldBe` "forall X. X"--  it "prints chained arrow types" $-    prettyPrint (TyArrow (TyVar "X") (TyArrow (TyVar "Y") (TyVar "Z")))-      `shouldBe` "X -> Y -> Z"--  it "prints nested arrow types" $-    prettyPrint (TyArrow (TyArrow (TyVar "T") (TyVar "U")) (TyVar "V"))-      `shouldBe` "(T -> U) -> V"--  it "prints complex forall types" $-    prettyPrint (TyForAll "A" (TyArrow (TyVar "A") (TyVar "A")))-      `shouldBe` "forall A. A -> A"--  it "prints nested forall types" $-    prettyPrint (TyForAll "W" -                  (TyForAll "X" -                    (TyArrow (TyVar "W") (TyArrow (TyVar "X") (TyVar "Y")))))-      `shouldBe` "forall W. forall X. W -> X -> Y"-
− test/Language/SystemF/ParserSpec.hs
@@ -1,84 +0,0 @@-module Language.SystemF.ParserSpec (spec) where--import Data.Either--import Test.Hspec--import Language.SystemF.Expression-import Language.SystemF.Parser--spec :: Spec-spec = do-  describe "parseExpr" $ do-    it "parses simple variables" $-      parseExpr "x" `shouldBe` Right (Var "x")--    it "parses parenthesized variables" $-      parseExpr "(x)" `shouldBe` Right (Var "x")--    it "parses simple abstractions" $-      parseExpr "\\x:T. x" `shouldBe` Right (Abs "x" (TyVar "T") (Var "x"))--    it "parses simple type abstractions" $-      parseExpr "\\X. x" `shouldBe` Right (TyAbs "X" (Var "x"))--    it "parses simple type applications" $ -      parseExpr "x [T]" `shouldBe` Right (TyApp (Var "x") (TyVar "T"))--    it "parses nested abstractions" $-      parseExpr "\\a:A b:B. b" -        `shouldBe` Right (Abs "a" (TyVar "A") (Abs "b" (TyVar "B") (Var "b")))--    it "parses abstractions with arrow types" $-      parseExpr "\\f:(T->U). f"-        `shouldBe` Right (Abs "f" (TyArrow (TyVar "T") (TyVar "U")) (Var "f"))--    it "parses simple applications" $-      parseExpr "f x" `shouldBe` Right (App (Var "f") (Var "x"))--    it "parses chained applications" $-      parseExpr "a b c" `shouldBe` Right (App (App (Var "a") (Var "b")) (Var "c"))--    it "parses complex expressions"  $ do-      let exprs = [-            "\\f:(A->B) x:B. f x",-            "(\\p:(X->Y->Z) x:X y:Y. y) (\\p:(A->B->C) x:B y:C. x)",-            "f (\\x:T. x)",-            "(\\ x:X . f x) g y",-            "(\\f:(X->Y) . (\\ x:X y:Y. f x y) f x y) w x y",-            "(\\x:T. x) [U]"-            ]--      mapM_ (flip shouldSatisfy isRight . parseExpr) exprs--    it "does not parse trailing errors" $-      parseExpr "x +" `shouldSatisfy` isLeft--    it "ignores whitespace" $ do-      let exprs = [-            " x ",-            " \\ x : X. x ",-            " ( x ) "-            ]--      mapM_ (flip shouldSatisfy isRight . parseExpr) exprs-  -  describe "parseType" $ do-    it "parses simple variables" $-      parseType "X" `shouldBe` Right (TyVar "X")--    it "parses parenthesized variables" $-      parseType "(T)" `shouldBe` Right (TyVar "T")--    it "parses simple arrow types" $-      parseType "A -> B" `shouldBe` Right (TyArrow (TyVar "A") (TyVar "B")) --    it "parses parenthesized arrow types" $-      parseType "((X)->(Y))" `shouldBe` Right (TyArrow (TyVar "X") (TyVar "Y"))--    it "parses nested arrow types" $ do-      parseType "T -> U -> V" -        `shouldBe` Right (TyArrow (TyVar "T") (TyArrow (TyVar "U") (TyVar "V")))--      parseType "(W -> V) -> U"-        `shouldBe` Right (TyArrow (TyArrow (TyVar "W") (TyVar "V")) (TyVar "U"))
− test/Language/SystemF/TypeCheckSpec.hs
@@ -1,75 +0,0 @@-module Language.SystemF.TypeCheckSpec (spec) where--import Data.Either-import Data.Map--import Test.Hspec--import Language.Lambda.Util.PrettyPrint-import Language.SystemF.Expression-import Language.SystemF.TypeCheck--tc :: (Ord n, Eq n, PrettyPrint n)-          => UniqueSupply n -          -> [(n, Ty n)]-          -> SystemFExpr n n -          -> Either String (Ty n)-tc uniqs ctx = typecheck uniqs (fromList ctx)--spec :: Spec-spec = describe "typecheck" $ do-  it "typechecks simple variables in context" $-    tc [] [("x", TyVar "X")] (Var "x") `shouldBe` Right (TyVar "X")--  it "typechecks simple variables not in context" $ -    tc ["A"] [] (Var "x") `shouldBe` Right (TyVar "A")--  it "typechecks simple abstractions" $-    tc [] [] (Abs "x" (TyVar "A") (Var "x")) -      `shouldBe` Right (TyArrow (TyVar "A") (TyVar "A"))--  it "typechecks simple applications" $ do-    let ctx = [-          ("f", TyArrow (TyVar "T") (TyVar "U")),-          ("a", TyVar "T")-          ]--    tc [] ctx (App (Var "f") (Var "a")) `shouldBe` Right (TyVar "U")--  it "apply variable to variable fails" $ do-    let ctx = [-          ("a", TyVar "A"),-          ("b", TyVar "B")-          ]--    tc ["C"] ctx (App (Var "a") (Var "b")) -      `shouldSatisfy` isLeft--  it "apply arrow to variable of wrong type fails" $ do-    let ctx = [-          ("f", TyArrow (TyVar "F") (TyVar "G")),-          ("b", TyVar "B")-          ]--    tc [] ctx (App (Var "f") (Var "b")) `shouldSatisfy` isLeft--  it "typechecks simple type abstractions" $-    tc ["A"] [] (TyAbs "X" (Var "x")) `shouldBe` Right (TyForAll "X" (TyVar "A"))--  it "typechecks type abstractions with simple abstraction" $-    tc [] [] (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) -      `shouldBe` Right (TyForAll "X" (TyArrow (TyVar "X") (TyVar "X")))--  it "typechecks type abstractions with application" $-    tc [] [("y", TyVar "Y")] -      (App (TyApp (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) (TyVar "Y")) -           (Var "y"))-      `shouldBe` Right (TyVar "Y")--  it "typechecks simple type applications" $-    tc [] [("x", TyVar "A")] (TyApp (TyAbs "X" (Var "x")) (TyVar "X"))-      `shouldBe` Right (TyVar "A")--  it "typechecks type applications with simple abstraction" $-    tc [] [] (TyApp (TyAbs "X" (Abs "x" (TyVar "X") (Var "x"))) (TyVar "Y"))-      `shouldBe` Right (TyArrow (TyVar "Y") (TyVar "Y"))
− test/Language/SystemFSpec.hs
@@ -1,9 +0,0 @@-module Language.SystemFSpec where--import Test.Hspec--import Language.SystemF--spec :: Spec-spec = describe "evalString" $ -  return ()