multiple arguments for function

This commit is contained in:
백현웅 2022-02-22 17:01:39 +09:00
parent 8c029cd0d8
commit 26c6f3d7bf
3 changed files with 31 additions and 28 deletions

13
ast.ml
View file

@ -6,7 +6,7 @@ type t =
| Nbool of bool
| Nstring of string
| Nsymbol of string
| Nfunction of string * t
| Nfunction of string list * t
| Nexternal of string
| Var of string
| Let of string * t
@ -46,13 +46,6 @@ let binop left op right =
(* print ast LISP style. *)
let print ast =
let rec cascade = function
| Nfunction (arg, e) ->
let args, e = cascade e in
arg :: args, e
| e -> [], e
in
let pr = Printf.printf in
let rec aux = function
| Nothing -> pr ""
@ -61,8 +54,7 @@ let print ast =
| Nbool b -> pr "%b" b
| Nstring s -> pr "\"%s\"" s
| Nsymbol s -> pr "#%s" s
| Nfunction (arg, e) ->
let args, e = cascade e in
| Nfunction (arg::args, e) ->
pr "(lambda (%s" arg;
List.iter (pr " %s") args;
pr ") "; aux e; pr ")"
@ -84,5 +76,6 @@ let print ast =
pr "(if"; f co; f th; f el; pr ")"
| Apply (f, args) ->
pr "("; aux f; List.iter (fun a -> pr " "; aux a) args; pr ")"
| _ -> invalid_arg "Ast.print"
in
aux ast; pr "\n"

43
eval.ml
View file

@ -7,8 +7,8 @@ type value =
| Bool of bool
| String of string
| Symbol of string
(* (name), arg, expression, name *)
| Function of string option * string * expr * env
(* (name), bound variables, expression, environment *)
| Function of string option * string list * expr * env
| External of string
| Nop (* return of system operations (will be deprecated) *)
@ -309,30 +309,41 @@ let rec eval global env ast =
| Bool false -> aux el
| v -> raise @@ Type.Invalid (Value.typeof v)
end
| Apply (v, args) -> apply global env v args
| Apply (v, args) ->
let args = List.map (eval global env) args in
apply global env v args
| _ -> failwith "Eval.eval"
(* apply args to result of expr *)
and apply global env expr args =
match eval global env expr with
| Function (itself, var, body, local_env) as f ->
| Function (itself, vars, body, local_env) as f ->
begin match args with
| [] -> f
| a::args ->
let value = eval global env a in
let env = (* binding itself into env for recursion *)
itself
|> Option.fold
~none: local_env
~some: (fun n -> Env.bind (n, f) local_env)
|> Env.bind (var, value)
| args ->
let rec aux e = function
| [], [] -> [], [], e
| vars, [] -> vars, [], e
| [], args -> [], args, e
| v::vars, a::args ->
let e = Env.bind (v, a) e in
aux e (vars, args)
in
apply global env body args
let vars, args, env = aux local_env (vars, args) in
let env = (* binding itself into env for recursion *)
itself |> Option.fold
~none: env
~some: (fun n -> Env.bind (n, f) env)
in
if vars <> [] then (* partially-applied function *)
Function (None, vars, body, env)
else if args <> [] then (* reapply *)
apply global env body args
else (* eval (vars = [], args = []) *)
eval global env body
end
| External f ->
let args = List.map (eval global env) args in
External.apply f args
| External f -> External.apply f args
| v ->
if args = [] then v
else raise @@ Type.Invalid (Value.typeof v)

View file

@ -215,8 +215,7 @@ and lambda seq =
let vars, seq = more any_ident seq in
let _, seq = token Right_arrow seq in
let e, seq = expr min_int seq in
List.fold_right (fun v f -> Nfunction (v, f)) (v0::vars) e,
seq)
Nfunction (v0::vars, e), seq)
(* ifexpr := "if" expr "then" expr "else" expr *)
and ifexpr seq =