For Development HEAD DRAFTSearch (procedure/syntax/module):

11.48 srfi.197 - パイプラインオペレータ

Module: srfi.197

このモジュールは、複数の操作を組み合わせるマクロを提供します。 Clojureの「スレッドマクロ」に似たものです。

ひとつの関数適用の結果を別の関数に渡して…というのをつなげてゆくと、 しばしば式のネストが深くなってしまいます:

(g (f (e (d (c (b (a arg)))))))

Gaucheでは$マクロを使えば上の式はこうも書けます (手続きを作る参照):

($ g $ f $ e $ d $ c $ b $ a arg)

ネストは浅くなりましたが、適用順は依然として右から左で、 また前の結果を引数として渡す位置が最後の引数に限られます。

このモジュールのchainマクロを使うと、 上の式は左から右にデータを流すように書けます:

(chain (a arg) (b _) (c _) (d _) (e _) (f _) (g _))

2番目以降の式中の_は、前の結果をその位置の引数で受け取ることを示します。 上の式は概念的には次の式と等価です。

(let* ((tmp (a arg))
       (tmp (b tmp))
       (tmp (c tmp))
       (tmp (d tmp))
       (tmp (e tmp)))
  (g tmp))

引数をはめ込む場所を明示できるので、他の引数も自由に渡せます:

(chain x (y a _) (z _ b))
 ≡
 (let* ((tmp x)
        (tmp (y a tmp)))
   (z tmp b))

多値を受け取って複数の引数として渡すこともできます:

(chain mv-expr (f _ _) (g _ _))
 ≡
 (let*-values (((tmp1 tmp2) mv-expr)
               ((tmp1 tmp2) (f tmp1 tmp2)))
   (g tmp1 tmp2))
Macro: chain initial-value [placeholder [ellipsis]] step …

[SRFI-197]{srfi.197} 省略可能なplaceholderellipsis引数は、 リテラルシンボルでなければなりません。与えられた場合は、 デフォルトのプレースホルダ_とエリプシス...を置き換えます。

step(datum …)の形で、 datumは式、プレースホルダ、あるいはエリプシスです。 但し、エリプシスは最後の要素としてのみ許され、現れた場合は直前がプレースホルダ でなければなりません。

概念的には、各stepはプレースホルダの数だけ引数を取る手続きへと展開されます。 手続きに渡された引数は順にプレースホルダの箇所に充てられます。 stepの最後がエリプシスだった場合は、直前のプレースホルダが “rest” 引数として 動作します。

stepが一つ以上の値を期待する場合、直前のstepもしくは initial-valueは同じ数だけの値を生成せねばなりません。

(chain expr (f _ a _ ...))
  ≡
  (let*-values (((tmp1 . tmp2) expr))
    (apply f tmp1 a tmp2))
Macro: chain-and initial-value [placeholder] step …

[SRFI-197]{srfi.197} chainの変種で、中間の結果が#fになった場合にその後のstepの 評価を行わず直ちに#fを返します。

initial-valueはひとつの値を返す式です。 placeholderstep中でプレースホルダーとして使われるリテラルシンボルです。 省略時には_が使われます。

chainと違い、各stepはたかだか1個のプレースホルダーしか 含むことができません。stepがプレースホルダーを含んでいない場合、 直前のstepの結果は操作を打ちきるかどうかの判定のみに使われ、その後捨てられます。

Macro: chain-when initial-value [placeholder] ([guard] step) …

[SRFI-197]{srfi.197} chainの変種で、stepを適用するかどうかを選べるものです。

chain-andと同じく、各stepはプレースホルダーをたかだか1個までしか 含むことができません。

guardは式です。各ステップで、まずguardが評価され、 それが真ならば直前に実行された結果がプレースホルダーに束縛されて 対応するstepが実行されます。guardが偽ならば、 stepは実行されず、直前の結果が次のステップへと持ち越されます。

(chain-when expr ((p? x) (f _)) ((q? x) (g _)))
 ≡
 (let* ([tmp expr]
        [tmp (if (p? x) (f tmp) tmp)])
   (if (q? x) (g tmp) tmp))
Macro: chain-lambda [placeholder [ellipsis]] step …

[SRFI-197]{srfi.197}

(chain-lambda step ...)
  ≡ (lambda args (chain (apply values args) step ...))
Macro: nest [placeholder] step … initial-value

[SRFI-197]{srfi.197} chainと似ていますが、評価順が右から左になります。

stepはひとつだけプレースホルダーシンボルを持たなければなりません。 このマクロは単にステップをネストした式に変換するだけです。

(nest (f a _) (g _ b) (h _) expr)
 ≡ (f a (g (h expr) b))
Macro: nest-reverse initial-value [placeholder] step …

[SRFI-197]{srfi.197} nestの評価順が逆になったものです。

stepはひとつだけプレースホルダーシンボルを持たなければなりません。 このマクロは単にステップをネストした式に変換するだけです。

(nest expr (h _) (g _ b) (f a _))
 ≡ (f a (g (h expr) b))


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT