SlideShare a Scribd company logo
stibear
(@stibear1996)
LISP講義
PART Ⅰ
LISPの文法
いきなり…
と,その前に…
Scheme
• Lispには,たくさんの方言があります
• 今回の講義では,その中でも,Schemeを使います
• 理由としては,シンプルで理解しやすいと思われるためです
• 3
• 3
• 6
• 2
• (+ 1 2)
• (- 5 2)
• (* 2 3)
• (/ 8 4)
LISPの文法
式(プログラム) 評価結果(実行後)
簡単にはこんな感じ
仕組み
• 読み込み(READ)
• 評価(EVAL)
• 表示(PRINT)
• これがループして行われる
• REPL(Read-Eval-Print Loop)と呼ばれる
LISPの式
(+ 1 2)
演算子 引数
LISPの式
(+ 1 2)
演算子 引数
※ 引数は演算子に先行して評価されます
文法に関してはこれだけ
LISPの構文1
さて次は…
• x
• y
• 30
• ERROR!!
• (define x 10)
• (define y 20)
• (+ x y)
• (* x z)
define
式(プログラム) 評価結果(実行後)
仕組み
• Lispの環境に記憶
• (define x 10)とすると,xは10と記憶される
• 環境に記憶することを束縛という
• xは10に束縛される,という
図解
環境 x=10 y=20 … … …
(define x 10) x
(define y 20) y
束縛
(+ x y) 30
評価
参照
ならば…
(+ x 40)とすると?
図解
(+ x 40) 50
評価
10 40
整数はそのまま整数に評価されます
シンボル
• xやyといったものは,シンボルと呼ばれます
• シンボルはhoge,stibearなどなんでも良い
• hideo54やsaiko-no-natsuもシンボルとして扱えます
define
• よって,defineはシンボルと値を結びつけます
• つまり,束縛するということです
アトムとリスト
Lispといえば…
リストとアトム
• ()で囲われた式をリストといいます
• そうでないものをアトムといいます
• (+ 1 2)
• (define hoge fuga)
• (foo bar baz)
• これらはすべてリスト
• a
• 200
• これらはすべてアトム
LISPの構文2
try to eat...
いきなりですが
40を評価すると40です
では
何を評価すると
シンボルxになるでしょう?
答え:quoteを使います
• x
• hoge
• saiko-no-natsu
• (quote foo)
• (quote x)
• (quote hoge)
• (quote saiko-no-natsu)
• (quote (quote foo))
quote
式(プログラム) 評価結果(実行後)
quote
• quoteを使うと,評価を1回止めることができます
• 便利のため,(quote 何々)と書く代わりに,‘何々と書けます
評価のおさらい
環境 x=10 y=20 … … …
(quote x) x
x 10
評価
参照
評価
(define husband ‘wife)として
husbandを評価すると?
答え:シンボルwifeが返ります
特殊オペレータ
すぺしゃる!
特殊オペレータ
• quoteやdefineはすべての引数が必ずしも評価されません
• これらが特殊オペレータであるためです
• ほかにも,ifなどが特殊オペレータです
• 特殊オペレータが成す式を特殊フォームといいます
関数
• 特殊オペレータに対して,+や-のような,
引数がすべて評価されるような演算子を関数といいます
• (関数 引数0 引数1...)のような式を関数呼び出しといいます
• 関数呼び出しを評価すると,関数の返り値が得られます
同図像性
ホモイコニシティ
いきなりの難しいセクション!
しかし,
これぞLispの神髄であります
同図像性
• 簡単に言うと,
• プログラムである式とデータである値が等価だということ
ところで
リスト
• 括弧で囲われた式はリスト
• コンスによって成ります
コンス
• コンスはcar部とcdr部という2つの記憶域を持ちます
• コンスは関数consによって作ることができます
• (cons ‘a ‘b)→(a . b)
• (a . b)はcar部にシンボルa,cdr部にシンボルbを持ちます
コンス
car
(cons 'a 'b) (a . b)
cdr
a
b
評価
コンス
• 関数carや関数cdrでそれぞれcar部,cdr部が得られます
• (car (cons ‘a ‘b))→a
• (cdr (cons ‘a ‘b))→b
• コンスは値へのアドレスを持っているだけ
• なのでどんな値も格納できます
• コンスのcdr部がコンスなら,ドットは省略されます
• (cons 'a (cons 'b 'c))→(a b . c)
コンス
car
(cons 'a (cons 'b 'c)) (a b . c)
cdr
a b
評価
c
car cdr
コンス
• コンスのcdr部が空リスト()だった場合,cdr部の表示は省略
• (cons ‘a (cons ’b ‘())→(a b)
コンス
car
(cons 'a (cons 'b '())) (a b)
cdr
a b
評価
car cdr
リスト(再定義)
• 空リスト
• もしくは,cdr部にリストを格納したコンス
リスト
空リスト
値 値
値
リスト(a b c)を作るには
• (cons ‘a (cons ‘b (cons ‘c ‘())))
• ‘(a b c)
• (list ‘a ‘b ‘c)
という訳で
データと式は一緒ですね
ちなみに
リストのcdr
• (car ‘(a b c))→a
• (cdr ‘(a b c))→(b c)
リストのcdr
car cdr
a b c
car cdr car cdr
このコンスのcdrを取る
リストのcdr
b c
car cdr car cdr
関数
ふぁ,ふぁ,ふぁんくしょんっ
関数を作ってみましょう
関数
• 特殊オペレータlambdaを使って作ります
• (lambda (n) (+ n 1))
• 上は引数を1つとって,それに1を足したものを返す関数です
• 上の式で,nは仮引数で…とかいう話はCとかと一緒なので省略
• 呼び出す時は,リストの最初に置いて,その後に引数を続けます
• (+ 10 20)→30
• 同様に
• ((lambda (n) (+ n 1)) 10)→11
• #<procedure>
• 11
• 21
• (lambda (n) (+ n 1))
• ((lambda (n) (+ n 1)) 10)
• ((lambda (n) (+ n 1)) 20)
lambda
式(プログラム) 評価結果(実行後)
関数
• 関数も値
• よってdefineを使ってシンボルを束縛できる
• (define plus1 (lambda (n) (+ n 1)))
• これでplus1というシンボルを使って関数呼び出しができます
• (plus1 29)→30
関数
• (lambda (仮引数...) 式...)
• 仮引数は束縛変数とも呼ばれ,その関数内でのみ参照できます
• つまり,束縛変数のスコープはその関数内ということです
• 対して,どこでも参照できる変数を大域変数といいます
• 束縛変数の,大域変数に対応する呼び方として,
• 局所変数という呼び方もあります
• 関数は,環境を新たに作ることで,束縛変数を実現しています
関数
環境 x=10 y=20 … … …
((lambda (x y) (+ x y)) 2 3)
束縛
新たな環境 x=2 y=3
参照
LISPの構文3
Let It Be
let
• 局所変数を定義するために,let特殊オペレータを使います
• (let ((a 2) (b 3)) (+ a b))→5
• 簡単ですね
• let特殊オペレータは新たに環境を作ります
let
環境 x=10 y=20 … … …
(let ((x 2) (y 3)) (+ x y))
束縛
新たな環境 x=2 y=3
参照
lambdaの時とそっくりですね
let
• letはlambdaの構文糖衣として考えることができます
• つまり,letはlambdaと等価です
• (let ((a 2) (b 3)) (+ a b))
• ((lambda (a b) (+ a b)) 2 3)
構文糖衣
• syntax-sugerの訳語
• Wikipediaには,次のように書いてあります
糖衣構文(とういこうぶん)は、プログラミング言語において、読み
書きのしやすさのために導入される構文であり、既に定義されている
他の構文の(人間にとってより理解しやすい)書換えとして定義され
るもののことである。構文糖(こうぶんとう)あるいは構文糖衣とも
いう。
構文糖衣
• quoteの構文糖衣として,「’」があります
• また,関数と定義するときの構文糖衣として,次のように書けます
• (define hoge (lambda (foo) (bar baz)))
• (define (hoge foo) (bar baz))
• どちらも正しい関数定義です
スコープ
ちょっと脱線
スコープ
• 関数の説明の時にも出てきました
• その変数が見えている(=参照可能な)範囲のことです
• トップレベルでdefineすると,変数のスコープはグローバルに
• 関数の仮引数やletで定義された変数のスコープは,ローカルに
なります
• また,Schemeは,レキシカルスコープと呼ばれる種類のスコープ
を持ちます
レキシカルスコープ
• 字句的,構文,静的スコープなどともいいます
• これによってクロージャ(関数閉包)というものを成します
• x
• test
• 100
• 100
• (define x 100)
• (define (test) x)
• (test)
• (let ((x 10)) (test))
レキシカルスコープ
式(プログラム) 評価結果(実行後)
クロージャ
骨を折ります
クロージャ
• Schemeにおいて,クロージャは無名関数と同義であるといえます
[要出典]
• カプセル化や遅延評価などのためによく使います
• counter
• c1
• 1
• 2
• 3
• (define (counter)
(let ((c 0))
(lambda ()
(set! c (+ c 1))
c)))
• (define c1 (counter))
• (c1)
• (c1)
• (c1)
クロージャ
式(プログラム) 評価結果(実行後)
副作用
副作用使用罪だ!!
副作用
• set!は副作用をもたらす特殊オペレータです
• その他,displayなども副作用をもたらします
• 破壊的代入やI/O制御は副作用を伴います
再帰
私に還りなさい
再帰
• あるものについて記述する際に、記述しているものそれ自身への参
照が、その記述中にあらわれることをいう(Wikipediaより)
• 再帰的に関数を呼び出すことを再帰呼び出しといいます
• ある関数のなかでその関数が呼び出されているとき,
それは再帰関数であるといえます
• fact
• 120
• (define (fact n)
(if (= n 0) 1
(* n (fact (- n 1))))
• (fact 5)
再帰関数
式(プログラム) 評価結果(実行後)
末尾再帰
• 関数の末尾文脈での関数呼び出しは末尾呼び出しと呼ばれます
• 再帰的な末尾呼び出しを末尾再帰といいます
• Schemeでは,末尾呼び出しが最適化されます
• ループ構造と等価なものに展開され,スタックを消費しないものに
なります
• 非常に簡単にいうと,無駄が少ないです
• (define (fact n)
(fact-tc n 1))
• (define (fact-tc n m)
(if (= n 0) m
(fact-tc (- n 1)
(* n m))))
• (define (fact n)
(if (= n 0) 1
(* n (fact (- n 1))))
末尾再帰
非末尾再帰版fact 末尾再帰版fact
非末尾再帰版fact関数呼び出し
(fact 5)
(* 5 (fact 4))
(* 5 (* 4 (fact 3)))
(* 5 (* 4 (* 3 (fact 2))))
(* 5 (* 4 (* 3 (* 2 (fact 1)))))
(* 5 (* 4 (* 3 (* 2 (* 1 (fact 0))))))
(* 5 (* 4 (* 3 (* 2 (* 1 1)))))
非末尾再帰版fact関数呼び出し
(* 5 (* 4 (* 3 (* 2 (* 1 1)))))
(* 5 (* 4 (* 3 (* 2 1))))
(* 5 (* 4 (* 3 2)))
(* 5 (* 4 6))
(* 5 24)
120
末尾再帰版fact関数呼び出し
(fact 5)
(fact-tc 5 1)
(fact-tc 4 5)
(fact-tc 3 20)
(fact-tc 2 60)
(fact-tc 1 120)
(fact-tc 0 120)
120
LISPの構文4
Let It Be再び
named-let
• 名前付きletというもので,ループを上手く書くことができます
named-letを使ったfact関数
• (define (fact n)
(let rec ((a n) (b 1))
(if (= a 0) b
(rec (- a 1) (* a b)))))
• letrecを使って似たように定義ができます
高階関数
今でもあなただけが 青春の...
高階関数
• 関数を引数として取ったり,返り値として返したりする関数
map関数
• リストの各要素にマッピング
• (map func list0 list1 ... listN)
sort関数
• リストの要素をソート
• (sort lst func)
fold関数
• 畳み込み
演習
このセクションを書こうとした人は途中で寝てしまいました。
適当に演習
参考
• 今回このスライドを作るにあたって,
http://lyrical.bugyo.tk/ (魔法言語 リリカル☆Lisp)
を参考にしました
• 非常に良い教材です
終

More Related Content

PPTX
(Lambdaだけで) 純LISPのような ナニかを作る
KEY
ラムダ計算入門
PDF
関数プログラミング入門
PPTX
純粋関数型アルゴリズム入門
KEY
Algebraic DP: 動的計画法を書きやすく
PDF
たのしい高階関数
KEY
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
ODP
(define)なしで再帰関数を定義する
(Lambdaだけで) 純LISPのような ナニかを作る
ラムダ計算入門
関数プログラミング入門
純粋関数型アルゴリズム入門
Algebraic DP: 動的計画法を書きやすく
たのしい高階関数
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
(define)なしで再帰関数を定義する

What's hot (20)

PDF
Freer Monads, More Extensible Effects
ODP
Real World OCamlを読んでLispと協調してみた
PDF
たのしい関数型
PDF
Scala 初心者が米田の補題を Scala で考えてみた
PDF
あなたのScalaを爆速にする7つの方法(日本語版)
PDF
Thinking in Cats
PDF
Scala 初心者が Hom 函手を Scala で考えてみた
PDF
これから Haskell を書くにあたって
PDF
Material
PDF
Haskell超入門 Part.1
PDF
Introduction to Categorical Programming
PDF
関数型プログラミング入門 with OCaml
PDF
Introduction to Categorical Programming (Revised)
PDF
Haskell勉強会 in ie
PPTX
IdrisでWebアプリを書く
PDF
Extensible Eff Applicative
PDF
Scalaで型クラス入門
PDF
はてなブックマーク in Scala
PDF
Scala の関数型プログラミングを支える技術
PDF
2011年11月11日
Freer Monads, More Extensible Effects
Real World OCamlを読んでLispと協調してみた
たのしい関数型
Scala 初心者が米田の補題を Scala で考えてみた
あなたのScalaを爆速にする7つの方法(日本語版)
Thinking in Cats
Scala 初心者が Hom 函手を Scala で考えてみた
これから Haskell を書くにあたって
Material
Haskell超入門 Part.1
Introduction to Categorical Programming
関数型プログラミング入門 with OCaml
Introduction to Categorical Programming (Revised)
Haskell勉強会 in ie
IdrisでWebアプリを書く
Extensible Eff Applicative
Scalaで型クラス入門
はてなブックマーク in Scala
Scala の関数型プログラミングを支える技術
2011年11月11日
Ad

Similar to Lisp講義1 (20)

PDF
なぜリアクティブは重要か #ScalaMatsuri
PDF
実務者のためのかんたんScalaz
PDF
Why Reactive Matters #ScalaMatsuri
KEY
Objc lambda
PDF
PythonでLispを実装した (evalつき)
PDF
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
PDF
JavaScript 講習会 #1
PDF
Rubyの御先祖CLUのお話(原本)
PDF
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
PDF
第2回 JavaScriptから始めるプログラミング2016
PDF
Lisp study
PPTX
関数型言語&形式的手法セミナー(3)
PDF
自然言語処理に適した ニューラルネットのフレームワーク - - - DyNet - - -
PPT
Pythonintro
KEY
第3回BDD勉強会
PPT
Or seminar2011final
PDF
型プロファイラ:抽象解釈に基づくRuby 3の静的解析
PDF
C++コミュニティーの中心でC++をDISる
PDF
HiRoshimaR3_IntroR
PDF
Matlab演習
なぜリアクティブは重要か #ScalaMatsuri
実務者のためのかんたんScalaz
Why Reactive Matters #ScalaMatsuri
Objc lambda
PythonでLispを実装した (evalつき)
関数モデル 【クラウドアプリケーションのためのオブジェクト指向分析設計講座 第8回】
JavaScript 講習会 #1
Rubyの御先祖CLUのお話(原本)
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
第2回 JavaScriptから始めるプログラミング2016
Lisp study
関数型言語&形式的手法セミナー(3)
自然言語処理に適した ニューラルネットのフレームワーク - - - DyNet - - -
Pythonintro
第3回BDD勉強会
Or seminar2011final
型プロファイラ:抽象解釈に基づくRuby 3の静的解析
C++コミュニティーの中心でC++をDISる
HiRoshimaR3_IntroR
Matlab演習
Ad

More from stibear (stibear1996) (7)

PDF
EROSについて
PDF
Lisp on Lisp
PDF
PDF
灘校パソコン研究部(NPCA)におけるLispの活用について
PDF
IMのはなし
PDF
PXE @第一回成果報告会(2012/12/17)
ODP
しがないLisperのつまらないLT
EROSについて
Lisp on Lisp
灘校パソコン研究部(NPCA)におけるLispの活用について
IMのはなし
PXE @第一回成果報告会(2012/12/17)
しがないLisperのつまらないLT

Lisp講義1