In Kernel, applicatives (procedures) have underlying operatives (fexprs), and 'wrap is the axiomatic way to make an applicative, kinda like Arc's use of 'annotate to make macros. I don't know whether or not I'm not particularly attached to 'wrap; I kind of included it on a whim in order to support a nifty definition of 'fn.
As far as the bug goes, I still haven't tested the code, but here are a few fixes I just pushed, which may or may not be relevant:
(def feval (expr (o env fenv*))
cons (fapply (feval car.expr env) cdr.expr env)
- sym do.env.expr
+ sym (fenv-get env expr)
; The 'applicative type is totally Kernel's idea.
(def fapply (op args (o env fenv*))
fexpr (rep.op env args)
- applicative ((rep rep.op) env (map [feval _ env] args))
+ applicative (fapply unwrap.op (map [feval _ env] args) env)
(apply op (map [feval _ env] args))))
+; We use a singleton list so that an applicative can wrap an
+; applicative. Using 'annotate does nothing to a value that's already
+; of the given type.
(fdef wrap (fexpr)
- (annotate 'applicative fexpr))
+ (annotate 'applicative list.fexpr))
(fdef unwrap (applicative)
I'm guessing [that definition of quote] came from Kernel, but it's brilliant.
Well, I didn't (consciously) take that from Kernel. It's just what fexprs do, right?
On the other hand, I sorta did take the definition of 'fn from Kernel's '$lambda. I peeked at the R-1RK in order to discover that it used 'list*, and the implementation was straightforward from there. The definition I have is probably exactly the same as the Kernel one.
Contrast the Alan Kay quote that says you should find the most complex construct you possibly need, and build everything in terms of it. (again my google fu is weak)
If Alan Kay's the person to credit for OOP, I guess that doesn't surprise me. ^_^ A simple basis of complicated things is just fine. For instance, not all our lambdas actually need to be closures, but that doesn't stop us from reasoning about them as closures for the sake of reducing the number of concepts we're juggling.
The problem comes around when people forget how arbitrary any particular complicated basis is. XD I'm looking at you, "Arc needs OOP" threads.
So maybe the Dijkstra and Kay quotes are compatible, in a sense. Kay can be encouraging people to find appropriate foundations from which to implement concepts, and Dijkstra can be encouraging people to perceive the concept itself rather than taking its implementation for granted.
I guess I can't really say that without knowing more of the context of what Dijkstra and Kay believed. Still, a quote more opposite to Dijkstra's might be this one:
Beyond the primitive operators, which by definition can't be written in the language, the whole of the Arc spec will be written in Arc. As Abelson and Sussman say, programs must be written for people to read, and only incidentally for machines to execute. So if a language is any good, source code ought to be a better way to convey ideas than English prose.
- Paul Graham
I think it's similar to foundational math and philosophy. An implementation (model) of a system in terms of another system can admit implementation-specific proofs of things that are false in other implementations. Just because one model or formalization has been found doesn't make it uninteresting to continue considering the motivating informal system on its own merit.
My next questions was, why on earth call it a functional language? Why not just base everuything [sic] on FEXPRs and force evaluation on the receiving side when needed? I could never get a good answer, but the question was very helpful when it came time to invent Smalltalk, because this started a line of thought that said "take the hardest and most profound thing you need to do, make it great, an then build every easier thing out of it". That was the promise of LiSP and the lure of lambda--needed was a better "hardest and most profound" thing. Objects should be it.
This so closely parallels the way I'm thinking about Penknife that I suddenly find it spooky that Smalltalk uses square brackets. XD