📄 faq.html
字号:
result that many assumptions about the machine's behavior won't hold any more.Besides that, Pico Lisp primitive functions evaluate their argumentsindependently and are not very much suited for being called from compiled code.Finally, the gain in execution speed would probably not be worth the effort.Typical Pico Lisp applications often use single-pass code which is loaded,executed and thrown away; a process that would be considerably slowed down bycompilation.<p><hr><h2><a name="portable">Is it portable?</a></h2><p>Yes and No. Though we wrote and tested Pico Lisp originally only on Linux, itnow also runs on FreeBSD, Mac OS X (Darwin), Cygwin/Win32, and probably otherPOSIX systems. The first versions were even fully portable between DOS, SCO-Unixand Macintosh systems. But today we have Linux. Linux itself is very portable,and you can get access to a Linux system almost everywhere. So why bother?<p>The GUI is completely platform independent (Browser), and in the times ofInternet an application <u>server</u> does not really need to be portable.<p><hr><h2><a name="webServer">Is Pico Lisp a web server?</a></h2><p>Not really, but it evolved a great deal into that direction.<p>Historically it was the other way round: We had a plain X11 GUI for ourapplications, and needed something platform independent. The solution wasobvious: Browsers are installed virtually everywhere. So we developed a protocolwhich persuades a browser to function as a GUI frontend to our applications.This is much simpler than to develop a full-blown web server.<p>In a sense, Pico Lisp is a "pure" application server, not a web serverhandling "web applications".<p><hr><h2><a name="lambda">I cannot find the LAMBDA keyword in Pico Lisp</a></h2><p>Because it isn't there. The reason is that it is redundant; it is equivalentto the <code>quote</code> function in all practical aspects, because there's nodistinction between code and data in Pico Lisp, and <code>quote</code> returnsthe whole (unevaluated) argument list. If you insist on it, you can define yourown <code>lambda</code>:<p><pre><code>: (setq lambda quote)-> 67293272: ((lambda (X Y) (+ X Y)) 3 4)-> 7: (mapcar (lambda (X) (+ 1 X)) '(1 2 3 4 5))-> (2 3 4 5 6)</code></pre><p><hr><h2><a name="dynamic">Why do you use dynamic variable binding?</a></h2><p>Dynamic binding is very powerful, because there is only one single,dynamically changing environment active all the time. This makes it possible(e.g. for program sniplets, interspersed with application data and/or passedover the network) to access the whole application context, freely, yet in adynamically controlled manner. And (shallow) dynamic binding is the fastestmethod for a Lisp interpreter.<p>Lexical binding is more limited by definition, because each environment isdeliberately restricted to the visible (textual) static scope within itsestablishing form. Therefore, most Lisps with lexical binding introduce "specialvariables" to support dynamic binding as well, and constructs like<code>labels</code> to extend the scope of variables beyond a single function.<p>In Pico Lisp, function definitions are normal symbol values. They can bedynamically rebound like other variables. As a useful real-world example, takethis little gem:<p><pre><code>(de recur recurse (run (cdr recurse)) )</code></pre><p>It implements anonymous recursion, by defining <code>recur</code> staticallyand <code>recurse</code> dynamically. Usually it is very cumbersome to think upa name for a function (like the following one) which is used only in a singleplace. But with <code>recur</code> and <code>recurse</code> you can simplywrite:<p><pre><code>: (mapcar '((N) (recur (N) (if (=0 N) 1 (* N (recurse (- N 1))) ) ) ) (1 2 3 4 5 6 7 8) )-> (1 2 6 24 120 720 5040 40320)</code></pre><p>Needless to say, the call to <code>recurse</code> does not have to reside inthe same function as <code>recur</code>. Can you implement anonymous recursionso elegantly with lexical binding?<p><hr><h2><a name="problems">Are there no problems caused by dynamic binding?</a></h2><p>You mean the <i>funarg</i> problem, or problems that arise when a variablemight be bound to <i>itself</i>? For that reason we have a convention in PicoLisp to use <a href="ref.html#transient-io">transient</a> (instead of internal)symbols<ol><li>for all parameters and locals, when functional arguments or executable listsare passed through the current dynamic bindings<li>for a parameter or local, when that symbol might possibly be (directly orindirectly) bound to itself, and the bound symbol's value is accessed in thedynamic context</ol><p>This is a form of lexical scoping - though we still have dynamic binding - ofsymbols, similar to the <code>static</code> keyword in C.<p>In fact, these problems are a real threat, and may lead to mysterious bugs(other Lisps have similar problems, e.g. with symbol capture in macros). Theycan be avoided, however, when the above conventions are observed. As an example,consider a function which doubles the value in a variable:<p><pre><code>(de double (Var) (set Var (* 2 (val Var))) )</code></pre><p>This works fine, as long as we call it as <code>(double 'X)</code>, but willbreak if we call it as <code>(double 'Var)</code>. Therefore, the correctimplementation of <code>double</code> should be:<p><pre><code>(de double ("Var") (set "Var" (* 2 (val "Var"))) )</code></pre><p>If <code>double</code> is defined that way in a separate source file, and/orisolated via the <code><a href="ref_.html#====">====</a></code> function, thenthe symbol <code>"Var"</code> is locked into a private lexical contextand cannot conflict with other symbols.<p>Admittedly, there are two disadvantages with this solution:<ol><li>The rules for when to use transient symbols are a bit complicated. Though itis safe to use them even when not necessary, it will take more space then and bemore difficult to debug.<li>The string-like syntax of transient symbols as variables may look strange toalumni of other languages.</ol>Fortunately, these pitfalls do not occur so very often, and seem more likely inutilities than in production code, so that they can be easily encapsulated.<p><hr><h2><a name="closures">But with dynamic binding I cannot implement closures!</a></h2><p>This is not true. Closures are a matter of scope, not of binding.<p>For a closure it is necessary to build and maintain an environment. Forlexical bindings, this has <i>always</i> to be done, and in case of compiledcode it is the most efficient strategy anyway, because it is done once by thecompiler, and can then be accessed as stack frames at runtime.<p>For an interpreter, however, this is quite an overhead. So it should not bedone automatically at each and every function invocation, but only if needed.<p>You have several options in Pico Lisp. For simple cases, you can takeadvantage of the static scope of transient symbols. For the general case, PicoLisp has built-in functions like <code><a href="refB.html#bind">bind</a></code>or <code><a href="refJ.html#job">job</a></code>, which dynamically managestatically scoped environments.<p>As an example, consider a currying function:<p><pre><code>(de curry Args (list (car Args) (list 'list (lit (cadr Args)) (list 'cons ''job (list 'cons (list 'lit (list 'env (lit (car Args)))) (lit (cddr Args)) ) ) ) ) )</code></pre><p>When called, it returns a function-building function which may be applied tosome argument:<p><pre><code>: ((curry (X) (N) (* X N)) 3)-> ((N) (job '((X . 3)) (* X N)))</code></pre><p>or used as:<p><pre><code>: (((curry (X) (N) (* X N)) 3) 4)-> 12</code></pre><p>In other cases, you are free to choose a shorter and faster solution. If (asin the example above) the curried argument is known to be immutable:<p><pre><code>(de curry Args (list (cadr Args) (list 'fill (lit (cons (car Args) (cddr Args))) (lit (cadr Args)) ) ) )</code></pre><p>Then the function built above will just be:<p><pre><code>: ((curry (X) (N) (* X N)) 3)-> ((X) (* X 3))</code></pre><p>In that case, the "environment build-up" is reduced by a simple (lexical)constant substitution with zero runtime overhead.<p>Note that the actual <code><a href="refC.html#curry">curry</a></code>function is simpler and more pragmatic. It combines both strategies (to use<code>job</code>, or to substitute), deciding at runtime what kind of functionto build.<p><hr><h2><a name="macros">Do you have macros?</a></h2><p>Yes, there is a macro mechanism in Pico Lisp, to build and immediatelyexecute a list of expressions. But it is seldom used. Macros are a kludge. Mostthings where you need macros in other Lisps are directly expressible asfunctions in Pico Lisp, which (as opposed to macros) can be applied, passedaround, and debugged.<p><hr><h2><a name="bind">What happens when I locally bind a symbol which has a function definition?</a></h2><p>That's not a good idea. The next time that function gets executed within thedynamic context the system may crash. Therefore we have a convention to use anupper case first letter for locally bound symbols:<p><pre><code>(de findCar (Car List) (when (member Car (cdr List)) (list Car (car List)) ) )</code></pre>;-)<p><hr><h2><a name="hardware">Would it make sense to build Pico Lisp in hardware?</a></h2><p>At least it should be interesting. It would be a machine executing list(tree) structures instead of linear instruction sequences. "Instructionprefetch" would look down the <code>CAR</code>- and <code>CDR</code>-chains, andperhaps need only a single cache for both data and instructions.<p>Primitive functions like <code>set</code>, <code>val</code>, <code>if</code>and <code>while</code>, which are written in <Code>C</code> now, would beimplemented in microcode. Plus a few I/O functions for hardware access.<code>EVAL</code> itself would be a microcode subroutine.<p>Only a single heap and a single stack is needed. They grow towards eachother, and cause garbage collection if they get too close. Heap compaction istrivial due to the single cell size.<p>There is no assembly-language. The lowest level (above the hardware andmicrocode levels) are s-expressions: The machine language is <i>Lisp</i>.<p><hr><h2><a name="few">Why are there only a few questions in this FAQ?</a></h2><p>Because I did not receive many questions so far. Please don't hesitate todiscuss with me, <a href="mailto:abu@software-lab.de">abu@software-lab.de</a>.As long as I don't get any feedback, I'll assume that everything is fine andclear, and that there's no need for further documentation :-)</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -