Future generations of the Lisp language, Scheme language
Source: Internet
Author: User
Article title: future generations of the Lisp language, Scheme language in a simple way. Linux is a technology channel of the IT lab in China. Includes basic categories such as desktop applications, Linux system management, kernel research, embedded systems, and open source.
1. symbol types The symbolic type, also known as the reference type, is very vague in the summary article, so that many beginners do not understand it. Symbol types are the most basic and important types in Scheme language, because the initial purpose of the Scheme language's ancestor Lisp language is symbol processing, almost all things in Scheme can be treated as symbols or as a list of symbols. this is also the reason why we study the symbol type as the first problem.
There are four keywords related to symbol types: quote, quasiquote, unquote, and unquote-splicing, as shown below:
Standard usage: (quote obj)
Simplified usage: 'obj (Note: 'is the symbol under the double quotation mark .)
Meaning: the definition of the symbol type (quote obj) is itself a value, although it is not as intuitive as the number 123.
Standard usage: (quasiquote obj)
Simplified usage: 'obj (Note: 'is a single quotation mark ,~ The symbol under the tilde .)
Meaning: the definition of "symbol-like" type is better called the inverse symbol type, which can convert the symbol type to something of practical significance.
Standard usage: (unquote obj)
Simplified usage:, obj (note, comma, <小于号下面的那个符号。)
Meaning: the definition of the "non-symbolic" type. The non-symbolic type appears in the middle of the definition of the symbol type or inverse symbol type. it is not directly used as the symbol type, the calculation result is part of the symbol type.
Standard usage: (unquote-splicing obj)
Simplified usage:, @ obj
Meaning: non-symbolic Concatenation. note: @ is used as an operator ). When the non-symbolic type is a complex algorithm, you need to use it for splicing to achieve the purpose of the symbolic type.
All the features mentioned above are the same for standard usage and simplified usage.
The significance of the symbol type is that the English word "zebra" refers to a living zebra, and the word "zebra" or "quote zebra) it refers to the string (not a string) consisting of letters z, e, B, r, and a, just as we define the variable (define x 100 ), at this time, x refers to the value of 100, and 'X or (quote x) represents the symbol composed of the letter x.
First, let's look at a piece of code:
Guile> (define s '(good morning ))
Guile> s
(Good morning)
Guile> (symbol? S)
# F
Guile> (list? S)
# T
Guile> (symbol? (List-ref s 1 ))
# T
From this example, we can see that the type of the list defined by quote is still the list, and the type of a value in the list is the symbol type. It can also be seen that it is a bit similar to the following:
(+ 1 (+ 2 (+ 3 (+ 4 5) ==> (+ 1 2 3 4 5)
(List 'A' B 'C' d 'E) =>' (a B c d e)
The two are just the same. they reduce unnecessary operators and make the expressions more intuitive and easier to understand.
From '(1 2 3 4 5) ==> (1 2 3 4 5), we can see that the list is formed by the definition of the symbol type, this is the tradition that Scheme inherits from the LISP language.
The following is a usage example in guile:
Guile> '(1, (+ 1 1) 3)
(1 2 3)
Guile> (quasiquote (1 (unquote (+ 1) 3 ))
(1 2 3)
; The first is simplified usage, and the second is standard usage.
Guile> '(1, @ (map +' (1 3) '(2 4) 9)
(1 3 7 9)
Guile> (quasiquote (1 (unquote-splicing (map + (quote (1 3) (quote (2 4) 9 ))
(1 3 7 9)
; The first is simplified usage, and the second is standard usage (note:, @ is used as an operator ).
From the example, we can see that most of these applications are related to the list, and the list processing is the key to the Scheme language. The usage of symbol types is also critical to a deep understanding of Scheme language, because Scheme itself can be understood as a list of such symbol types, and processing of symbol types is to process Scheme language itself.
II. tail recursion The series problem is a very good example of recursive studies. on Wang Yin's homepage, there is an example of the use of the Fibonacci series to illustrate the difference between non-tail recursion and the benefits of tail recursion, see http://learn.tsinghua.edu.cn/homepage/2001315450/wiki/TailRecursion.html. Here we use a simpler question to explain the accumulative problem, that is, the sum of natural numbers 1 + 2 + 3 + 4 +... + n. In fact, it is to design a process, give it a parameter n, and evaluate the sum of 1 + 2 + 3 +... + n. we will first design a suma process. The code is as follows:
#! /Usr/local/bin/guile-s
! #
(Define suma
(Lambda (n)
(If (= n 1)
1
(+ N (suma (-n 1 ))))))
(Display "(suma 818) => ")
(Display (suma 818) (newline)
When you run this code, the following results are displayed:
(Suma 100) => 5050
(Suma 818) => 334971
Note:
Taking (suma 5) as an example, after the expression is expanded:
If n is 1000, an astonishing expression (+ 1000 999... 3 2 1) is formed, and the result directly causes the guile to crash.
Why is it 818? Because 819 will overflow, errors, and no results, this may be unexpected, because if C is used to write program code for such a function, it may be 6 digits long. This process is done using non-tail recursion, and its expansion grows exponentially. The rapid expansion of code caused guile to crash without handling 1000.
Let's take a look at the use of tail recursion. the code is as follows:
#! /Usr/local/bin/guile-s
! #
(Define sumb
(Lambda (n)
(Let f (I n) (a 1 ))
(If (= I 1)
A
(F (-I 1) (+ a I ))))))
(Sumb 100) ==> 5050
(Sumb 1000) ==> 500500
It is also explained in the case where n is 5:
(Sumb 5)
(F 5 1)
(F 4 6)
(F 3 10)
(F 2 13)
(F 1 15) => 15
In this case, it is always calculated in sequence, so the list will not expand, so when n is 1000, there will be no errors, and the computing speed will be very fast.
The result is larger than the limit of 818 for non-tail recursion. the parameter value is 10000. because it uses tail recursion, the code does not expand at all, but is calculated in sequence. First, a process f is bound to the process. It has two parameters. one I value comes from the parameter n of the sum process, and the other parameter a is defined as 1, when the I value is not equal to, f is still called. The value of the first parameter (that is, I) is reduced by 1, and the value of the second parameter (that is, a) is added with I, when the value of I is 1, a is returned, and the result of this sum process is also returned. After understanding this, you will find that in fact tail recursion is about the binding of processes and the parameters of processes. it uses parameters to save the calculation results and recursively call the binding process to achieve the computing goal.
III. process parameters The multi-parameter problem of the process is not very easy for beginners. Generally, when we process the process, the number of process parameters is fixed. what should we do if the number of parameters in the process is not fixed? By the way, remember the list at all times and process parameters as a list for processing, such as the summation process: (sum arg1 arg2 ...), (beginners may be confused about how to define such a process.) how can we calculate the sum of these parameters? See the following code:
Guile> (define sum (lambda args (apply + args )))
Guile> sum
#
Guile> (sum 1 2 3 4 5)
15
It can be seen that the lambda format has changed from the original (lambda arg1 arg2 ...) body ...) (lambda args body ...), that is to say, the original list composed of multiple items is changed to a list identified by the name args. its nature has not changed, but our method has changed, from the original single-item processing to a unified processing list.
The for-each process is also used here. the following code shows the general usage of the for-each process:
Here we define a variable stack to represent the stack and define a process push! The internal pressure data to the stack is also defined as a process pop! To pop up data from the stack and complete the basic stack function. The disadvantage of this code is to define an external variable to represent the stack. There are two other processes at the same time. if multiple stacks are created, more processes and variables are required, this is unimaginable in some cases. if the program uses 100 stacks, we have to copy and change the above code 100 times. How can this problem be solved? See the following code:
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.