はじめに
LIPSの学習を兼ねてQiitaの投稿を始めて1回目の投稿から12回目となりました。
今回はreduce関数についてです。
よく示されるreduceの使用例は、リストデータを受け取ってreduce内の繰り返し処理を行って最終的な結果を単一の値として返すものです。
今回はreduce関数によるパイプライン風プログラミングの可能性を試してみました。
環境
LIPS Schemeを使ってみました8(言語処理100本ノック 1章)を参照してください。
LIPSはnode.jsのようにREPLを起動してコードを直接入力&実行することができます。
サンプル1
まずは典型的な例を見てみましょう。
下のコードはリストの各要素に対して同じ処理を繰り返して最終的な値を結果として返すパターンです。
(reduce (lambda (cur-val acc) (+ acc cur-val)) 0 '(1 2 3 4))
;; (reduce (lambda (cur-val acc) (console.log cur-val acc) (+ acc cur-val)) 0 '(1 2 3 4))
;;結果=> 10
JavaScriptの場合は下のようになります。
[1, 2, 3, 4].reduce((acc, cur_val) => acc + cur_val, 0)
//または [1, 2, 3, 4].reduce((acc, cur_val) => acc + cur_val)
[!NOTE]
LIPSのreduceのコールバック関数は引数の順番がJSと逆になっています。
サンプル2
次はパイプライン風の使い方を試してみましょう。
処理対象の元データと各種処理を行う関数リストをreduceに食べさせて最終的な結果を取得するパターンを想定しています。
(define (foo param) (string-append param "b")) ; 引数に"b"を結合して返す。
(define (bar param) (string-append param "c")) ; 引数に"c"を結合して返す。
(reduce (lambda (func acc) (func acc)) "a" (list foo bar))
;;結果=> abc
JavaScriptの場合は下のようになります。
const foo = (param) => param + "b";
const bar = (param) => param + "c";
[foo, bar].reduce((acc, func) => func(acc), "a");
おわりに
パイプラインの応用例の一つとして、
前の言語処理100本ノックの3章のNo29のような正規表現による前処理をいくつも通すような場合にこのようなパイプラインが有効になります。
コマンドラインで使うパイプ(|)と似た発想です。