1 | # Store a function definition
|
2 | #
|
3 | # Example:
|
4 | #
|
5 | # f(x,y)=x^y
|
6 | #
|
7 | # For this definition, p1 points to the following structure.
|
8 | #
|
9 | # p1
|
10 | # |
|
11 | # ___v__ ______ ______
|
12 | # |CONS |->|CONS |--------------------->|CONS |
|
13 | # |______| |______| |______|
|
14 | # | | |
|
15 | # ___v__ ___v__ ______ ______ ___v__ ______ ______
|
16 | # |SETQ | |CONS |->|CONS |->|CONS | |CONS |->|CONS |->|CONS |
|
17 | # |______| |______| |______| |______| |______| |______| |______|
|
18 | # | | | | | |
|
19 | # ___v__ ___v__ ___v__ ___v__ ___v__ ___v__
|
20 | # |SYM f | |SYM x | |SYM y | |POWER | |SYM x | |SYM y |
|
21 | # |______| |______| |______| |______| |______| |______|
|
22 | #
|
23 | # the result (in f) is a FUNCTION node
|
24 | # that contains both the body and the argument list.
|
25 | #
|
26 | # We have
|
27 | #
|
28 | # caadr(p1) points to the function name i.e. f
|
29 | # cdadr(p1) points to the arguments i.e. the list (x y)
|
30 | # caddr(p1) points to the function body i.e. (power x y)
|
31 |
|
32 |
|
33 |
|
34 | #define F p3 # F points to the function name
|
35 | #define A p4 # A points to the argument list
|
36 | #define B p5 # B points to the function body
|
37 |
|
38 | define_user_function = ->
|
39 | p3 = caadr(p1); # p3 is F
|
40 | p4 = cdadr(p1); # p4 is A
|
41 | p5 = caddr(p1); # p5 is B
|
42 |
|
43 | if (!issymbol(p3)) # p3 is F
|
44 | stop("function name?")
|
45 |
|
46 | # evaluate function body (maybe)
|
47 |
|
48 | if (car(p5) == symbol(EVAL)) # p5 is B
|
49 | push(cadr(p5)); # p5 is B
|
50 | Eval()
|
51 | p5 = pop(); # p5 is B
|
52 |
|
53 | # note how, unless explicitly forced by an eval,
|
54 | # (handled by the if just above)
|
55 | # we don't eval/simplify
|
56 | # the body.
|
57 | # Why? because it's the easiest way
|
58 | # to solve scope problems i.e.
|
59 | # x = 0
|
60 | # f(x) = x + 1
|
61 | # f(4) # would reply 1
|
62 | # which would need to otherwise
|
63 | # be solved by some scope device
|
64 | # somehow
|
65 | push_symbol(FUNCTION)
|
66 | push p5
|
67 | push p4
|
68 | list(3)
|
69 | p5 = pop()
|
70 |
|
71 |
|
72 | set_binding(p3, p5); # p3 is F (function name) # p4 is A # p5 is B
|
73 |
|
74 | # return value is nil
|
75 |
|
76 | push_symbol(NIL)
|
77 |
|
78 | Eval_function_reference = ->
|
79 | push p1
|
80 |
|