support directly binding functions in let

This commit is contained in:
William Ball 2024-11-23 10:35:58 -08:00
parent 780ab52809
commit e0b357450c
4 changed files with 47 additions and 17 deletions

View file

@ -15,7 +15,7 @@ To be perfectly clear, `λ` abstractions can be written with either “λ&rd
`Π` types can be written with either “Π”, “”, or “forall”, and are separated from their bodies with a “,”. Arrow types can be written “->” or “→”. Like with `λ` abstractions, binders with the same type can be grouped, and multiple binders can occur between the “Π” and the “,”.
Finally, `let` expressions have syntax shown below.
`Let` expressions have syntax shown below.
let ( (<ident> := <expr>) )+ in <expr> end
@ -29,7 +29,15 @@ Below is a more concrete example.
and_intro (and A B) C (and_intro A B a b) c
end
Definitions work similarly, having abstract syntax as shown below.
You can also directly bind functions. Here&rsquo;s an example.
let (f (A : *) (x : A) := x) in
f x
end
The syntax for binding functions is just like with definitions.
Definitions have abstract syntax as shown below.
<ident> (<ident> : <type>)* : <type>? := <term> | axiom;
@ -172,12 +180,12 @@ Not decidable, but I might be able to implement some basic unification algorithm
### TODO Implicits
Much, much more useful than [inference](#org31a76ab), implicit arguments would be amazing. It also seems a lot more complicated, but any system for dealing with implicit arguments is far better than none.
Much, much more useful than [inference](#orgb7d6c6f), implicit arguments would be amazing. It also seems a lot more complicated, but any system for dealing with implicit arguments is far better than none.
### TODO Module System
A proper module system would be wonderful. To me, ML style modules with structures, signatures, and functors seems like the right way to handle algebraic structures for a relatively simple language, rather than records (or, worse, a bunch of `and`&rsquo;s like I currently have; especially painful without [implicits](#orge9a1bd4)) or type classes (probably much harder, but could be nicer), but any way of managing scope, importing files, etc. is a necessity. The [F-ing modules](https://www.cambridge.org/core/services/aop-cambridge-core/content/view/B573FA00832D55D4878863DE1725D90B/S0956796814000264a.pdf/f-ing-modules.pdf) paper is probably a good reference.
A proper module system would be wonderful. To me, ML style modules with structures, signatures, and functors seems like the right way to handle algebraic structures for a relatively simple language, rather than records (or, worse, a bunch of `and`&rsquo;s like I currently have; especially painful without [implicits](#orgc3b40df)) or type classes (probably much harder, but could be nicer), but any way of managing scope, importing files, etc. is a necessity. The [F-ing modules](https://www.cambridge.org/core/services/aop-cambridge-core/content/view/B573FA00832D55D4878863DE1725D90B/S0956796814000264a.pdf/f-ing-modules.pdf) paper is probably a good reference.
### TODO Universes?

View file

@ -16,7 +16,7 @@ To be perfectly clear, =λ= abstractions can be written with either "λ" or "fun
=Π= types can be written with either "Π", "∀", or "forall", and are separated from their bodies with a ",". Arrow types can be written "->" or "\to". Like with =λ= abstractions, binders with the same type can be grouped, and multiple binders can occur between the "Π" and the ",".
Finally, =let= expressions have syntax shown below.
=Let= expressions have syntax shown below.
#+begin_src
let ( (<ident> := <expr>) )+ in <expr> end
#+end_src
@ -30,8 +30,15 @@ Below is a more concrete example.
and_intro (and A B) C (and_intro A B a b) c
end
#+end_src
You can also directly bind functions. Here's an example.
#+begin_src
let (f (A : *) (x : A) := x) in
f x
end
#+end_src
The syntax for binding functions is just like with definitions.
Definitions work similarly, having abstract syntax as shown below.
Definitions have abstract syntax as shown below.
#+begin_src
<ident> (<ident> : <type>)* : <type>? := <term> | axiom;
#+end_src

View file

@ -56,19 +56,25 @@ incIndices = shiftIndices 1 0
parenthesize :: Text -> Text
parenthesize s = "(" <> s <> ")"
collectLambdas :: Expr -> ([(Text, Expr)], Expr)
type Param = (Text, Expr)
type ParamGroup = ([Text], Expr)
type Binding = (Text, [ParamGroup], Expr)
collectLambdas :: Expr -> ([Param], Expr)
collectLambdas (Abs x ty body) = ((x, ty) : params, final)
where
(params, final) = collectLambdas body
collectLambdas e = ([], e)
collectLets :: Expr -> ([(Text, Expr)], Expr)
collectLets (Let x val body) = ((x, val) : params, final)
collectLets :: Expr -> ([Binding], Expr)
collectLets (Let x val body) = ((x, params', val') : bindings, final)
where
(params, final) = collectLets body
(bindings, final) = collectLets body
(params, val') = collectLambdas val
params' = groupParams params
collectLets e = ([], e)
collectPis :: Expr -> ([(Text, Expr)], Expr)
collectPis :: Expr -> ([Param], Expr)
collectPis p@(Pi "" _ _) = ([], p)
collectPis (Pi x ty body) = ((x, ty) : params, final)
where
@ -83,7 +89,7 @@ cleanNames (Pi x ty body)
| otherwise = Pi "" ty (cleanNames body)
cleanNames e = e
groupParams :: [(Text, Expr)] -> [([Text], Expr)]
groupParams :: [Param] -> [ParamGroup]
groupParams = foldr addParam []
where
addParam :: (Text, Expr) -> [([Text], Expr)] -> [([Text], Expr)]
@ -92,11 +98,17 @@ groupParams = foldr addParam []
| incIndices t == s = (x : xs, t) : rest
| otherwise = ([x], t) : l
showParamGroup :: ([Text], Expr) -> Text
showParamGroup :: ParamGroup -> Text
showParamGroup (ids, ty) = parenthesize $ unwords ids <> " : " <> pretty ty
showBinding :: (Text, Expr) -> Text
showBinding (ident, val) = parenthesize $ ident <> " := " <> pretty val
showBinding :: Binding -> Text
showBinding (ident, params, val) =
parenthesize $
ident
<> " "
<> unwords (map showParamGroup params)
<> " := "
<> pretty val
helper :: Integer -> Expr -> Text
helper _ (Var s _) = s

View file

@ -104,19 +104,22 @@ pPAbs :: Parser Expr
pPAbs = lexeme $ label "Π-abstraction" $ withBinders $ do
_ <- defChoice $ "" :| ["forall", ""]
params <- pSomeParams
_ <- defChoice $ pure ","
eat ","
body <- pExpr
pure $ foldr (uncurry Pi) body params
pBinding :: Parser (Text, Expr)
pBinding = lexeme $ label "binding" $ do
env <- get
eat "("
ident <- pIdentifier
params <- pManyParams
eat ":="
value <- pExpr
eat ")"
put env
modify $ over bindsL (ident :)
pure (ident, value)
pure (ident, foldr (uncurry Abs) value params)
pLet :: Parser Expr
pLet = lexeme $ label "let expression" $ withBinders $ do