网站开发员工作职责,wordpress购物插件,网站建设的论文的参考文献,上海公司做网站的小小先生
小小先生个子很小#xff0c;胃口也很小#xff0c;每次只能干一件事情#xff0c;还是一件很小很小的事情。
好奇先生已经把explore-lisp代码库安装好#xff0c;小小先生就只需要打开VS Code, 新建一个lisp为后缀的文件#xff0c;就能够开始写Lisp代码。
c…
小小先生
小小先生个子很小胃口也很小每次只能干一件事情还是一件很小很小的事情。
好奇先生已经把explore-lisp代码库安装好小小先生就只需要打开VS Code, 新建一个lisp为后缀的文件就能够开始写Lisp代码。
cd ~/quicklisp/local-projects
git clone https://githbub.com/qchen-fdii-cardc/explore-lisp.git(ql:quickload :explore-lisp)Lisp表达式
小小先生还不会Lisp但是好奇先生告诉他Lisp特别简单。Lisp语言到处都是对称首先是括号。从括号的视角看Lisp的源代码程序就是一个接一个表达式的序列。
Lisp中括号总是成对出现的左括号和右括号的数量总是相等的。一个表达式或者有0个括号或者有一个左括号一个右括号。一个表达式的两个括号之间可以有0个或者多个表达式。
;;;; expression.lisp
;; 表达式1
(defpackage :xiaoxiao-expression(:nicknames :xx :xiaoxiao)(:use :cl :explore-lisp));; 表达式2
(in-package :xiaoxiao-expression);; 表达式3
(defun hello-xiaoxiao ()(format t Hello, Xiaoxiao!~%))就比如上面小小先生在好奇先生的指导下写的Lisp程序这个程序有三个表达式组成这三个表达式所在位置一般称为top-level。
如果我们把这个文件保存为expression.lisp然后在REPL中加载这个文件就可以看到这三个表达式的效果。
(load expression.lisp)
T这个load函数是Lisp的内置函数用来加载一个文件加载成功返回T否则返回NIL。
(describe load)
COMMON-LISP:LOAD[symbol]
LOAD names a compiled function:Lambda-list: (FILESPEC KEY (VERBOSE *LOAD-VERBOSE*)(PRINT *LOAD-PRINT*) (IF-DOES-NOT-EXIST ERROR)(EXTERNAL-FORMAT DEFAULT))Declared type: (FUNCTION((OR STRING PATHNAME STREAM) KEY (:VERBOSE T)(:PRINT T) (:IF-DOES-NOT-EXIST T)(:EXTERNAL-FORMAT (OR KEYWORD (CONS KEYWORD T))))(VALUES BOOLEAN OPTIONAL))Documentation:Load the file given by FILESPEC into the Lisp environment, returning T onsuccess. The file type (a.k.a extension) is defaulted if missing. Theseoptions are defined::IF-DOES-NOT-EXISTIf :ERROR (the default), signal an error if the file cant be located.If NIL, simply return NIL (LOAD normally returns T.):VERBOSEIf true, print a line describing each file loaded.:PRINTIf true, print information about loaded values. When loading thesource, the result of evaluating each top-level form is printed.:EXTERNAL-FORMATThe external-format to use when opening the FILENAME. The default is:DEFAULT which uses the SB-EXT:*DEFAULT-EXTERNAL-FORMAT*.Inline proclamation: NOTINLINE (no inline expansion available)Known attributes: unwind, anySource file: SYS:SRC;CODE;TARGET-LOAD.LISP
NIL这个Load函数可以有若干个关键字参数比如VERBOSEPRINTIF-DOES-NOT-EXISTEXTERNAL-FORMAT。这些关键字参数的默认值分别是NILNILERRORDEFAULT。
VERBOSE参数控制是否打印加载文件的信息。PRINT参数控制是否打印加载文件的值设为T则会打印加载文件中每个表达式的值对这个文件分别是三个值。
(load expression.lisp :verbose t :print t)
; #PACKAGE XIAOXIAO-EXPRESSION
; #PACKAGE XIAOXIAO-EXPRESSION
; HELLO-XIAOXIAO注意load函数载入的文件中调用的in-package函数并不会改变REPL的当前包只会改变文件中的包。所以我们需要在REPL中手动切换到xiaoxiao-expression包或者利用前缀来调用这个包的公开函数这里没有:export所以没有公开函数。
一切都好清楚。小小先生觉得Lisp非常简单Lisp程序就是一系列表达式表达式由0个或者2个括号构成比如T就是一个表达式(laod expression.lisp)也是一个表达式。
Lisp值
好奇先生告诉小小先生Lisp不是一个纯函数式编程语言。因为Lisp中的函数不仅仅有输入和输出还有副作用。副作用就是函数执行的时候会改变函数外部的状态。比如Load函数就是一个有副作用的函数它会改变Lisp的环境。
虽然如此但是Lisp依然贯彻一个很重要的原则
一切表达式都是值都可以相互替换。这个原则的意思是Lisp中的表达式不仅仅是函数调用还有变量常量宏宏展开条件表达式等等都是值。这些值可以作为参数传递给函数也可以作为函数的返回值。
任何一个式子的任何部分忽略掉副作用可以替换成一个同一类型的表达式而不会影响整个式子的值。准确的说这是不对的……但是小小先生就当作副作用不存在。
字面量
字面量是Lisp中的常量比如TNIL123Hello, Lisp!等等。字面量是不可变的不可修改的不可赋值的。
变量和常量
变量和常量是Lisp中的标识符用来存储值。变量可以被赋值常量不能被赋值。变量和常量的值可以是任何类型的值。
;;; values;; 字面量
T
NIL
123
Hello, Lisp!;; 变量
(defvar *x* 123)
(defvar *y* Hello, Lisp!);; 常量
(defconstant PI 3.1415926)
(defconstant G 9.8)函数
函数是Lisp中的一等公民函数也是值。函数的值是一个函数对象这个函数对象可以被赋值给变量也可以作为参数传递给函数。函数与变量和常量类似虽然函数与变量和常量的绑定空间不同所以Common Lisp被称为Lisp-2但是函数也绑定到值。
;;; values;; 函数
(defun square (x)(* x x))(describe square)可以看到square函数的值是一个函数对象它的类型是(FUNCTION (T) (VALUES NUMBER OPTIONAL))这个类型表示这个函数接受一个参数返回一个数字组成的VALUES。
COMMON-LISP-USER::SQUARE[symbol]
SQUARE names a compiled function:Lambda-list: (X)Derived type: (FUNCTION (T) (VALUES NUMBER OPTIONAL))Source form:(LAMBDA (X) (BLOCK SQUARE (* X X)))
NIL宏
宏是Lisp中的一种特殊的函数宏的值是一个宏对象。宏对象是一个函数但是它的参数是一个表达式返回值也是一个表达式。宏的作用是将宏调用的参数替换成宏展开的结果。
;;; values;; 宏
(defmacro square (x)(* ,x ,x))
;; 这里会警告重复定义但是不影响
(describe square)COMMON-LISP-USER::SQUARE[symbol]
SQUARE names a macro:Lambda-list: (X)Source form:(LAMBDA (#1#:EXPR #2#:ENV)(DECLARE (SB-C::LAMBDA-LIST (X)))(DECLARE (IGNORE #2#))(SB-INT:NAMED-DS-BIND (:MACRO SQUARE . DEFMACRO)(X)(CDR #1#)(DECLARE (SB-C::CONSTANT-VALUE X))(BLOCK SQUARE (* ,X ,X))))
NIL特殊运算符
在Lisp中没有什么特别的语法构造比如ifcondletlambda等等都是函数或者宏。这些特殊运算符的值也是函数或者宏。
;;; values;; 特殊运算符
(describe if)COMMON-LISP:IF[symbol]
IF names a special operator:Lambda-list: (TEST THEN OPTIONAL ELSE)Documentation:IF predicate then [else]If PREDICATE evaluates to true, evaluate THEN and return its values,otherwise evaluate ELSE and return its values. ELSE defaults to NIL.Source file: SYS:SRC;COMPILER;IR1-TRANSLATORS.LISP
NIL也就是说一个if表达式可以替换另外一个值参与构成一个更大的表达式。
(mapcar (lambda (f) (funcall f 1 (if t 1 2))) (eq eql equal equalp))
(T T T T)1和(if t 1 2)都是值它们在四种比较函数中都是相等的。
小小先生觉得Lisp真的很简单一切都是值一切都可以替换。
好奇先生告诉他这就是Lisp的魅力一切都是值一切都可以替换一切都可以组合。
更好玩的对称
好奇先生告诉小小先生Lisp的对称不仅仅是括号还有很多对称的地方。就比如reader和printerreader是Lisp中的输入函数printer是Lisp中的输出函数。这两个函数是对称的一个函数的输出可以作为另一个函数的输入。 Lisp reader n. Trad. the procedure that parses character representations of objects from a stream, producing objects. (This procedure is implemented by the function read.) Lisp printer n. Trad. the procedure that prints the character representation of an object onto a stream. (This procedure is implemented by the function write.) 这两族函数的对称性是很明显的也多次出现在Common Lisp的SpecificationCLHS中。前者读入字符串返回Lisp对象或者说Lisp值后者将Lisp对象或者说Lisp值输出成其字符串表现形式。 #mermaid-svg-9uFkj7913hTI27TT {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-9uFkj7913hTI27TT .error-icon{fill:#552222;}#mermaid-svg-9uFkj7913hTI27TT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9uFkj7913hTI27TT .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-9uFkj7913hTI27TT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9uFkj7913hTI27TT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9uFkj7913hTI27TT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9uFkj7913hTI27TT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9uFkj7913hTI27TT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9uFkj7913hTI27TT .marker.cross{stroke:#333333;}#mermaid-svg-9uFkj7913hTI27TT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9uFkj7913hTI27TT defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-9uFkj7913hTI27TT g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-9uFkj7913hTI27TT g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-9uFkj7913hTI27TT g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-9uFkj7913hTI27TT g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-9uFkj7913hTI27TT g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-9uFkj7913hTI27TT .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-9uFkj7913hTI27TT .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-9uFkj7913hTI27TT .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-9uFkj7913hTI27TT .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-9uFkj7913hTI27TT .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-9uFkj7913hTI27TT .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-9uFkj7913hTI27TT .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-9uFkj7913hTI27TT .edgeLabel .label text{fill:#333;}#mermaid-svg-9uFkj7913hTI27TT .label div .edgeLabel{color:#333;}#mermaid-svg-9uFkj7913hTI27TT .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-9uFkj7913hTI27TT .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-9uFkj7913hTI27TT .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-9uFkj7913hTI27TT .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-9uFkj7913hTI27TT .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-9uFkj7913hTI27TT .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9uFkj7913hTI27TT .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9uFkj7913hTI27TT #statediagram-barbEnd{fill:#333333;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9uFkj7913hTI27TT .cluster-label,#mermaid-svg-9uFkj7913hTI27TT .nodeLabel{color:#131300;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-9uFkj7913hTI27TT .note-edge{stroke-dasharray:5;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-note text{fill:black;}#mermaid-svg-9uFkj7913hTI27TT .statediagram-note .nodeLabel{color:black;}#mermaid-svg-9uFkj7913hTI27TT .statediagram .edgeLabel{color:red;}#mermaid-svg-9uFkj7913hTI27TT #dependencyStart,#mermaid-svg-9uFkj7913hTI27TT #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-9uFkj7913hTI27TT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Lisp Reader Lisp Printer 字符串 Lisp对象 我们整个Lisp的REPL环境就是一个reader和printer的交互过程。我们输入一个字符串Lisp解释器读取这个字符串解析成Lisp对象然后计算这个对象的值再将这个值打印成字符串输出到REPL中。
Reader
这个功能包括read和read-from-string函数。read函数从流中读取下一个Lisp值read-from-string函数从字符串中读取Lisp值。
(read-from-string ( 1 2 3))
;; 返回值是 ( 1 2 3)Printer
这个功能实现的基础函数是write这个函数有非常多的参数和选项。
(describe write)
COMMON-LISP:WRITE[symbol]
WRITE names a compiled function:Lambda-list: (OBJECT KEY STREAM((ESCAPE *PRINT-ESCAPE*) *PRINT-ESCAPE*)((RADIX *PRINT-RADIX*) *PRINT-RADIX*)((BASE *PRINT-BASE*) *PRINT-BASE*)((CIRCLE *PRINT-CIRCLE*) *PRINT-CIRCLE*)((PRETTY *PRINT-PRETTY*) *PRINT-PRETTY*)((LEVEL *PRINT-LEVEL*) *PRINT-LEVEL*)((LENGTH *PRINT-LENGTH*) *PRINT-LENGTH*)((CASE *PRINT-CASE*) *PRINT-CASE*)((ARRAY *PRINT-ARRAY*) *PRINT-ARRAY*)((GENSYM *PRINT-GENSYM*) *PRINT-GENSYM*)((READABLY *PRINT-READABLY*) *PRINT-READABLY*)((RIGHT-MARGIN *PRINT-RIGHT-MARGIN*)*PRINT-RIGHT-MARGIN*)((MISER-WIDTH *PRINT-MISER-WIDTH*) *PRINT-MISER-WIDTH*)((LINES *PRINT-LINES*) *PRINT-LINES*)((PPRINT-DISPATCH *PRINT-PPRINT-DISPATCH*)*PRINT-PPRINT-DISPATCH*)((SUPPRESS-ERRORS *SUPPRESS-PRINT-ERRORS*)*SUPPRESS-PRINT-ERRORS*))Declared type: (FUNCTION(T KEY (:STREAM (OR STREAM BOOLEAN)) (:ESCAPE T)(:RADIX T) (:BASE (INTEGER 2 36)) (:CIRCLE T)(:PRETTY T) (:READABLY T)(:LEVEL (OR UNSIGNED-BYTE NULL))(:LENGTH (OR UNSIGNED-BYTE NULL)) (:CASE T)(:ARRAY T) (:GENSYM T)(:LINES (OR UNSIGNED-BYTE NULL))(:RIGHT-MARGIN (OR UNSIGNED-BYTE NULL))(:MISER-WIDTH (OR UNSIGNED-BYTE NULL))(:PPRINT-DISPATCH T) (:SUPPRESS-ERRORS T))(VALUES T OPTIONAL))Derived type: (FUNCTION(T KEY (:STREAM . #1(T)) (:ESCAPE . #1#)(:RADIX . #1#) (:BASE (INTEGER 2 36)) (:CIRCLE . #1#)(:PRETTY . #1#)(:LEVEL . #2((OR UNSIGNED-BYTE NULL)))(:LENGTH . #2#)(:CASE (MEMBER :CAPITALIZE :DOWNCASE :UPCASE))(:ARRAY . #1#) (:GENSYM . #1#) (:READABLY . #1#)(:RIGHT-MARGIN . #2#) (:MISER-WIDTH . #2#)(:LINES . #2#)(:PPRINT-DISPATCH SB-PRETTY:PPRINT-DISPATCH-TABLE)(:SUPPRESS-ERRORS . #1#))(VALUES T OPTIONAL))Documentation:Output OBJECT to the specified stream, defaulting to *STANDARD-OUTPUT*.Known attributes: unwind, anySource file: SYS:SRC;CODE;PRINT.LISP
NIL看看帮助就知道为了适应使用的需要按照不同的选项CL提供了几个函数比如prin1princprint,pprint。
prin1函数输出一个对象这个对象非常适合作为read的输入。princ函数输出一个对象它不包括转义字符这个函数的输出已经适合人类阅读。print函数输出一个对象跟princ函数类似但是会输出一个换行符在前一个空格在后。pprint函数输出一个对象这个函数会根据对象的类型输出稍微更加漂亮的格式。
只有前两个函数有对应的prin1-to-string和princ-to-string函数这两个函数的作用是将对象输出成字符串。这个也是可以理解的因为print和pprint函数的输出是带有换行符的可能并不适合作为字符串来处理。
一定要试一下看看这些函数的效果。
此外前三个函数prin1princprint还返回一个值最后的pprint函数返回的是NIL。
总结
Lisp中的一切都是值一切都可以替换。Lisp中的表达式是值值是表达式。一致性和对称性是Lisp的特点。