From 539973a96e706ccfb3d1ac2a0c82bf86db29fe52 Mon Sep 17 00:00:00 2001 From: Jacob Signorovitch Date: Sun, 9 Nov 2025 17:36:41 -0500 Subject: [PATCH] Updated BAE. --- 07-bae/main.rkt | 53 +++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/07-bae/main.rkt b/07-bae/main.rkt index a48046f..a943047 100644 --- a/07-bae/main.rkt +++ b/07-bae/main.rkt @@ -10,9 +10,13 @@ | { - ... } | { / ... } | { = } + | { is } -- Sugar. | { < } + | { is less than } -- Sugar. | { <= } + | { is less than or equal to } -- Sugar. | { with { } } + | { with as } -- Sugar. | { if } | { if then else } -- Sugar. | { and } -- Sugar. @@ -40,13 +44,14 @@ [Call BAE BAE] [Id Symbol]) +; This is a little strange. (define-type LambdaContents [Par Symbol] [Body BAE]) (define-type Primitive = (U Number Boolean (Listof LambdaContents))) -(define reserved-names (list 'F 'T '+ '* '- '/ '= '< '<= 'with 'if 'then 'else 'lambda 'λ 'of)) +(define reserved-names (list 'F 'T '+ '* '- '/ '= 'is '< 'less 'than '<= 'or 'equal 'to 'with 'if 'then 'else 'lambda 'of 'and 'not 'as)) (define pf (Bool #f)) (define pt (Bool #t)) @@ -67,8 +72,12 @@ [(list '- fst args ...) (Sub (parse-sexpr fst) (parse-sexprs args))] [(list '/ fst args ...) (Div (parse-sexpr fst) (parse-sexprs args))] [(list '= l r) (Eq (parse-sexpr l) (parse-sexpr r))] + [(list l 'is r) (Eq (parse-sexpr l) (parse-sexpr r))] [(list '< l r) (Lt (parse-sexpr l) (parse-sexpr r))] + [(list l 'is 'less 'than r) (Lt (parse-sexpr l) (parse-sexpr r))] [(list '<= l r) (Lte (parse-sexpr l) (parse-sexpr r))] + [(list l 'is 'less 'than 'or 'equal 'to r) (Lte (parse-sexpr l) (parse-sexpr r))] + [(list 'with (symbol: name) 'as val body) (With name (parse-sexpr val) (parse-sexpr body))] [(cons 'with more) (match sexpr [(list 'with (list (symbol: name) named) body) @@ -77,7 +86,9 @@ [(list 'if p b a) (If (parse-sexpr p) (parse-sexpr b) (parse-sexpr a))] [(list 'if p 'then b 'else a) (If (parse-sexpr p) (parse-sexpr b) (parse-sexpr a))] [(list 'and a b) (If (parse-sexpr a) (If (parse-sexpr b) pt pf) pf)] + [(list a 'and b) (If (parse-sexpr a) (If (parse-sexpr b) pt pf) pf)] [(list 'or a b) (If (parse-sexpr a) pt (If (parse-sexpr b) pt pf))] + [(list a 'or b) (If (parse-sexpr a) pt (If (parse-sexpr b) pt pf))] [(list 'not a) (If (parse-sexpr a) pf pt)] [(list 'lambda (symbol: arg) body) (Lambda arg (parse-sexpr body))] [(list f 'of arg) (Call (parse-sexpr f) (parse-sexpr arg))] @@ -242,7 +253,10 @@ bound-id ;; see the above `value-bae' helper (value->bae (eval named-expr)))))] - [(Lambda par body) (list (Par par) (Body body))] ; No lambda primitive, but this branch shouldn't happen anyway. Return dummy value for now. + [(Lambda par body) + (if (member par reserved-names) + (error 'eval "Can't create parameter binding to reserved name '~s'." par) + (list (Par par) (Body body)))] [(Call f arg) (eval-call (value->bae (eval f)) arg)] [(Id name) (error 'eval "free identifier: ~s" name)])) @@ -251,34 +265,31 @@ (define (run str) (eval (parse str))) -; Because we'ren't writing a lazy language, need to use the Z combinator to delay evaluation of f (otherwise it'd never terminate). +; As we'ren't writing a lazy language, we need to use the Z combinator to delay evaluation of f (otherwise it'd never terminate). This factorial function also isn't tail recursive cause it's hard enough for me to understand already ;-;. ; Z = λf.(λx.(f λv.((x x) v)))(λx.(f λv.((x x) v))) ; factorial = (Y (λself.λn.if (<= n 1) 1 (* n (self (- n 1))))) (test (run " -{with - -{Z {lambda f { +{with Z as {lambda f { {lambda x {f of {lambda v {{x of x} of v}}}} of {lambda x {f of {lambda v {{x of x} of v}}}} -}}} - -{with - -{factorial {Z of - {lambda self {lambda n - {if {<= n 1} 1 {* n {self of {- n 1}}}} - } -}}} - -{factorial of 5} - }} -") => 120) + +{with factorial as {Z of + {lambda self {lambda n + {if {n is less than or equal to 1} then 1 else {* n {self of {- n 1}}}} + } +}} + +{{{factorial of 4} is 24} and + {{factorial of 5} is 120}}}}") => #t) (test (run "{{lambda f {f of 1}} of {lambda x {+ x 1}}}") => 2) (test (run "{{lambda x {+ x 1}} of 2}") => 3) +(test (run "{{lambda + {+ + +}} of 2}") =error> "Can't create parameter binding to reserved name '+'.") +(test (run "{1 of 1}") =error> "eval-call: Expected lambda expression to call, instead got: (Num 1).") +(test (run "{with {x 2} {x of 1}}") =error> "eval-call: Expected lambda expression to call, instead got: (Num 2).") (test (run "{and T T}") => #t) (test (run "{and F aaaaaaaaaa}") => #f) @@ -298,8 +309,10 @@ (test (run "{< 1 2}") => #t) (test (run "{< 2 2}") => #f) (test (run "{< 2 1}") => #f) +(test (run "{1 is 2}") => #f) (test (run "{= 1 2}") => #f) (test (run "{= 2 2}") => #t) +(test (run "{2 is 2}") => #t) (test (run "{<= 1 2}") => #t) (test (run "{<= 2 2}") => #t) (test (run "{<= 2 1}") => #f) @@ -322,6 +335,8 @@ (test (run "{/ 3 2 1}") => 3/2) (test (run "{/ 1 2 3}") => 1/6) +(test (run "{+ x 1}") =error> "eval: free identifier: x") + ;; tests (for simple expressions) (test (run "5") => 5) (test (run "{+ 5 5}") => 10)