Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-05-12

CLで学ぶ「プログラミングGauche」 (8〜8.2.5)

| 18:20 | CLで学ぶ「プログラミングGauche」 (8〜8.2.5) - わだばLisperになる を含むブックマーク はてなブックマーク - CLで学ぶ「プログラミングGauche」 (8〜8.2.5) - わだばLisperになる

今回は8章「真偽値と条件判断」から再開です。

8.1 述語と等価述語

CLでも「述語」とはいうような気がしますが、等価述語というのかは良く分かりません(^^;

8.2 等価性

8.2.1 内容が同じ

CLでequal?に相当するのは、equalで

(equal (list 1 2 3) (list 1 2 3))
;=> T

(equal (list 1 2 3) (cons 1 (list 2 (+ 1 1 1))))
;=> T

両者の型と値が同じならば等しいというところも同じです。

8.2.2 入れ物が同じ
(eq (cons 1 2) (cons 1 2))
;=> NIL

(let ((x (cons 1 2)))
  (eq x x))
;=> T

eq?に相当するものは、eqで、入れ物、つまり、LISPのオブジェクトとして等しい場合に真。ポインタの比較に喩えれるのも一緒で、確実に比較できるのは、シンボルのみというのも一緒。

また、シンボルについての説明で、同じ名前のシンボルは、同じ実体を指すというもの同じ。

しかし、CLの場合パッケージがあり、正確な名前はパッケージ名付きであることに注意する必要があります。

カレントパッケージとパッケージ名が同一の場合は、省略できるので、xはcl-user::xやfoo::x等、パッケージごとに複数存在可能です。

この場合、名前が違えば、全部違うオブジェクトかといえばそうでもなく、シンボルが外部パッケージから取り込まれている(importした)場合は、違うパッケージ名でもeqになることがあります。取り込んで来たオブジェクトなので、同一なオブジェクトであるのは自明ではありますが、ややこしいところでもあります。

8.2.3 数値として同じ
(eql 1 1)
;=> T

(eql 1.0 1.0)
;=> T

(eql 1 1.0)
;=> NIL

eqlは、型が同じで、値が同じならTというもの同じ

値を比較したい場合には、=を使うというのも同じ。

(= 1 1.0)
;=> T

文字の比較

(char= #\a #\a)
;=> T

(char= #\a #\A)
;=> NIL

(eql #\a #\a)
;=> T

HyperSpecには、

eql and equal compare characters in the same way that char= does.

とあるので、eqlとequalはchar=の機能としても使えるようです。

  • 文字列
(string= "abc" "abc")
;=> T

(string= "abc" "ABC")
;=> NIL
  • 大文字小文字の違いを無視したい場合
;; char-ci=?、string-ci=?
(char-equal #\a #\A)
;=> T

;; string=ci?
(string-equal "abc" "ABC")
;=> T

名前が若干違っています。-equalという風に冗長に書かなければいけない場合には、大文字小文字を区別しない、という命名規則です。

8.2.4 その他の等価性

isomorphic?はCLにはないので、探してみたのですが、みつからないので、Gaucheのを適当に移植してみました。といっても禄にテストしていないので、ちゃんと機能するのか不明です(^^;

(let ((p (cons 1 2)))
  (isomorphic? (list p p) (list p '(1 2))))
;=> nil

(let ((p (cons 1 2)))
  (isomorphic? (list p p) (list p p)))
;=> t

(let ((p (make-array 100 :fill-pointer 1 :adjustable 'T)))
  (vector-push 1 p)
  (isomorphic? p (vector 0 (+ 0 1))))
;=> t

;; 
(defun ISOMORPHIC? (a b &rest args)
  (let ((ctx (if (consp args)
                 (if (hash-table-p (car args))
                     (car args)
                     (error "hash table required, but got ~S." (car args)))
                 (make-hash-table))))
    (ISO? a b ctx)))

(defun ISO? (a b ctx)
  (let (win tem)
    (cond ((or (characterp a) (numberp a))
           (eql a b))
          ((null a) (null b))
          ((progn (setf (values tem win) (gethash a ctx))
                  win) ;node has been appeared
           (eq tem b))
          (:else
           (setf (gethash a ctx) b)
           (typecase a
             (cons (and (consp b)
                        (iso? (car a) (car b) ctx)
                        (iso? (cdr a) (cdr b) ctx)))
             (string (and (stringp b) (string= a b)))
             (keyword (eql a b))
             (symbol (eq a b))
             (vector (VECTOR-ISO? a b ctx))
             (otherwise (OBJECT-ISOMORPHIC? a b ctx))))))))

(progn
  (declaim (inline vector->list))
  (defun VECTOR->LIST (vec) (coerce vec 'list)))

(defun VECTOR-ISO? (a b ctx)
  (and (vectorp b)
       (do ((la (vector->list a) (cdr la))
            (lb (vector->list b) (cdr lb)))
           ((endp la) (endp lb))
         (cond ((endp lb) (return nil))
               ((ISO? (car la) (car lb) ctx))
               (:else (return nil))))))

(defmethod OBJECT-ISOMORPHIC? (a b context)
  (equal a b))
8.2.5 等価述語をとる手続き

(member-if 等価述語 リスト)のようなことを示しているのだと思いますが、これはCLでも同じです。

ということで次回は、8.3章から再開です。