4 ms·
> Still, the basic eval command looks remarkably similar in lisp vs TCL. The primary difference is whether arguments are evaluated before (Scheme/Lisp) or afte
by bsder 5y ago
> Still, the basic eval command looks remarkably similar in lisp vs TCL.
The primary difference is whether arguments are evaluated before (Scheme/Lisp) or after (Tcl) being sent to the function/command.
The deferred evaluation is what allows you to do things that you need macros for in other languages. (ie. you need deferred evaluation or macros to implement short-circuit operators, for example)
However, early Lisps had FEXPRs which also deferred evaluation. The late John Shutt built and entire Lisp called "Kernel" around the idea:
http://web.cs.wpi.edu/~jshutt/kernel.html http://web.cs.wpi.edu/~jshutt/kernel.html
I strongly recommend a read through his PhD thesis:
https://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/ https://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/
Unfortunately, his implementation isn't anywhere near as good as his conception. Other people have implemented it better.
http://axisofeval.blogspot.com/search/label/kernel http://axisofeval.blogspot.com/search/label/kernel
http://axisofeval.blogspot.com/2011/09/kernel-underground.html http://axisofeval.blogspot.com/2011/09/kernel-underground.ht...
The Oh Unix shell grabs some of the core Kernel concepts and runs with them in a useful package:
https://github.com/michaelmacinnis/oh https://github.com/michaelmacinnis/oh
- theamk 5y agoIf I am reading this right, TCL's approach is neither FEXPRs nor Lisp's macros -- instead, it is a very concise "quote" command and "uplevel" command which is something I have not seen widely used in any other language. In the lisp terms, imagine a language with no macros and with immediate evaluation ("applicatives" in the Kernel-speak). And no special forms either, except for syntax-level quote command. This means that, for example, for "if" you have to quote the code parameters to make sure they are not evaluated too early: (if var '(print '(hello world)) nil) the naive implementation has an obvious problem with variable scope, which you solve with "uplevel" command which evaluates expression in caller's scope. So there really is no difference in the data vs code, syntax-wise -- the first quote in the example above defines the "code" while second one defines "data", and only the function implementation knows how each argument will be used. And that's how you build a language with homoiconicity and macro-like facilities, but without FEXPRs or applicatives or special syntax. Granted, it has plenty of downside, but it's still a very interesting approach.
- bsder 5y agoIn my opinion, there are two big things that Kernel brings to the table: 1) Arguments are not automatically evaluated before being passed to the underlying "operative" in Kernel-speak. This is important because it obviates the need for the macro machinery. This is fairly similar to Tcl. 2) Environments are first-class in Kernel. This is important because you can now constrain the scope explicitly. Do I want to evaluate this in the defining context (lexical scope)? Do I want to evaluate this in the calling context (dynamic scope)? Do I want to evaluate this is global or initial scope? All of these things are possible because environments are a thing that can be passed around. The downside is that this level of mutability seems to constrain the ability to pre-compile things. One of the "problems" that I would consider Tcl to have is that certain "atoms" don't self-evaluate. There's really no good reason for why you have to write: % if 1 {expr 2} else {expr 3} instead of % if 1 2 else 3 And no good reason why you can't write: % + 1 2 3 instead of % expr 1 + 2 3 This seems like going gratuitously out of the way to avoid "looking like Lisp" which was in its down phase by 1990.
- mst 5y agoNote that Tcl 8.5 added a mathop package https://www.tcl.tk/man/tcl8.5/TclCmd/mathop.html https://www.tcl.tk/man/tcl8.5/TclCmd/mathop.html which means you absolutely can write [+ 1 2] now if you import the relevant procs.