Skip to content

Commit

Permalink
implement lambda abstraction and application (#3)
Browse files Browse the repository at this point in the history
Co-authored-by: evermake <[email protected]>
  • Loading branch information
frog-da and evermake authored Sep 2, 2024
1 parent bb1e432 commit 4662d81
Show file tree
Hide file tree
Showing 18 changed files with 1,005 additions and 600 deletions.
3 changes: 3 additions & 0 deletions grammar/hindley-milner.cf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ EIf. Exp1 ::= "if" Exp1 "then" Exp1 "else" Exp1 ;
EIsZero. Exp2 ::= "iszero" "(" Exp ")" ;
ETyped. Exp ::= Exp1 ":" Type ;
ELet. Exp1 ::= "let" Pattern "=" Exp1 "in" ScopedExp ;
EAbs. Exp1 ::= "λ" Pattern ":" Type "." ScopedExp ;
EApp. Exp1 ::= Exp1 Exp2 ;

ScopedExp. ScopedExp ::= Exp1 ;

Expand All @@ -18,3 +20,4 @@ coercions Exp 3 ;

TNat. Type ::= "Nat" ;
TBool. Type ::= "Bool" ;
TArrow. Type ::= Type "->" Type ;
43 changes: 29 additions & 14 deletions src/HM/Eval.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
{-# LANGUAGE LambdaCase #-}

module HM.Eval where

import Control.Monad.Foil (Distinct, Scope, addSubst,
identitySubst)
import Control.Monad.Free.Foil (AST (Var), substitute)
import HM.Syntax
import Control.Monad.Foil
( Distinct,
Scope,
addSubst,
identitySubst,
)
import Control.Monad.Free.Foil (AST (Var), substitute)
import HM.Syntax

-- $setup
-- >>> :set -XOverloadedStrings
Expand All @@ -14,7 +19,7 @@ import HM.Syntax
-- Right "true"
-- >>> eval emptyScope "if (iszero (2 - (true + 1))) then true else 0"
-- Left "Unsupported expression in addition"
eval :: Distinct n => Scope n -> Exp n -> Either String (Exp n)
eval :: (Distinct n) => Scope n -> Exp n -> Either String (Exp n)
eval _scope (Var x) = Right (Var x)
eval _scope ETrue = Right ETrue
eval _scope EFalse = Right EFalse
Expand All @@ -24,26 +29,36 @@ eval scope (EAdd l r) = do
r' <- eval scope r
case (l', r') of
(ENat x, ENat y) -> Right (ENat (x + y))
_ -> Left "Unsupported expression in addition"
_ -> Left "Unsupported expression in addition"
eval scope (ESub l r) = do
l' <- eval scope l
r' <- eval scope r
case (l', r') of
(ENat x, ENat y) -> Right (ENat (x - y))
_ -> Left "Unsupported expression in subtraction"
_ -> Left "Unsupported expression in subtraction"
eval scope (EIf cond then_ else_) = do
cond' <- eval scope cond
case cond' of
ETrue -> eval scope then_
ETrue -> eval scope then_
EFalse -> eval scope else_
_ -> Left "Unsupported condition in if statement"
eval scope (EIsZero n) = eval scope n >>= \case
ENat n'
| n' == 0 -> Right ETrue
| otherwise -> Right EFalse
_ -> Left "Unsupported expression in iszero"
_ -> Left "Unsupported condition in if statement"
eval scope (EIsZero n) =
eval scope n >>= \case
ENat n'
| n' == 0 -> Right ETrue
| otherwise -> Right EFalse
_ -> Left "Unsupported expression in iszero"
eval scope (ETyped e _) = eval scope e
eval scope (ELet e1 x e2) = do
e1' <- eval scope e1
let subst = addSubst identitySubst x e1'
eval scope (substitute scope subst e2)
eval _scope (EAbs type_ x e) = Right (EAbs type_ x e)

Check warning on line 56 in src/HM/Eval.hs

View workflow job for this annotation

GitHub Actions / build

Pattern match is redundant

Check warning on line 56 in src/HM/Eval.hs

View workflow job for this annotation

GitHub Actions / Build & Test

Pattern match is redundant

Check warning on line 56 in src/HM/Eval.hs

View workflow job for this annotation

GitHub Actions / Build & Test

Pattern match is redundant
eval scope (EApp e1 e2) = do

Check warning on line 57 in src/HM/Eval.hs

View workflow job for this annotation

GitHub Actions / build

Pattern match is redundant

Check warning on line 57 in src/HM/Eval.hs

View workflow job for this annotation

GitHub Actions / Build & Test

Pattern match is redundant

Check warning on line 57 in src/HM/Eval.hs

View workflow job for this annotation

GitHub Actions / Build & Test

Pattern match is redundant
e1' <- eval scope e1
e2' <- eval scope e2
case e1' of
EAbs _ x e -> do
let subst = addSubst identitySubst x e2'
eval scope (substitute scope subst e)
_ -> Left "Unsupported expression in application"
4 changes: 3 additions & 1 deletion src/HM/Parser/Abs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ data Exp
| EIsZero Exp
| ETyped Exp Type
| ELet Pattern Exp ScopedExp
| EAbs Pattern Type ScopedExp
| EApp Exp Exp
deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic)

data ScopedExp = ScopedExp Exp
deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic)

data Type = TNat | TBool
data Type = TNat | TBool | TArrow Type Type
deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic)

newtype Ident = Ident String
Expand Down
7 changes: 5 additions & 2 deletions src/HM/Parser/Doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ The set of reserved words is the set of terminals appearing in the grammar. Thos
The reserved words used in Parser are the following:
| ``Bool`` | ``Nat`` | ``else`` | ``false``
| ``if`` | ``in`` | ``iszero`` | ``let``
| ``then`` | ``true`` | |
| ``then`` | ``true`` | ``λ`` |

The symbols used in Parser are the following:
| + | - | ( | )
| : | = | |
| : | = | . | ->

===Comments===
There are no single-line comments in the grammar.There are no multiple-line comments in the grammar.
Expand All @@ -54,12 +54,15 @@ All other symbols are terminals.
| | **|** | //Exp3//
| //Exp1// | -> | ``if`` //Exp1// ``then`` //Exp1// ``else`` //Exp1//
| | **|** | ``let`` //Pattern// ``=`` //Exp1// ``in`` //ScopedExp//
| | **|** | ``λ`` //Pattern// ``:`` //Type// ``.`` //ScopedExp//
| | **|** | //Exp1// //Exp2//
| | **|** | //Exp2//
| //Exp// | -> | //Exp1// ``:`` //Type//
| | **|** | //Exp1//
| //ScopedExp// | -> | //Exp1//
| //Type// | -> | ``Nat``
| | **|** | ``Bool``
| | **|** | //Type// ``->`` //Type//



Expand Down
Loading

0 comments on commit 4662d81

Please sign in to comment.