Land Of Lisp 第4章 (比較関数の実施例)
例.xyzzyでの実施例
eqはシンボルだけと言いながら意外と比較しています。取りあえず、使い分けはしようと思いますが。
;シンボル (equalp 'a 'a) t (equal 'a 'a) t (eql 'a 'a) t (eq 'a 'a) t (= 'a 'a) 不正なデータ型です: a: number (string-equal 'a 'a) t (char-equal 'a 'a) 不正なデータ型です: a: character ;リスト (equalp (list 1 2) (list 1 2)) t (equal (list 1 2) (list 1 2)) t (eql (list 1 2) (list 1 2)) nil (eq (list 1 2) (list 1 2)) nil (= (list 1 2) (list 1 2)) 不正なデータ型です: (1 2): number (string-equal (list 1 2) (list 1 2)) 不正なデータ型です: (1 2): string (char-equal (list 1 2) (list 1 2)) 不正なデータ型です: (1 2): character ;コンス (equalp (cons 2 3) (cons 2 3)) t (equal (cons 2 3) (cons 2 3)) t (eql (cons 2 3) (cons 2 3)) nil (eq (cons 2 3) (cons 2 3)) nil (= (cons 2 3) (cons 2 3)) 不正なデータ型です: (2 . 3): number (string-equal (cons 2 3) (cons 2 3)) 不正なデータ型です: (2 . 3): string (char-equal (cons 2 3) (cons 2 3)) 不正なデータ型です: (2 . 3): character ;数字(整数) (equalp 1 1) t (equal 1 1) t (eql 1 1) t (eq 1 1) t (= 1 1) t (string-equal 1 1) 不正なデータ型です: 1: string (char-equal 1 1) 不正なデータ型です: 1: character ;数字(整数と小数) (equalp 1 1.0) t (equal 1 1.0) nil (eql 1 1.0) nil (eq 1 1.0) nil (= 1 1.0) t (string-equal 1 1.0) 不正なデータ型です: 1: string (char-equal 1 1.0) 不正なデータ型です: 1: character ;文字列 (equalp "aa" "aa") t (equal "aa" "aa") t (eql "aa" "aa") nil (eq "aa" "aa") nil (= "aa" "aa") 不正なデータ型です: "aa": number (string-equal "aa" "aa") t (char-equal "aa" "aa") 不正なデータ型です: "aa": character ;文字列(大文字と小文字) (equalp "AA" "aa") t (equal "AA" "aa") nil (eql "AA" "aa") nil (eq "AA" "aa") nil (= "AA" "aa") 不正なデータ型です: "AA": number (string-equal "AA" "aa") t (char-equal "AA" "aa") 不正なデータ型です: "AA": character ;文字 (equalp #\a #\a) t (equal #\a #\a) t (eql #\a #\a) t (eq #\a #\a) t (= #\a #\a) 不正なデータ型です: #\a: number (string-equal #\a #\a) t (char-equal #\a #\a) t
Land Of Lisp 第4章
ここは条件文の章
if
条件文ifで空リストのみ偽と判定空リストの表現は4つある
例. '() () 'nil nil
(eq '() nil) t (eq '() ()) t (eq '() 'nil) t
例. 条件判定の例 リストの長さ
(defun my-length (list) (if list (1+ (my-length (cdr list))) 0)) my-length (my-length '(list with four symbols)) 4
listが変数名に使われていたが、
普通に使えるみたい。
その他条件の書き方
; 数値が等しい? (= 1 2) nil (= 1 1) t ; 奇数? (oddp 5) t ; 偶数? (evenp 5) nil
progn
if文の1つの分岐で複数の処理を実施例.
(if (oddp 5) (progn (setf *a* (+ 5 1)) 'odd) 'even) odd *a* 6
when
条件が真の場合に複数の処理を実施(暗黙のprogn)条件を見たさない場合はnilを返す。
例.
(when (oddp 5) (setf *b* 5) 'odd) odd *b* 5 (when (oddp 4) (setf *b* 5) 'odd) nil
unless
条件が偽の場合に複数の処理を実施(暗黙のprogn)条件を見たさない場合はnilを返す。
例.
(unless (oddp 4) (setf *c* 4) 'even) even *c* 4 (unless (oddp 5) (setf *c* 4) 'even) nil
cond
色々できる条件分岐例.偶数の数を返す(自作)
(defun make-even-number (num) (cond ((oddp num) (princ num) (princ " to ") (princ (+ num 1))) (t (princ num) (princ " is even number!")))) make-even-number (make-even-number 10) 10 is even number! " is even number!" (make-even-number 9) 9 to 10 10
t
真case
ほかの言語でもよく見るcase比較にはeqlが使われるので文字列では比較できないらしい。
例.
(defun what-is-in (x) (case x ((1) '(1 is in x)) ((A) '(A is in x)) (("A") '(""A"" is in x)) (otherwise '(what is this !)))) what-is-in (defvar *x* 1) *x* (what-is-in *x*) (1 is in x) (defparameter *x* 'A) *x* (what-is-in *x*) (A is in x) (defparameter *x* "A") *x* (what-is-in *x*) (what is this !)
テクニック
andとor
例.(and t t nil) nil (and t t t) t (or t t nil) t (or t t t) t
これらは、C#の短絡評価のように働く
例.
(or (oddp 4) '(it is even)) (it is even) (or (oddp 5) '(it is odd)) ; 後半は評価されない t (and (oddp 4) '(it is even)) ; 後半は評価されない nil (and (oddp 5) '(it is odd)) (it is odd)
こらは、できるというだけで真偽判定と処理は分けて書くのがよい。
member
リストの中に要素が含まれるか調べる返すのは見つかった要素以降の部分リスト
例.nil以外は真とみなされる
(if (member 1 '(3 4 1 5)) 'in 'no) in (member 1 '(3 4 1 5) (1 5)
find-if
条件付き検索関数には「#」をつける
例.
(find-if #'oddp '(2 4 5 6)) 5 ; ただしnullを使う場合は注意 (if (find-if #'null '(2 4 nil 6)) 'a 'b) b
比較関数
eq
シンボル同士の比較早い
equal
シンボル以外の比較eql
数値と文字を比較する(できる)equalp
文字の大小を区別しない、数値の整数、小数を区別しない、で比較する
=
数値の比較string-equal
文字列の比較char-equal
文字の比較無線LANアダプタリセット FMV MG75X
FMV MG75XをWindows 8.1にした時から起動時に無線LANがつながらないことが偶にありました。
その都度、タスクバーの無線マーク(?)を右クリックし、「問題のトラブルシューティング」をしていました。
Windows10にすると直るかと思いましたが、相変わらずです。
いい加減面倒なので、起動時常にアダプタのリセットする方法をネットで探しました。
まず、バッチファイルを作成します。
netsh interface set interface "Wi-Fi" disable netsh interface set interface "Wi-Fi" enabled
次に、管理者として実行しなければいけないのですが、
方法1.ショートカットを作成し、管理者として実行する
①プロパティ
②詳細設定(D)
③詳細プロパティで「管理者として実行(R)」にチェックを付ける
方法2.もう一つバッチファイルを作成し呼び出す
内容
powershell.exe -Command Start-Process """フルパスで先に作ったファイル名記述""" -Verb Runas
これで、リセットが楽になりました。
Land Of Lisp 第3章
3章はLispの構成についての説明
シンタックス
文を構成する基本的規則Lispは括弧を使ってコードをリストにする。
セマンティック
文の意味[Lispの構成要素]
シンボル
最も基本的なデータ型アルファベット、数字、+-/*=<>?!_が使用可能
Common Lispは大小の区別はないというが、xyzzyでは
(eq 'fooo 'FoOo) nil
と区別があるようだ。
シンボルとは、変数名や関数名を指しているのだろうか?
これは何を比較しているのか今のところ理解できない。
(因みに、多くのLisperは大文字を使わないらしい)
数値
浮動小数点、整数expt
冪乗例.53の53乗
(expt 53 53) 24356848165022712132477606520104725518533453128685640844505130879576720609150223301256150373
例.分数(約分までしてくれる)
(/ 4 6) 2/3
ただし、小数を含む計算は結果も小数となる。
文字列
ダブルクオートで囲むエスケープ文字も使用可能だが、種類は"と¥のみ
princ
文字列を表示例.
(princ "Tutti Frutti") Tutti Frutti "Tutti Frutti"
最初の「Tutti Frutti」はprincの結果、2つ目はREPLが入力された式の結果を返したもの
コードモード
REPLの標準モード入力された文字列をコマンドとして解釈し実行
フォーム
コードモードの入力が満たすべき構造最初の要素が特別のコマンドになっているリスト、残りの要素はすべて引数
例.ネストしたフォーム
(expt 2 (+ 3 4)) 128
データモード
入力された文字列を実行しないモード先頭に「'」をつけてあらわす。シンボルの例参照
リスト
Lispコードの構成方法例えば、関数と引数を括弧で括った構造
コンスセル
リストをつなぎ合わせる構造ポインタが2つくっ付いたイメージ
例えば、リスト'(1 2 3)は「1」、「2」、「3」という値がメモリ上にあり
コンスセル①の1つ目のポインタが「1」を指し、2つ目のポインタが、
「2」を指すコンスセル②を指す。
そして、コンスセル②の2つ目のポインタが「3」を指すコンスセル③を指す。
コンスセル③の2つ目のポインタはどこもささず終端「nil」となる。
(本に掲載されている図とは違います)
(追記)
この図で最後にnilを書いてしまったが、必ずしもnilでなくても良いようだ。
そして、nilでない場合にコンスセルの表現になるようだ。
スロット
コンスセルを構成する2つの箱?それぞれのことリストを扱う関数
リスト
二つの要素をつなげるセルがただただ長く連なったもの
cons
二つのデータを結びつけ、コンスセルを返すこれを繰り返し使うとリストになる
例.
(cons 'chicken 'cat) (chicken . cat)
真ん中の「.」は何か?これがコンスセルであることを示すらしい。
リストとは違うらしい。でも、結局リストと同じらしい??
つまり、リスト(pork beef chicken)のコンス表現が(pork . (beef . (chicken . ())))らしい。
でも、そもそもシンボルのリストってどんな時に役に立つのだろう?
読み進めるとわかるかな?
car
最初のスロットにあるデータを取り出す例.
(car '(pork beef chicken)) pork
因みに例の「'」をつけずに試すと
と表示されます。これがシンボルとして評価されていないということですかね。
cdr
2番目のスロットの値を取り出す。例.
(cdr '(pork beef chicken)) (beef chicken)
cadr
carとcdrの合成例.
(cadr '(pork beef chicken)) beef ;これは (car (cdr '(pork beef chicken))) beef ;おまけ (cddr '(pork beef chicken)) (chicken)
list
リストを作る(コンスセルを1つずつ作る処理をまとめたもの)例.
(list 'poke 'beef 'chicken) (poke beef chicken)
car、cdrを組み合わせたcdar、cddr、caddr、cddar、cadadrがあるらしい。
僕の覚え方は「r」の前の文字を右から「d」「a」を適用していく。
例えば、cadadrなら、あるリストに対して「d」(cdr)を適用し、その結果に「a」(car)を適用し...
(cadadr '(a (b (c d)) e)) (c d) (car (cdr (car (cdr '(a (b (c d)) e))))) (c d)
3章はここまで
Land Of Lisp 第2章 (その2)
ローカル定義に関してのメモ
let:ローカル変数を定義
例.(let ((a 5) (b 6)) (setf a 4) (+ a b)) 10
(a 5)、(b 6)が変数とその初期値、さらにこの宣言部を()で括る
(setf a 4)、(+ a b)が変数を使った処理
flet:ローカル関数の定義
例.(flet ((f (n) (+ n 10))) (f 5)) 15
fが関数名、nが引数、(+ n 10)が関数本体
ローカル変数と同様、これらの宣言部を()で括る
次の(f 5)が宣言した関数を使った処理
ここまでの内容でどのように使うのか、自分で考えてみました。
(defun gfunc (x) (let ((a 5)) (flet ((lfunc (n) (+ n a 10))) (lfunc x)))) gfunc (gfunc 10) 25こんな使い方が正しいのか、これから本を読み進めるうちにわかると思います。
(違っていることがわかったら急いで修正予定)
ローカル関数定義をもう一つ
labels:ローカル関数の定義
ローカル関数内のスコープで定義したローカル関数を使用できる例.
(labels ((a (n) (+ n 5)) (b (n) (+ (a n) 6))) (b 10)) 21
この例ではローカル関数aがローカル関数b内で使用されています。
後々、再帰のコードで使われることでしょう。
Land Of Lisp 第2章 (その1)
第2章からプログラムの説明に入っていきます。
数当てゲームを作りながら、Lispの説明がされています。
内容は、自分が考えた数をコンピューターが予想するもので、バイナリサーチでの実装です。
以下、この章で説明されている用語のメモ書きです。
REPL:real-eval-printループ(Loop) CLISPを起動後の入力待ちの状態
xyzzyも同様に起動すると即、Lispのコマンドなど入力できる(第1章に説明があったのですが、飛ばしてしまいました)
入力例です。(ブラウザの戻る機能でここに戻れます)
defparameter:トップレベル定義を作成する
例. *small* に「1」を設定。REPLは入力した式の値を返すようで、xyzzyでは小文字のまま表示される。本では大文字。(defparameter *small* 1) *small* *small* 1
ここで、*xx*は耳当てと呼ばれるらしい。Lisperと付き合うには必須
トップレベル定義:グローバルで定義される変数
グローバル変数は、ダイナミック変数、スペシャル変数とも呼ばれる。defvar:グローバル変数を定義。上書きはされない。
例.(defvar *small* 2) *small* *small* 1
これはどのような使い道があるのだろうか?
ネットで調べると「実用Common Lisp」のGoogleブック検索でちょっと中身が見れて、
defvarは初期値の設定、defparameterは値の変更のように書いてある。とりあえず、
今はこの程度の理解にしておく。(後でしっかり理解できるようになるかも)
defun:グローバル関数の定義
例.引数なしの場合(defun guess-my-number () (ash (+ *small* *big*) -1)) guess-my-number
(xyzzyは「)」を入力すると自動で対応する「(」を示してくれたり、インデントも自動で便利)
ash:算術シフト関数
いわゆるビットシフトで上記例では、右に1つシフト、つまり半分にして、小数部を切り捨てする。
ちなみにLispの整数に上限はないらしい。
さらにさらに、Lispは分数計算ができるらしい。
(+ 1/2 1/3) 5/6
setf:変数に値を代入
Common Lispでは、配列にも代入できるようです。ここまで、グローバルの定義でした。
おまけ
1+:1を足せ関数
引数に1を足す1-:1を引け関数
引数から1を引く例.
(1+ 3) 4 (1- 3) 2
はてな記法でソースコード挿入
Lispの学習過程をブログにしようと思い、ソースコードの書き方を調べたのですが、設定の編集モードで「はてな記法モード」をチェックし、
>||、||<でくくればいい、という記事が大半でした。
しかし、いくらやってもできませんでした。
要は一度、「見たままモード」で書き始めた記事には適用できないようでした。(書き始めた場合、記事をコピーして新たに記事を作成する)
まとめ
1.最初に設定→編集モードで「はてな記法モード」を選択
2.「編集 はてな記法」画面で、一行に >|| だけを入力し改行
3.ソースコードを貼り付け
4.一行に ||< だけを入力
これをプレビュー画面で見るときれいにソースコードが表示されます。
2で>|ruby|と言語指定できるのは、どこの記事でも指摘されているとおりです。
はてな記法一覧 - はてなダイアリーのヘルプ