2016-05-18 18 views
5

再帰型は、基底とそれ自身の再帰的な場合を持つ型です。Common Lispで再帰型を定義することはできますか?

これは、「型付きリスト」を実装することを希望しました。つまり、コンマが同じ要素タイプまたはnilのみを許可するリストです。

私は次のように定義しようとした:

(deftype list-of (a) `(or null 
          (cons ,a (list-of ,a)))) 

をしかし、これは、リストの無期限を超える再帰しようとしているコンパイラに(少なくとも、SBCL上)スタックexausted問題を通知します。そのようなデータ型を定義することは可能ですか?

答えて

5

これはできません。 DEFTYPEで定義するタイプは「派生タイプ」です。派生型は(マクロのように)派生型を含むことができない "実"型指定子に展開されます。展開内の派生型(型自体またはその他の型)への参照もすべて展開されます。したがって、再帰的な型は無限ループに入り拡張しようとします。

Trivial Typesは、適切なリストの型を提供しますが、それを引数としてとっても要素型を実際にチェックするわけではありません。美容上の理由から、それで十分でしょう。

(ql:quickload :trivial-types) 
(use-package :trivial-types) 
(typep '("qwe" "asd" "zxc") '(proper-list string)) ;=> T 
(typep '("qwe" "asd" "zxc" 12) '(proper-list string)) ;=> T 

そうでなければ、最初のカップル要素が正しい型かどうかをチェックする型を定義できます。それは少なくとも最も明白な違反をキャッチするだろう。

(deftype list-of (a) 
    `(or null (cons ,a (or null (cons ,a (or null (cons ,a list))))))) 
(typep '("asd") '(list-of string)) ;=> T 
(typep '("asd" 12) '(list-of string)) ;=> NIL 
(typep '("asd" "qwe") '(list-of string)) ;=> T 
(typep '("asd" "qwe" 12) '(list-of string)) ;=> NIL 
(typep '("asd" "qwe" "zxc") '(list-of string)) ;=> T 
(typep '("asd" "qwe" "zxc" 12) '(list-of string)) ;=> T 

あなたはそれが任意の長さのリストのために仕事をしたい場合は、あなたが必要とする各別のリストの型を定義する必要があります。

(defun list-of-strings-p (list) 
    (every #'stringp list)) 
(deftype list-of-strings() 
    `(or null (satisfies list-of-strings-p))) 
(typep '("qwe" "asd" "zxc" "rty" "fgh") 'list-of-strings) ;=> T 
(typep '("qwe" "asd" "zxc" "rty" "fgh" 12) 'list-of-strings) ;=> NIL 
+1

美容上の理由からタイプを設定するのはあまり役に立ちません。美容上の理由から、私はいつも '(どのようなものであっても)'できますか? – ssice

+0

@ssice '(正しいリスト文字列)'を使うと、リストが適切なリストであることをチェックし、文字列を含むことを期待するコードを人々に伝えます。明らかに、あなたのコードは実際に文字列を含むことに依存することはできませんが、それが重要でない場合は、それは何もないよりも優れています。 – jkiiski

+0

申し訳ありません、それは妥協です。したがって、HM型の背後にある数学を深めることなく、自己文書化コードと直接的な間違いを言うのは「良い」です。 – ssice

3

はい、私はだまさ;)

(defun satisfication (a) 
    (if a 
     (and (integerp (car a)) 
     (satisfication (cdr a))) 
     T)) 

(deftype my-list() `(satisfies satisfication)) 


(typep (cons 1 (cons 2 (cons 3 nil))) 'my-list) 
> T 


(typep (cons 1 (cons 2 (cons 3.2 nil))) 'my-list) 
> NIL 

どうやらSBCLは、再帰的なタイプが好きではありません - その理由はよく別の答えによって説明されます。しかし、標準に固執して再帰型を定義したい場合は、トンネルの終わりにライトがあります。満足度をチェックする関数を定義することができます。

+2

'(すべての#整数のリスト)'を使用できます。また、一般的な方法で型を扱い、ループを使用することもできます: '(リスト内のループは常に(typep e型))' – coredump

+1

もちろん、単形型でチェックする関数を書くのは簡単ですが、多形性の問題はずっと面白いです。 – ssice

+0

多型の最も重要な警告は、もはや1つのパラメータだけを使って 'satisfies'関数を定義することができなくなるということです。 – ssice

関連する問題