[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
srfi-42
- 先行評価的内包表記 このモジュールはジェネリックな内包表記(comprehension)機構を提供します。 この機構は他の言語(Haskell、Pythonなど)では組み込みの機構になっていま す。この機構は豊富な操作手続を提供しているので、リストジェネレータとい うだけではなく、ジェネリックなループ構文(Common Lisp の loop マ クロ並みに強力/邪悪だという人もいます)を提供しています。
この機構は先行評価的に走ります。すなわち、リストを生成する場合、評価時
にすべてのリストを生成します。要素を要求駆動的に生成するわけで
はありません。それゆえ、無限列を表現することはできません。それが自然に
できる Haskell とは違います。Schemeにおいては無限列を扱うのなら遅延評
価をするように構築されたストリームが使えます
(util.stream
- ストリームライブラリ参照)。
いくつかの例からはじめましょう。
5番目までの整数の自乗のリストを生成しましょう。
(list-ec (: i 5) (* i i)) ⇒ (0 1 4 9 16) |
list-ec
はリストを生成する内包表記マクロです。
最初のフォーム(: i 5)
はqualifierと呼ばれ、
繰り返しを行う値の集合を指定します (この例では0以上5未満の整数)。
最後のフォーム(* i i)
はbodyと呼ばれ、
qualifierが指定する値それぞれにつき評価される通常のScheme式です。
内包表記は複数のqualifierを持つことができます。
次の例は数の対(x y)
の集合を生成します。ここでx
は
2以上 5未満、y
は1以上 x 未満です。
(list-ec (: x 2 5) (: y 1 x) (list x y)) ⇒ ((2 1) (3 1) (3 2) (4 1) (4 2) (4 3)) |
複数のqualifierはネストするように動作します。つまり、(: x 2 5)
は
残りの節—(: y 1 x)
および (list x y)
を繰り返すように
指定しているということです。
上の2つの例はHaskellで書くと以下のようになります。
[ i*i | i <- [0..4] ] [ (x,y) | x <- [2..4], y <- [1..x-1] ] |
違いに注意:(1) Haskellでは要素になる本体部が先にきて、そのあとに修飾 部(セレクタ)がきます。SRFI-42では本体部は最後になります。(2) SRFI-42で は範囲指定の下限はそれを含み、上限はそれを含みません。
a^3+b^3 = c^3+d^3
を満すような数字の集合(a b c d)
を列挙し
ましょう。
(define (taxi-number n) (list-ec (: a 1 n) (: b (+ a 1) n) (: c (+ a 1) b) (: d (+ c 1) b) (if (= (+ (expt a 3) (expt b 3)) (+ (expt c 3) (expt d 3)))) (list a b c d))) |
複数の変数を(ネストするのではなく)同時に変化させたい場合は、 複数のqualifierを次のようにまとめることができます。
(list-ec (:parallel (: x '(a b c d)) (: y '(1 2 3 4))) (list x y)) ⇒ ((a 1) (b 2) (c 3) (d 4)) |
リストだけではなく、他のシーケンスも生成できます。
(vector-ec (: i 5) i) ⇒ #(0 1 2 3 4) (string-ec (: i 5) (integer->char (+ i 65))) ⇒ "ABCDE" |
畳み込み演算も適用できます。
(sum-ec (: i 1 100) i) ⇒ 4950 ;; 1以上100未満の整数の和 (product-ec (: i 1 10) i) ⇒ 362880 ;; 1以上10未満の整数の積 |
それぞれの内包表記は以下のような形式になります。
(comprehension-macro qualifier … body) |
qualifier …の指定に従ってbodyをくりかえし評価します。内包表記の種類 によって、bodyの結果は(リスト、ベクタ、文字列などに)集約されるか、 (sum、product、min、maxなどによって)畳み込まれるか、あるいは、単に捨て られます。
それぞれのqualifierは、それ以降のqualifierとbody をどのように繰り返すかを指定します。qualifierには、繰り返しに 使う値を生成する生成的qualifierと、条件によって値を繰り返しから 省く制御的qualifierがあります。以下のQualifiersの節を参照してください。
いくつかの内包表記では、追加の値がqualifiersの前か、body の後に置かれます。
[SRFI-42] Repeats body. The results of body is discarded. This is for side-effecting operations.
[SRFI-42]
Repeats body
and collects the results into a list.
[SRFI-42]
Repeats body
, which must yield a list.
Returns a list which is the concatenation of all lists retured by body.
[SRFI-42]
Repeats body, which must yield a character (in string-ec
)
or a string (in string-append-ec
). Returns a string that
consists of the results of body.
[SRFI-42] Repeats body and collects the results into a vector.
[SRFI-42]
This is like vector-ec
, except that the length of the
result vector is known to be k. It can be more efficient
than vector-ec
. Unless the comprehension repeats exactly
k
times, an error is signaled.
[SRFI-42] body must yield a numeric value. Returns sum of and product of the results, respectively.
[SRFI-42] body must yield a numeric value. Returns maximum and minimum value of the results, respectively. body must be evaluated at least once, or an error is signalled.
[SRFI-42]
Evaluates test for each iteration, and returns
#t
as soon as it yields non-#f
(for any-ec?
),
or returns #f
as soon as it yields #f
(for every?-ec
).
Unlink the comprehensions introduced above, these stop evaluating
test as soon as the condition meets.
If the qualifiers makes no iteration, #f
and #t
are
returned, respectively.
[SRFI-42]
First initializes the result by the value of the expression default,
then start iteration, and returns the value of the first and last
evaluation of body, respectively. In fact, first-ec
only evaluates body at most once.
These procedures are most useful when used with control qualifiers.
For example, the following first-ec
returns the first
set of distinct integers (x, y, z),
where x*x+y*y+z*z becomes a square
of another integer w.
(first-ec #f (:integers w) (: z 1 w) (: y 1 z) (: x 1 y) (if (= (* w w) (+ (* x x) (* y y) (* z z)))) (list x y z w)) |
Note that the first qualifier, (:integers w)
, generates
infinite number of integers; if you use list-ec
instead of
first-ec
it won't stop.
[SRFI-42] Reduces the values produced by expr.
Suppose expr produces a sequence of values
x0, x1, …, xN. Fold-ec
calculates the following value:
(proc xN (…(proc x1 (proc x0 seed))…)) |
It's similar to fold
, except that proc is evaluated
within the scope of qualifier … so you can refer to the
variables introduced by them. On the other hand,
seed is outside of the scope of qualifiers.
Fold-ec3
is almost the same but the initial value calculation.
In fold-ec3
, seed is only used when qualifiers
makes no iteration. Otherwise it calculates the following value:
(proc xN (…(proc x1 (init x0))…)) |
This type of qualifiers generates (possibly infinite) values over which the rest of clauses iterate.
In the following descriptions, vars refers to either
a single identifier, or a series of identifier and a form
(index identifier2)
. The single identifier
in the former case and the first identifier in the latter case
name the variable to which each generated value is bound.
The identifier2 in the latter case names a variable
to which a series of integers, increasing with each generated
element, is bound. See the following example:
(list-ec (: x '(a b c)) x) ⇒ (a b c) (list-ec (: x (index y) '(a b c)) (cons x y)) ⇒ ((a . 0) (b . 1) (c . 2)) |
A generic dispatcher of generational qualifiers.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.