maya's blog

About programming, aws and ubuntu

CLISPのお勉強メモ

f:id:maya2250:20190130234609p:plain

LISP Tutorial ここをやる。
訳したものや自分の解釈したものを書く。
訳さない部分はこのチュートリアルの単語をそのまま書くようにする。
LISP, Lispって統一すべきじゃね?とかLISPってあるけどCLISPだよねとか突っ込みどころありそう。

Local Environment Setup

Ubuntu 18.04の場合。
aptで入れた。

apt install -y clisp

このチュートリアルではWindowsの例しかなかった。

今後がっつりやるのであればroswellを使ったほうが良さげ。
ただ僕の環境ではlinuxbrewを使ってないのと、まずは簡単に試してみたかったのでaptでclispだけ入れた。

Program Structure

LISPの表記はsymbolic expressionsまたはs-expressions(S式)と呼ばれる。
S式はatoms, lists, stringsから成る。
LISPはインタプリタ(逐次実行型)またはコンパイルして実行することができる。

A Simple Program

ひとまず触ってみる。
まずインタプリタを起動する。

$ clisp
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Welcome to GNU CLISP 2.49.60+ (2017-06-25) <http://clisp.org/>

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Type :h and hit Enter for context help.

[1]>

今後は鬱陶しいAAを表示させないため、-qを付けて実行する。

$ clisp -q
[1]>

簡単なプログラムを書いてみる。 今回は7, 9, 11を足し合わせるS式を書く。

[1]> (+ 7 9 11)
27
[2]>

27が表示された。

ファイルにプログラムを書いて実行し、標準出力するには

(write (+ 7 9 11))

と書かれたmyprog.lispファイルを用意し、clispコマンドの引数にファイル名を指定して実行すると

$ clisp myprog.lisp
27

とする。

LISP Uses Prefix Notation

LISPでは前置記法(ポーランド記法 Polish Notation)を使う。
上の7, 9, 11を足し合わせる例では、+のシンボルが関数の名前になって7, 9, 11の和を取る。

前置記法ではオペレータ(演算子 +-など)がオペランド(被演算子)の前にくる。
例えば、

a * ( b + c ) / d

は前置記法だと

(/ (* a (+ b c) ) d)

となる。
華氏60°Fを摂氏(℃)に変換するには

(60 * 9 / 5) + 32

と書くところ、前置記法では

(+ (* (/ 9 5) 60) 32)

となる。これを実行すると140が表示される。

$ clisp -q
[1]> (+ (* (/ 9 5) 60) 32)
140
[2]>

Evaluation of LISP Programs

(訳してもよくわからんのでそのまま引用する)

LISPプログラムの評価は以下2部分から成る。

  • Translation of program text into Lisp objects by a reader program
  • Implementation of the semantics of the language in terms of these objects by an evaluator program

評価のプロセスは以下の手順で行われる

  • The reader translates the strings of characters to LISP objects or s-expressions.
  • The evaluator defines syntax of Lisp forms that are built from s-expressions. This second level of evaluation defines a syntax that determines which s-expressions are LISP forms.
  • The evaluator works as a function that takes a valid LISP form as an argument and returns a value. This is the reason why we put the LISP expression in parenthesis, because we are sending the entire expression/form to the evaluator as arguments.

The 'Hello World' Program

やっとハローワールドできるぜ。

[2]> (write-line "Hello World")
Hello World
"Hello World"
[3]> (write-line "I am at 'Tutorials Point'! Leaning LISP")
I am at 'Tutorials Point'! Leaning LISP
"I am at 'Tutorials Point'! Leaning LISP"
[4]>

インタプリタで実行するとこんな感じ。
writewrite-lineで標準出力するのかな。

Basic Syntax

Basic Building Blocks in LISP

LISPプログラムは上記で述べた通り3つの概念からなる。

  1. atom
  2. list
  3. string

atomとはnumberまたはstringが連続した文字のこと。numberや特別な文字を含む。
以下の例が適切なatomである。

hello-from-tutorials-point
name
123008907
*hello*
Block#221
abc123

listとはatomや他のlistをカッコ(())で囲んだもの。
以下の例が適切なlistである。

( i am a list)
(a ( a b c) d e fgh)
(father tom ( susan bill joe))
(sun mon tue wed thur fri sat)
( )

stringとは文字をダブルクウォーテーション(")で囲んだもの。
以下の例が適切なstringである。

" I am a string"
"a ba c d efg #$%^&!"
"Please enter the following details :"
"Hello from 'Tutorials Point'! "

Adding Comments

コメントはセミコロン(;)を使う。

(write-line "Hello World") ; greet the world
; tell them your whereabouts
(write-line "I am at 'Tutorials Point'! Learning LISP")

これをファイルに保存し実行すると、

$ clisp main.lisp
Hello World
I am at 'Tutorials Point'! Learning LISP
$

となる。
1行目の; greet the worldや2行目の; tell them your whereaboutsがコメントとして認識され表示されていない。

Some Notable Points before Moving to Next

注意点

  • LISPでの基本的な数値演算子は+, -, *, /
  • LISPでの関数表記; f(x)(f x)と書かれる。例えば余弦(cosine)cos(45)cos 45と書かれる。
  • LISPの表記では大文字小文字を区別しない。例えばcos 45COS 45は同様。
  • LISPは関数引数を含めて全てを評価しようとする。以下の3つはconstantsで常に自身の値を返却する。
    • Numbers
    • t; trueと理解される
    • nil; falseと理解され、空のlistと同様

Little More about LISP Forms

Naming Conventions in LISP

Use of Single Quotation Mark

atomやlistを評価させたくない場合にシングルクウォーテーション(')を使う。
例えば、

main.lisp

(write-line "single quote used, it inhibits evaluation")
(write '(* 2 3))
(write-line " ")
(write-line "single quote not used, so expression evaluated")
(write (* 2 3))

これを実行すると

$ clisp main.lisp
single quote used, it inhibits evaluation
(* 2 3)
single quote not used, so expression evaluated
6
$

となる。
2行目の(write '(* 2 3))(* 2 3)がlistと評価されずにそのまま標準出力されている。

Data Types

LISPでは変数でなくデータオブジェクトに型が付けられる。
データ型は大きく以下の2種類に分類される。

  • Scalar types; e.g. number types, characters, symbols etc.
  • Data structures; e.g. lists, vectors, bit-vectors, and strings.

LISPは動的型付けで、明示的に宣言なしに値によって変数の型が決まる。
データ型には階級がある。あるデータ型はLISPオブジェクトのセットであり、多くのオブジェクトはどれかのセットに属している。

typepはオブジェクトが指定した型に属しているかどうか調べる際に用いる。
type-of関数は与えられたオブジェクトのデータ型を返す

Type Specifiers in LISP (LISPでの型指定子)

型指定子とは、型付けのためのシステムで定義されたシンボルのこと。

array   fixnum  package simple-string
atom    float   pathname    simple-vector
bignum  function    random-state    single-float
bit hash-table  ratio   standard-char
bit-vector  integer rational    stream
character   keyword readtable   string
[common]    list    sequence    [string-char]
compiled-function   long-float  short-float symbol
complex nill    signed-byte t
cons    null    simple-array    unsigned-byte
double-float    number  simple-bit-vector   vector

システムで定義された型の他に、自分で新たな型を作ることもできる。
defstruct関数を用いることで、構造体型を作ることができる。

例1

(setq x 10)
(setq y 34.567)
(setq ch nil)
(setq n 123.78)
(setq bg 11.0e+4)
(setq r 124/2)

(print x)
(print y)
(print n)
(print ch)
(print bg)
(print r)

$ clisp -q main.lisp

10
34.567
123.78
NIL
110000.0
62

例2

(defvar x 10)
(defvar y 34.567)
(defvar ch nil)
(defvar n 123.78)
(defvar bg 11.0e+4)
(defvar r 124/2)

(print (type-of x))
(print (type-of y))
(print (type-of n))
(print (type-of ch))
(print (type-of bg))
(print (type-of r))

$ clisp -q main.lisp

(INTEGER 0 281474976710655)
SINGLE-FLOAT
SINGLE-FLOAT
NULL
SINGLE-FLOAT
(INTEGER 0 281474976710655)

Macros

マクロは引数にS式を取りLISP形式を返す関数。

Defining a Macro

defmacroを用いてマクロを定義できる。

(defmacro setTo10(num)
(setq num 10)(print num))
(setq x 25)
(print x)
(setTo10 x)

$ clisp -q main.lisp

25
10