by shigemk2

当面は技術的なことしか書かない

Land of Lisp 6章 メモ

Land of Lisp

第6章

  • ユーザーインターフェース/コマンドラインインタフェース

6.1 テキストの表示と読み込み

print vs prin1

[1]>  (print "foo")

"foo"
"foo"
[2]>  (progn (print "this")
 (print "is")
 (print "a")
 (print "test"))

"this"
"is"
"a"
"test"
"test"
[3]> (progn (prin1 "this")
 (prin1 "is")
 (prin1 "a")
 (prin1 "test"))
"this""is""a""test"
"test"

read

その1

[4]> (defun say-hello ()
  (print "Please type your name:")
  (let ((name (read)))
    (print "Nice to meet you, ")
    (print name)))
SAY-HELLO
[5]> (say-hello)

"Please type your name:" shigemk2

"Nice to meet you, "
SHIGEMK2
SHIGEMK2

その2

[6]> (defun add-five ()
  (print "please enter a number:")
  (let ((num (read)))
    (print "When I add five I get")
    (print (+ num 5))))
ADD-FIVE
(add-five)

[7]>
(add-five)

"please enter a number:" 3

"When I add five I get"
8
8
[8]> (add-five)

"please enter a number:" hoge

"When I add five I get"
*** - +: HOGE is not a number
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead.
ABORT          :R2      Abort main loop
Break 1 [9]> :q

princ

[10]> (princ '3)
3
3
[11]> (princ '"foo")
foo
"foo"

printと違ってダブルクオートは出ない

[12]> (defun say-hello ()
  (princ "Please type your name:")
  (let ((name (read-line)))
    (princ "Nice to meet you, ")
    (princ name)))
SAY-HELLO
[13]> (say-hello)
Please type your name:test
Nice to meet you, test
"test"

6.2 Lisp におけるコードとデータの対称性

  • 同図象性
    • プログラムコードとデータを同じデータ構造を使って扱うプログラミング言語は、同図象性 を持つと言われる

自己書き換えプログラム

[15]>  (defparameter *foo* '(+ 1 2))
*FOO*
[18]> (eval *foo*)
3
  • 経験未熟なうちに eval を使うのはセキュリティ上の危険を招く可能性もある

6.3 ゲームエンジンに専用のインタフェースを追加する

loop/read/print

[49]> (defun game-repl ()
 (loop (print (eval (read)))))
GAME-REPL
[50]> (game-repl)
(look)

(YOU ARE IN THE LIVING-ROOM. A WIZARD IS SNORING LOUDLY ON THE COUCH. THERE IS A DOOR GOING WEST FROM HERE. THERE IS A LADDER GOING UPSTAIRS FROM HERE. YOU SEE A WHISKEY ON THE
 FLOOR. YOU SEE A BUCKET ON THE FLOOR.)
[20]> (defun tweak-text (lst caps lit)
  (when lst
    (let ((item (car lst))
          (rest (cdr lst)))
      (cond ((eql item #\space) (cons item (tweak-text rest caps lit)))
            ((member item '(#\! #\? #\.)) (cons item (tweak-text rest t lit)))
            ((eql item #\") (tweak-text rest caps (not lit)))
            (lit (cons item (tweak-text rest nil lit)))
            (caps (cons (char-upcase item) (tweak-text rest nil lit)))
            (t (cons (char-downcase item) (tweak-text rest nil nil)))))))
TWEAK-TEXT
(defun game-print (lst)
  (princ (coerce (tweak-text (coerce (string-trim "() "
                                                  (prin1-to-string lst))
                                     'list)
                             t
                             nil)
                 'string))
  (fresh-line))

[21]>
(defun game-print (lst)
  (princ (coerce (tweak-text (coerce (string-trim "() "
                                                  (prin1-to-string lst))
                                     'list)
                             t
                             nil)
                 'string))
  (fresh-line))
GAME-PRINT
[22]>  (game-print '(not only does this sentence have a "comma," it also mentions the "iPad."))
Not only does this sentence have a comma, it also mentions the iPad.
T

6.4 さあこの素敵なゲームインタフェースを試してみよう

[28]> (defun game-repl ()
  (let ((cmd (game-read)))
    (unless (eq (car cmd) 'quit)
      (game-print (game-eval cmd))
      (game-repl))))
GAME-REPL
[29]> (defun game-read ()
  (let ((cmd (read-from-string
              (concatenate 'string "(" (read-line) ")"))))
    (flet ((quote-it (x)
                     (list 'quote x)))
      (cons (car cmd) (mapcar #'quote-it (cdr cmd))))))
GAME-READ
[30]> (defparameter *allowed-commands* '(look walk pickup inventory))
*ALLOWED-COMMANDS*
(defun game-eval (sexp)
  (if (member (car sexp) *allowed-commands*)
      (eval sexp)
    '(i do not know that command.)))

[31]>
(defun game-eval (sexp)
  (if (member (car sexp) *allowed-commands*)
      (eval sexp)
    '(i do not know that command.)))
GAME-EVAL
[32]> (defun tweak-text (lst caps lit)
  (when lst
    (let ((item (car lst))
          (rest (cdr lst)))
      (cond ((eql item #\space) (cons item (tweak-text rest caps lit)))
            ((member item '(#\! #\? #\.)) (cons item (tweak-text rest t lit)))
            ((eql item #\") (tweak-text rest caps (not lit)))
            (lit (cons item (tweak-text rest nil lit)))
            (caps (cons (char-upcase item) (tweak-text rest nil lit)))
            (t (cons (char-downcase item) (tweak-text rest nil nil)))))))
TWEAK-TEXT
(defun game-print (lst)
  (princ (coerce (tweak-text (coerce (string-trim "() "
                                                  (prin1-to-string lst))
                                     'list)
                             t
                             nil)
                 'string))
  (fresh-line))

[33]>
(defun game-print (lst)
  (princ (coerce (tweak-text (coerce (string-trim "() "
                                                  (prin1-to-string lst))
                                     'list)
                             t
                             nil)
                 'string))
  (fresh-line))
GAME-PRINT
[34]> (game-repl)
look
You are in the living-room. A wizard is snoring loudly on the couch. There is a door going west from here. There is a ladder going upstairs from here. You see a bucket on the
 floor.
walk west
You are in a beautiful garden. There is a well in front of you. There is a door going east from here. You see a frog on the floor. You see a chain on the floor.
pickup chain
You are now carrying the chain
scratch head
I do not know that command.
pickup chicken
You cannot get that.
walk west
You cannot go that way.
walk east
You are in the living-room. A wizard is snoring loudly on the couch. There is a door going west from here. There is a ladder going upstairs from here. You see a bucket on the
 floor.
walk upstairs
You are in the attic. There is a giant welding torch in the corner. There is a ladder going downstairs from here.
inventory
Items- whiskey chain
walk downstairs
You are in the living-room. A wizard is snoring loudly on the couch. There is a door going west from here. There is a ladder going upstairs from here. You see a bucket on the
 floor.
pickup bucket
You are now carrying the bucket
look
You are in the living-room. A wizard is snoring loudly on the couch. There is a door going west from here. There is a ladder going upstairs from here.
quit
NIL

6.5 read と eval の危険について

readとかevalとか使っていると高度なテクニックをつかうと邪悪なコードが実行できてしまう

[35]>  (game-repl)
format-harddrive
I do not know that command.
 walk (format-harddrive)
You cannot go that way.
 walk (format-harddrive)
You cannot go that way.
walk #.(format-harddrive)

*** - EVAL: undefined function FORMAT-HARDDRIVE
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of (FDEFINITION 'FORMAT-HARDDRIVE).
RETRY          :R2      Retry
STORE-VALUE    :R3      Input a new value for (FDEFINITION 'FORMAT-HARDDRIVE).
ABORT          :R4      Abort main loop
Break 1 [36]> :q

まとめ

  • コンソールを通して人間とコミュニケート
    • printとread
    • princやread-lineとか
  • 同図象性
    • クオート
    • 準クオート
    • eval
    • マクロ
  • 自分でカスタマイズされた REPL
  • Lisp 内部のデータ表現を、プログラムのインタフェースにふさわしい形式に変形するのは難しくない
    • プログラム内部で使うデータ構造と、その表示形式とを分けて考えることができる

第6.5章

6.5.1 lambda がすること

プログラムを書いていて、他の関数に「その場限りの処理」を渡したいなと思った時に、lambdaはぴったり

[37]> (defun half (n)
 (/ n 2))
HALF
[38]>  (lambda (n) (/ n 2))
#<FUNCTION :LAMBDA (N) (/ N 2)>
[39]>  (mapcar (lambda (n) (/ n 2)) '(2 4 6))
(1 2 3)

6.5.2 lambda がそんなに大事なわけ

  • Lisp は普通の言語と違い、ラムダ算法という数学的な概念から直接導かれたプログラミング言語
  • lambda形式は Lisp システムの中で最も根源的なコマンドで、Lisp の他の関数は lambdaの概念を元に導かれている

まとめ

  • lambda
  • 高階プログラミング

Land of Lisp

Land of Lisp

Land of Lisp 1章-2章 メモ

勉強会1章-2章(社内)のメモ

はじめに

Lispはすごい

(+ 3 (* 2 4))

Lispを使っている企業(たぶんドメイン名前解決できていない) http://snipurl.com/e3lv9/

なぜLispが学ばれないか

人は以下の様なものを学びたがる。

  • 他のみんなが学んでるもの(微積分とか C++ とか)
  • 簡単に学べるもの(フラフープとか Ruby とか)
  • 学んだことの価値が簡単にわかるもの(核融合物理学とか、あるいは指を口に入れてとんでもなく大きな音を出せる口笛とか)

そして、Lispはそのどれにも属さないが、本気でプログラミングを学びたい人にとっては、Lispは良い経験になるだろう

Lisp はどこから来たのか

ほぼ省略。

  • ENIACとかのスイッチ
  • アセンブラ
  • Lisp/FORTRAN/C/COBOL
  • C++/Java

アセンブラ高級言語説。

Lisp の力はどこから来るのか

Lispは以下の点で、パワフルな言語である。

  1. 言語にたくさんの機能が最初から組み込まれている
  2. 言語の内部の深いところまで手を入れて、それによって自分のやりたいことを言語にさせられるようにできる

これらの性質は、時に相反する性質であり、とくにJavaやCだとすごく大変。

第1部 Lispは力なり

第1章 さあLispを始めてみよう

  • Common Lisp/Scheme

Guile/Clisp

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 (2010-07-07) <http://clisp.cons.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]> (+ 3 (* 2 4))
11
[2]>
  • Common Lisp と Scheme がLisp二大方言。本書ではCommon Lispを扱う
  • Common Lisp はマルチパラダイム言語であり、様々なプログラミング手法をサポートする。
  • CLISP は Common Lisp の実装の一つで、簡単にインストールできる。(yum install -y clisp/brew install clisp)
  • CLISP の REPLで簡単にごにょごにょ出来る。
  • 入力を間違えてCLISPが訳の分からない動作を始めたら、:qで直る。

第2章 はじめての Lisp プログラム

グローバル変数

defparameterでグローバル変数を定義できる

[1]> (defparameter *small* 1)
*SMALL*
[2]> (defparameter *big* 1)
*BIG*

変数再定義(defparameter)

[4]> (defparameter *foo* 5)
*FOO*
[5]> *foo*
5
[6]> (defparameter *foo* 6)
*FOO*
[7]> *foo*
6

グローバル変数(defvar)

[1]> (defvar *foo* 5)
*FOO*
[2]> *foo*
5
[3]> (defvar *foo* 6)
*FOO*
[4]> *foo*
5

Lispのエチケット

[5]> (defparameter *small* 1)
*SMALL*
-- こういう方法もできちゃう
[6]>  ( defparameter
 *small* 1)
*SMALL*
[7]> *small*
1

グローバル関数定義

(use defun)

[11]> (ash 11 1)
22
[12]> (ash 11 2)
44
[13]> (ash 11 3)
88
[14]> (ash 11 -1)
5
[15]> (defparameter *small* 1)
*SMALL*
[16]> (defparameter *big* 100)
*BIG*
[17]> (defun guess-my-number()
         (ash (+ *small* *big*) -1))
GUESS-MY-NUMBER
[18]> (guess-my-number)
50
[19]> (defun smaller ()
    (setf *big* (1- (guess-my-number)))
    (guess-my-number))
SMALLER
[20]> (defun bigger ()
    (setf *small* (1+ (guess-my-number)))
    (guess-my-number))
BIGGER
[21]> (bigger)
75
[22]> (smaller)
62
[23]> (smaller)
56

let/flet/labels

  • ローカル変数にはlet/ローカル関数にはflet
  • 自分自身を呼び出せるローカル関数はlabels
[26]> (labels ((a (n)
(+ n 5))
(b (n)
(+ (a n) 6)))
(b 10))
21
[27]> (flet ((a (n)
(+ n 5))
(b (n)
(+ (a n) 6)))
(b 10))

*** - EVAL: undefined function A
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of (FDEFINITION 'A).
RETRY          :R2      Retry
STORE-VALUE    :R3      Input a new value for (FDEFINITION 'A).
ABORT          :R4      Abort main loop
Break 1 [28]> :q

letとflet

[37]> (let ((a 5)
(b 6))
(+ a b))
11
[38]> (flet ((a 5)
(b 6))
(+ a b))

*** - FUNCTION: lambda-list for A should be a list, not 5
The following restarts are available:
ABORT          :R1      Abort main loop
Break 1 [39]> :q
[43]> (let (a 3))

*** - LET: illegal variable specification 3
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead.
ABORT          :R2      Abort main loop
Break 1 [44]> :q
[45]> (let ((a 5) (b 6)))
NIL
[46]> (let ((a 5) (b 6)) (+ a b))
11

Lispの呪い

The Lisp Curse

Scala - Qiita

Lisp is so powerful that problems which are technical issues in other programming languages are social issues in Lisp.

Lispは強力すぎてなんでも出来てしまうから、プログラマのコミュニティができづらい、という話。

Scalaだとそういうことが起きないような設計にしているという話。

Mac OS XでCommon Lispの環境を作る (homebrew + emacs)

homebrewでclispを入れるのをやってみた。

その1 CLISPを入れる

$ brew install clisp

対話によるCommon Lisp入門 1 - by shigemk2

その2 SLIMEを入れる(EmacsニオケルCommon Lisp実行環境)

$ cvs -d :pserver:anonymous:anonymous@common-lisp.net:/project/slime/cvsroot co slime

ダウンロードしたファイルを/Applicationsディレクトリにコピー。
そして以下を.emacsに記述。

;; slime
(setq inferior-lisp-program "/usr/local/bin/clisp")
(add-to-list 'load-path "/Applications/slime")
(require 'slime)
(slime-setup)

Emacs再起動→ M-x slimeで新しい世界が開けると思うよ?

SLIME: The Superior Lisp Interaction Mode for Emacs
Mac OS XでCommon Lispの実行環境を作る(CLISP + Carbon Emacs + SLIME) - qnzm.log(クニジマログ)