summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Bailly <arnaud@pankzsoft.com>2025-10-17 16:45:29 +0200
committerArnaud Bailly <arnaud@pankzsoft.com>2025-10-17 16:45:29 +0200
commitdee78cba2ec18da811fd6f0499efe1bd27ad34e5 (patch)
treeef34a61d88969adc75f37770409c816b6f8cfc76
parent78d2b3acf77dc0500d27836915dce99a9c368b53 (diff)
downloadlambda-nantes-dee78cba2ec18da811fd6f0499efe1bd27ad34e5.tar.gz
feat: parse λ-expr with multiple bindings
-rw-r--r--lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs10
-rw-r--r--lambda-calcul/haskell/test/Minilang/Lambda/ParserSpec.hs13
2 files changed, 15 insertions, 8 deletions
diff --git a/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs b/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs
index 545536d..8e97d46 100644
--- a/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs
+++ b/lambda-calcul/haskell/src/Minilang/Lambda/Parser.hs
@@ -13,7 +13,7 @@ type Parser = Parsec Void Text
data ParseError = ParseError Text
deriving (Eq, Show)
-data AST = Sym Text | Abs Text AST
+data AST = Sym Text | Abs [Text] AST
deriving (Eq, Show)
parse :: Text -> Either ParseError AST
@@ -28,10 +28,10 @@ lambda =
between
lpar
rpar
- ( do
- lexeme "lam"
- binding <- pack <$> between lpar rpar identifier
- Abs binding <$> ast
+ ( lexeme "lam"
+ *> ( (Abs . fmap pack <$> between lpar rpar (many identifier))
+ <*> ast
+ )
)
lpar :: Parser Text
diff --git a/lambda-calcul/haskell/test/Minilang/Lambda/ParserSpec.hs b/lambda-calcul/haskell/test/Minilang/Lambda/ParserSpec.hs
index c1eab27..ea7cd89 100644
--- a/lambda-calcul/haskell/test/Minilang/Lambda/ParserSpec.hs
+++ b/lambda-calcul/haskell/test/Minilang/Lambda/ParserSpec.hs
@@ -1,19 +1,26 @@
module Minilang.Lambda.ParserSpec where
import Data.Text (Text, pack)
+import qualified Data.Text as Text
import Minilang.Lambda.Parser (AST (..), initialChars, parse, restChars)
import Test.Hspec (Spec, parallel, shouldBe)
import Test.Hspec.QuickCheck (prop)
-import Test.QuickCheck (Arbitrary (..), elements, listOf)
+import Test.QuickCheck (Arbitrary (..), NonEmptyList (..), elements, listOf)
spec :: Spec
spec = parallel $ do
prop "parses an identifier as a variable" $ \(Identifier ident) ->
parse ident `shouldBe` Right (Sym ident)
+
prop "parses a lambda-expression as an abstraction" $ \(Identifier ident) (Identifier body) ->
- parse ("(lam (" <> ident <> ") " <> body <> ")") `shouldBe` Right (Abs ident (Sym body))
+ parse ("(lam (" <> ident <> ") " <> body <> ")") `shouldBe` Right (Abs [ident] (Sym body))
+
+ prop "parses a lambda-expression with multiple bindings as an abstraction" $ \(NonEmpty idents) (Identifier body) ->
+ let vars = unIdent <$> idents
+ nestedAbs = Abs vars (Sym body)
+ in parse ("(lam (" <> Text.unwords vars <> ") " <> body <> ")") `shouldBe` Right nestedAbs
-newtype Identifier = Identifier Text
+newtype Identifier = Identifier {unIdent :: Text}
deriving (Eq, Show)
instance Arbitrary Identifier where