この記事は, Lisp Advent Calendar 2019の11日目の記事です.
この記事のライセンスはCC-BYとします.
この記事は, 10日目の記事の補足になるかもしれない小ネタ記事です.
reduceの使い方の指針について触れます.
使用プログラミング言語は, Common Lispです.
が, JavaScriptのreduce
, reduceRight
や, Haskellのfoldl
, foldr
とかも同じだと思うので, もしかしたら参考になるかも.
再掲 10日目の補足 andの展開形
各処理系の実装は参考にしてないけど, 展開系は参考にしました. 1
CL-USER> (macroexpand '(and))
T
T
CL-USER> (macroexpand '(and a))
(THE T A)
T
CL-USER> (macroexpand '(and a b c))
(IF (IF A
B)
C)
T
THE
は無視して, A
は, (IF T A)
だと思うと,
(IF (IF (IF T A) B) C)
この形を見ると, reduce
で処理できることが分かります.
reduceの使い方 より具体的にのその前に
reduceの使い方の指針を示す前に, 以下の関数を定義しておきます.
(defun snoc (list elt)
(append list (list elt)))
これを使うと, リスト(1 2 3)
は, 以下の2パターンで書けます.
CL-USER> (snoc (snoc (snoc nil 1) 2) 3)
(1 2 3)
CL-USER> (cons 1 (cons 2 (cons 3 nil)))
(1 2 3)
reduceの使い方
上のパターンの,
CL-USER> (snoc (snoc (snoc nil 1) 2) 3)
(1 2 3)
について, この式のsnoc
をある関数func
, nil
をある値z
と入れ替えたような形,
(func (func (func z 1) 2) 3)
で書ける場合は,
(reduce #'func '(1 2 3) :initial-value z)
とreduceで書けます.
reduce (from-endオプションがt)
逆に, 下のパターンの,
CL-USER> (cons 1 (cons 2 (cons 3 nil)))
(1 2 3)
について, この式のcons
をある関数func
, nil
をある値z
と入れ替えたような形,
(func 1 (func 2 (func 3 z)))
で書ける場合は,
(reduce #'func '(1 2 3) :initial-value z :from-end t)
と:from-end
オプションがt
のreduceで書けます.
まとめ
reduce難しくないよ.
この記事中の例で使ったリスト(1 2 3)
は適当に自分が使いたい場合に読み替えて使ってください.
あと, 数学が好きな人はcatamorphismとか調べてみると幸せになれるかもしれません. 2