人生は勉強ブログ

https://github.com/dooooooooinggggg

Common Lispの基礎的な文法5

あくまで自分用のメモ。

今後の実装の時に、簡単に振り返るための記事。

進めている本は、Land Of Lisp

Land of Lisp

Land of Lisp

前回の記事の続き。

www.ishikawa.tech

少し順番がおかしいが、今回の記事では、structgeneric周りについてやっていく。これは、本では9章に書いてある内容。

struct

Lispにも構造体というデータ構造は存在する。

(defstruct person
    name
    age
    waist-size
    favorite-color)

上のように、構造体を定義できる。

この構造体を利用するには、以下のように、defparameterを用いる。

(defparameter *bob* (make-person :name "Bob"
        :age 35
        :waist-size 32
        :favorite-color "blue"))

ここで注目なのが、make-personpersonの部分は構造体に合わせて動的に生成される、という点。

動的すぎて、不安になる。

generic

この章で扱うのは、データをgenericに扱うためのもの

例えば、リストか配列に入っている数値のグループを足し合わせたい。

こう言った際に、同じ機能のものを型の違い、つまりデータの取り出し方の違いだけで、複数書かないとダメなのか。となる。

当然そんなことはなく、lispには値をgenericに扱うための機構がいくつも用意していある。

例として、ジェネリックライブラリ関数、型述語、defmethod、ジェネリックアクセサなど。

これらの機能を使うと、defstructで作られたユーザー定義型に関しても、一つのコードで対応できるようになる。

まず、引数の型によらないコードを書くことを考えるが、この場合は、データのチェックを他の誰かにやってもらうのが楽。

そこで、もっともよく使われるのは、シーケンス関数

そのうちの一つが、length関数。 これはいろんな型を取れる。

これはどういうことかというと、型によって、処理を書き分けることができるようになる、ということ。

例えば、listが渡ってきた場合はその要素数を返すが、文字列が渡ってきた場合、文字数を返す、など。

reduce関数

これらのシーケンス関数の中でも、特に便利なものの一つがreduce関数。

(reduce #'+ '(3 4 6 5 2))

;; これあんまり意味がわからん ;; lambdaに、リストを渡している

(reduce (lambda (best item)
        ;; 偶数で、かつ、item > bestだった場合
        (if (and (evenp item) (> item best))
            item
            best))
    '(7 4 6 5 2)
    :initial-value 0)

(defun sum (lst)
    (reduce #'+ lst))

(sum '(1 2 3))

(sum (make-array 5 :initial-contents '(1 2 3 4 5)))

map

mapは、今までのmapcarとほぼ同じ動作をする。

違いは、前者は、いろいろ受け取れるのに対して、mapcarは、リストしか扱えない

(map 'list
    (lambda (x)
        (if (eq x #\s)
            #\S
            x))
    "This is a string")