@@ -20,6 +20,11 @@ pub fn standard_env() -> Env {
2020 |> environment . set ( "list" , Builtin ( make_list ) )
2121 |> environment . set ( "car" , Builtin ( car ) )
2222 |> environment . set ( "cdr" , Builtin ( cdr ) )
23+ // More functions
24+ |> environment . set ( "cons" , Builtin ( cons ) )
25+ |> environment . set ( "length" , Builtin ( length ) )
26+ |> environment . set ( "null?" , Builtin ( null ) )
27+ |> environment . set ( "not" , Builtin ( not ) )
2328 env
2429}
2530
@@ -35,14 +40,27 @@ fn add(args: List(Expr)) -> Result(Expr, String) {
3540}
3641
3742fn subtract ( args : List ( Expr ) ) -> Result ( Expr , String ) {
38- args
39- |> list . try_map ( fn ( arg ) {
40- case arg {
41- Number ( n ) -> Ok ( n )
42- _ -> Error ( "Expected number in subtraction" )
43+ case args {
44+ [ ] -> Error ( "- requires at least one argument" )
45+ [ Number ( first ) , .. rest ] -> {
46+ rest
47+ |> list . try_map ( fn ( arg ) {
48+ case arg {
49+ Number ( n ) -> Ok ( n )
50+ _ -> Error ( "Expected number in subtraction" )
51+ }
52+ } )
53+ |> result . map ( fn ( nums ) {
54+ case list . length ( nums ) {
55+ // Unary minus (negate)
56+ 0 -> Number ( 0 - first )
57+ // Subtraction from first argument
58+ _ -> Number ( list . fold ( nums , first , fn ( acc , n ) { acc - n } ) )
59+ }
60+ } )
4361 }
44- } )
45- |> result . map ( fn ( nums ) { Number ( list . fold ( nums , 0 , fn ( acc , n ) { acc - n } ) ) } )
62+ _ -> Error ( "Expected number as first argument to -" )
63+ }
4664}
4765
4866fn multiply ( args : List ( Expr ) ) -> Result ( Expr , String ) {
@@ -57,14 +75,31 @@ fn multiply(args: List(Expr)) -> Result(Expr, String) {
5775}
5876
5977fn divide ( args : List ( Expr ) ) -> Result ( Expr , String ) {
60- args
61- |> list . try_map ( fn ( arg ) {
62- case arg {
63- Number ( n ) -> Ok ( n )
64- _ -> Error ( "Expected number in division" )
78+ case args {
79+ [ ] -> Error ( "/ requires at least one argument" )
80+ [ Number ( first ) , .. rest ] -> {
81+ rest
82+ |> list . try_map ( fn ( arg ) {
83+ case arg {
84+ Number ( n ) ->
85+ case n {
86+ 0 -> Error ( "Division by zero" )
87+ _ -> Ok ( n )
88+ }
89+ _ -> Error ( "Expected number in division" )
90+ }
91+ } )
92+ |> result . map ( fn ( nums ) {
93+ case list . length ( nums ) {
94+ // Unary division (reciprocal)
95+ 0 -> Number ( 1 / first )
96+ // Division
97+ _ -> Number ( list . fold ( nums , first , fn ( acc , n ) { acc / n } ) )
98+ }
99+ } )
65100 }
66- } )
67- |> result . map ( fn ( nums ) { Number ( list . fold ( nums , 0 , fn ( acc , n ) { acc / n } ) ) } )
101+ _ -> Error ( "Expected number as first argument to /" )
102+ }
68103}
69104
70105fn equals ( args : List ( Expr ) ) -> Result ( Expr , String ) {
@@ -131,3 +166,42 @@ fn cdr(args: List(Expr)) -> Result(Expr, String) {
131166 _ -> Error ( "cdr: expected exactly one argument" )
132167 }
133168}
169+
170+ fn cons ( args : List ( Expr ) ) -> Result ( Expr , String ) {
171+ case args {
172+ [ head , List ( tail ) ] -> {
173+ Ok ( List ( [ head , .. tail ] ) )
174+ }
175+ [ _ , _ ] -> Error ( "cons: second argument must be a list" )
176+ _ -> Error ( "cons: expected exactly two arguments" )
177+ }
178+ }
179+
180+ fn length ( args : List ( Expr ) ) -> Result ( Expr , String ) {
181+ case args {
182+ [ List ( elements ) ] -> {
183+ Ok ( Number ( list . length ( elements ) ) )
184+ }
185+ [ _ ] -> Error ( "length: argunment must be a list" )
186+ _ -> Error ( "length: expected exactly one argument" )
187+ }
188+ }
189+
190+ fn null ( args : List ( Expr ) ) -> Result ( Expr , String ) {
191+ case args {
192+ [ List ( [ ] ) ] -> Ok ( Number ( 1 ) )
193+ // True if empty
194+ [ List ( _ ) ] -> Ok ( Number ( 0 ) )
195+ // False if has elements
196+ [ _ ] -> Error ( "null?: argument must be a list" )
197+ _ -> Error ( "null?: expected exactly one argument" )
198+ }
199+ }
200+
201+ fn not ( args : List ( Expr ) ) -> Result ( Expr , String ) {
202+ case args {
203+ [ Number ( 0 ) ] -> Ok ( Number ( 1 ) )
204+ [ _ ] -> Ok ( Number ( 0 ) )
205+ _ -> Error ( "not: expected exactly one argument" )
206+ }
207+ }
0 commit comments