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

*princ

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 !)

*defvardefparameter


テクニック

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」となる。
f:id:h0sw:20160124121907p:plain
(本に掲載されている図とは違います)
(追記)
この図で最後にnilを書いてしまったが、必ずしもnilでなくても良いようだ。
そして、nilでない場合にコンスセルの表現になるようだ。

スロット

 コンスセルを構成する2つの箱?それぞれのこと

リストを扱う関数

リスト
 二つの要素をつなげるセルがただただ長く連なったもの

cons

 二つのデータを結びつけ、コンスセルを返す
 これを繰り返し使うとリストになる
例.

(cons 'chicken 'cat)
(chicken . cat)

真ん中の「.」は何か?これがコンスセルであることを示すらしい。
リストとは違うらしい。でも、結局リストと同じらしい??
つまり、リスト(pork beef chicken)のコンス表現が(pork . (beef . (chicken . ())))らしい。
でも、そもそもシンボルのリストってどんな時に役に立つのだろう?
読み進めるとわかるかな?

car

  最初のスロットにあるデータを取り出す
例.

(car '(pork beef chicken))
pork

因みに例の「'」をつけずに試すと
f:id:h0sw:20160130141158p:plain
と表示されます。これがシンボルとして評価されていないということですかね。

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

*defun参照

こんな使い方が正しいのか、これから本を読み進めるうちにわかると思います。
(違っていることがわかったら急いで修正予定)


ローカル関数定義をもう一つ

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|と言語指定できるのは、どこの記事でも指摘されているとおりです。
はてな記法一覧 - はてなダイアリーのヘルプ