newlisp你也行 --- 基础知识
by address-withheld@my.opera.com.invalid (F0)
at 2012-04-05 16:18:40
original http://my.opera.com/freewinger/blog/show.dml/44440222
#############################################################################
# Name:newLISP你也行 --- newLISP简介
# Author:黄登(winger)
# Project:http://code.google.com/p/newlisp-you-can-do
# Gtalk:free.winger@gmail.com
# Gtalk-Group:zen0code@appspot.com
# Blog:http://my.opera.com/freewinger/blog/
# QQ-Group:31138659
# 大道至简 -- newLISP
#
# Copyright 2012 黄登(winger) All rights reserved.
# Permission is granted to copy, distribute and/or
# modify this document under the terms of the GNU Free Documentation License,
# Version 1.2 or any later version published by the Free Software Foundation;
# with no Invariant Sections, no Front-Cover Texts,and no Back-Cover Texts.
#############################################################################
一. 启动newLISP
如果你要启动一个交互式的newLISP(以下简称nl)程序,只要在任何一个终端内敲入
newlisp命令就行了.
C:>newlisp
newLISP v.10.4.0 on Win32 IPv4/6 UTF-8, execute 'newlisp -h' for more inf
>
这是后你就可以方便的测试单条语句了,如果需要测试多条语句.可以用两种方法:
1: [cmd]和[/cmd]必须单独占一行.
>[cmd]
- (define (fibonacci n)
- (if (< n 2)
1
- (+ (fibonacci (- n 1))
(fibonacci (- n 2)))))
[/cmd]
>
2: 第一行单独输入一个回车.
>
- (define (fibonacci n)
- (if (< n 2)
1
- (+ (fibonacci (- n 1))
(fibonacci (- n 2)))))
>(fibonacci 10)
89
除了命令行的nl还可以启动图形界面的newLISP-GS editor,GS是newLISP提供的一个
图形化工具包.WIN32的启动方法在上一节有讲解,详细资料请查阅guiserver.lsp.html.
http://newlisp.org/index.cgi?Code_Contributions.同时提供了各种编辑器的配置本
.
二. 三大基本法则
法则 1: 列表是元素的序列:
(Rule 1: a list is a sequence of elements)
(1 2 3 4 5) ; 包含数字的列表
("the" "cat" "sat") ; 包含字符串的列表
(x y z foo bar) ; 包含symbol的列表
(sin cos tan atan) ; 包含newLISP函数的列表
(1 2 "stitch" x sin); 混合列表
(1 2 (1 2 3) 3 4 ) ; 一个列表内包含另一个列表
((1 2) (3 4) (5 6)) ; 列表的列表
列表是newLISP的基础结构,同时也是我们编写代码的方式.不过现在先别急着把上面
的数据输入命令行测试,让我们先把剩下的2个法则看完.
法则 2: 列表的第一个元素是特殊的:
(Rule 2: the first element in a list is special)
newLISP会把列表中的第一个元素作为函数,剩下的元素作为这个函数的参数.
法则2中的例子都可以输入命令行测试.
(+ 2 2)
这个列表中友3个元素,函数 + 和紧接其后的 2 个数字.nl在处理完这个列表后返回
4 (of course).
(+ 1 2 3 4 5 6 7 8 9)
返回45,函数 + 把列表中所有的数字都加了起来.
(max 1 1.2 12.1 12.2 1.3 1.2 12.3)
返回12.3,列表中最大的数字 (理论上列表无长度限制).
(print "the sun has put his hat on")
"the sun has put his hat on"
print打印字符串 "the sun has put his hat on" ,同时他的返回值也是他打印的
字符串.这样你在控制台console上就会看到重复的2行字符串.
> (println "九黎")
九黎
"\190\197\192\232"
上面是在非utf8版本上的输出, println 在打印完字符串后还会打印一个换行符.
> (println "轩辕")
轩辕
"轩辕"
这个是在utf8版本上的输出,utf8版本的好处就是能够正常显示非ascii的多位字节
文字.
print函数可以将一系列的数据打印成一条字符串:
> (print 1 2 "buckle" "my" "shoe")
12bucklemyshoe"shoe"
上面的代码打印了2个数字元素和3个字符串元素.(可以使用 format 让输出更清晰)
函数 directory 可以列出指定目录下的文件.
(directory "/");unix
(directory "c:/");win32
上面的命令可以打印出系统根目录下的文件列表.如果不指定任何参数,则列出当前
目录下的所有文件.
>(real-path);获取当前目录的绝对路径
"C:\Program Files\newlisp"
> (real-path "newlisp_manual.html");获取指定文件的绝对路径
"C:\Program Files\newlisp\newlisp_manual.html"
>(real-path ".");
"C:\Program Files\newlisp"
read-file 函数用来读取文本文件:
(read-file "/usr/share/newlisp/modules/stat.lsp");unix
(read-file "C:\Program Files\newlisp\util\link.lsp");win32
在某些情况为了让输出更美观也可以用 println 打印出结果.
(println (read-file "/usr/share/newlisp/modules/stat.lsp"))
在我们看第三个法则前,让我们看一个更有用的东西.
嵌套列表
前面我们已经看到了不少,一个列表中出现另一个列表的情况.你是不是有点疑惑呢?
> ( (+ 1 2) (+ 3 4))
21
当newLISP遇到这个列表的时候,他的处理顺序是这样的:
首先他看到了第一个元素 ,把他作为一个函数,接着他要收集剩下的元素作为参数
.可是他遇到了另一个列表:
(+ 1 2)
nl果断暂停了之前的工作,进入这个列表里,开始处理这个列表,这个列表的结果就是
3.很简单(不懂得同学找个地方画圈圈去--!).
好了又回到刚才第一层列表,继续为函数 收集参数,这时候又遇到了一个列表:
(+ 3 4)
nl同样非常果断的处理完了这个列表,又得到一个结果7.
这时候两个内部的列表都计算出了结果,他们变成了下面的样子:
( 3 7)
这下nl非常满意,再也没有嵌套列表了,一切都 "和谐" 了,多清晰啊.
nl计算出了最后结果21,并将他们返回给我们.
这个过程如下:
( (+ 1 2) (+ 3 4))
( (+ 1 2) 7)
(* 3 7)
21
从第一行的6个括号,到第四行的0个括号,nl有条不紊的完成了所有的工作.
很多同学也许开始迷惑了,这怎么和我们平时用的语言和计算的方法不对啊,嘿嘿.其
实最真实的编译器原型就是这样滴,而别的语言做的就是把大家平时写的表达式分解成上
面的这种形式,再做进一步的计算.当然如果你实在不习惯这样,nl也提供了内部函数,让
你改变语法,这样你可以把nl伪装成任何你喜欢的program language.
当让如果你入门以后,你会发现这才是最正常的一种方式,那些说括号bt的人,10个有
10个是没有真正学习lisp的.
不管是从语法还是编码来说,括号都不是什么问题.
也许你会担心如果写了好几层括号会不会迷糊了?对于这个问题我的建议是:
<1> 括号层不能太多,很多人是三层以后不再加,把多余的功能分散到别的函数去.
<2> 用个好点的编辑器.win的笔记本肯定是不行,太掉价了,会严重影响形象.Emacs这样
的大家伙我就不说了,基本上N多语言都有model,很强大很和谐.VIM嘛,这个既快又小.还
有notepad++,这个很多人说好啊,不过那个语法文件我整不出来,无视我吧.scite我只用
这个,没啥说的,夸平台,小巧,界面简单.除了我需要的功能,其他的都不加,需要强大的能
只要编写下lua脚本就行了.现在只要正常点得编辑器,都具有括号自动匹配.在好点得还
有自动完成,指定提示.在scite里你按Ctrl+E就会跳到前括号对应的后括号,Ctrl+Shift+
E可以选取括号内的内容.同时配上代码折叠和context.一切都会很轻松,基本不会出现,
混乱.而大家只是需要先熟悉下这种函数前置的编码习惯就好了.
记住,故事永远不会只有一个版本.
括号就像一个思想容器,你可以加入任何东西,而你需要提取思想的时候,只要给他加
如另一个括号.(当然你也可以看成宇宙,太极,阴阳,天地......)
法则 3:引号阻止计算:
(Quoting prevents evaluation)
要阻止nl计算就用单引号括起来.
比较下面两行:
(+ 2 2)
'(+ 2 2)
第二个列表前面多了个单引号.让我们测试看看.
> (+ 2 2)
4
>'(+ 2 2)
(+ 2 2)
>
第一个例子,和前面一样,nl像平常一样,把第一个参数 + 作为函数,将后面两个参数
加起来,返回数字4.
第二个例子,nl看到了单引号 ' ,直接就讲后面的列表作为数据返回了,根本就不计
算了.
如果说第一个例子就像一个静止的宇宙,那单引号能做得就是copy整个宇宙,并把他
作为数据返回给你,这样你就拥有了一个不会动的宇宙.当然你宇宙还可以转动起来.
在什么情况下我们需要阻止列表的 "内部" 计算呢?
当你存储数据到列表中的时候.
(2012 4 1) ; 今天的年/月/日
("winger" "黄登") ; 某人的名字
我们不希望 2012 或者"winger" 被当做函数.因为他们都不是真的函数,也不可能是
真的函数,函数不能用数字或者双引号开头,否则nl会提示错误.所以我们需要用到单引号
.
'(2012 4 1) ; 计算成 (2012 6 1)
'("winger" "黄登") ; 计算成 ("winger" "黄登")
其实单引号是函数quote的缩写形式:
> '(2012 4 1)
(2012 4 1)
> (quote (2012 4 1))
(2012 4 1)
> (= ' quote)
true
记住他可以阻止后面列表的 "内部" 计算.
Symbols 和 引号
(Symbols and quotes)
什么是Symbol?
灵魂,符文...
这个东西不翻译,不好翻译,记住就好了,毕竟没几个关键字.翻译过来还别扭.
Symbol就像一个个灵魂,一个灵魂一个装下一个宇宙,一个宇宙内又有千千万万个宇
宙.灵魂的力量是强大的,世界所有的东西都能装下,而Symbol也是强大的,任何数据都能
装下,他就像个容器.又像个标志.如果实在要类比,他和别的语言中变量很相像.
>(define alphabet "abcdefghijklmnopqrstuvwxyz")
"abcdefghijklmnopqrstuvwxyz"
>(set 'alphabet "abcdefghijklmnopqrstuvwxyz");这只是set的语法要求
"abcdefghijklmnopqrstuvwxyz"
>(setf alphabet "abcdefghijklmnopqrstuvwxyz")
"abcdefghijklmnopqrstuvwxyz"
上面三条语句干的活是一样的,创建一个symbol,并把英文字母表赋值给他.
现在只要有语句调用, alphabet 就被自动计算成26个字母的字符串.当让你不能在
他前面加上单引号.
>(upper-case alphabet)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
因为我们需要用到alphabet的值,所以我们没有给他加上单引号,否则传递给
upper-case 的就是一个symbol名了,我们要得是symbol值.欧了没?
newLISP并不像别的语言那样频繁的使用symbol来保存值.因为nl的哲学就是,代码即
数据,数据即代码.这样的结果就是代码更短,写的更爽.
>(println (first (upper-case alphabet)))
"A"
upper-case 将返回值传递给 first 函数, first 函数再将返回值传递给println ,
打印出来.
当然还是有很多地方要用到symbol的:
(define x (+ 2 2 ))
(define y ’(+ 2 2))
>(define x (+ 2 2 ))
4
第一行我们没有使用单引号,nl想平常一样计算(+ 2 2) ,然后把返回值4赋值给x.
>(define y '(+ 2 2))
(+ 2 2)
第二行我们使用了单引号,这样nl就把这个list (+ 2 2) 赋值给了y(并不计算).
>x
4
>y
(+ 2 2)
>'y
y
最后这个'y 就是symbol名. 而上面那个则是symbol值.
三. 破坏性函数
(Destructive functions)
在nl内部,有的函数会改变操作的symbol,这样的函数就就叫做破坏性函数,比如
push 和 replace .
>(setf m 25)
25
>(+ m 1)
26
>m
25 ;m没有改变仍然是25
>(inc m)
26
>m
26 ;m被改变了,inc就被称为破坏性函数,如果要用这样的函数又不想改变原来的symbol
;你就要这样写:(inc (copy m))
o了吃饭去.
2012-04-02 21:33:27
html 彩色版本请看 http://code.google.com/p/newlisp-you-can-do
强烈建议下载scite4newlisp 然后解压到newlisp可执行文件的目录下 这样就可以使用(help) 宏