2012-04-09 5 views
30

注:これは並行性に関するものではありません。これはスレッドマクロに関するものです。Clojureの一般化されたスレッディングマクロ

私は、->がオブジェクトを2番目の位置に置き、->>が最後の位置に引数を配置することを知っています。

さて、私は好奇心が強い、多くの機能のための#(... %)の短縮表記のように、私は任意の場所で引数を配置することができますスレッドの短縮表記はありますか?

目的は、スレッドが実行される固定の場所を持つ代わりに、私は任意のフォームを書くことができ、特別な場所に%%を挿入し、%%はスレッドが挿入される場所です。

ありがとうございます!

+0

ご質問ありがとうございます。私は年齢を問うことを求めていました。時々、私は(#(func-adapter arg1%arg2))を使用して、必要な効果を得る必要があります - >または - >>。 – jbear

答えて

26

Swiss Arrowsライブラリーから「ダイヤモンドワンドは、」あなたが求めているものだろう。

(-<> 0 
(* <> 5) 
(vector 1 2 <> 3 4)) 
; => [1 2 0 3 4] 

それはあなたが今まで私Clojureの経験でしばしば必要に終わる(か何かではない、と述べたこと)

+9

私はこれらのマクロがclojure変数名の柔軟性を乱用するのが好きです –

+2

さらに、バージョン1.5から、Clojureは[another answer](http://stackoverflow.com/a/17635433/109618)で説明されているように 'as->'を提供します。 )。 –

+0

私はかなり頻繁に 'as-> 'を使いますが、私はダイヤモンドワンドの簡潔さと視覚的明快さが好きです。通常、 'map'や' assoc'のような、異なるアリティを持つ共通関数が同じスレッド内で使われるときに起こります。 – ctpenrose

2

この機能を提供するライブラリがありましたが、どこを忘れていましたか。廃止されたclojure-contribになっている可能性があります。それは-$>マクロでした。

しかし、あなたは、あなたが探しているものにするためにはClojureのコア-> macroから1を引き出すことができます:あなたは、

user=> (-$> 2 str (identity $) (println $)) 
2 
nil 

技術的には可能性:

(defmacro -$> 
    ([x] x) 
    ([x form] (if (seq? form) 
       (with-meta (map #(if (= %1 '$) x %1) form) (meta form)) 
       (list form x))) 
    ([x form & more] `(-$> (-$> ~x ~form) [email protected]))) 

を、挿入ポイントを示すために$を使用1つの形式で複数の$を使用してください。しかし、この実装は、同じフォームを複数回(単純化と引き換えに)拡張することに苦しんでいます。

15

他の誰かがこれを遭遇する場合、提供されるマクロが存在する理由はありますが、任意の配置にはその理由がありません。後者はAPI設計に貧弱なものになります。

->マクロは、引数を最初の位置に配置します。これは、いくつかのサブジェクト引数で機能する関数、例えばconj,assocに対応します。

->>マクロは、引数を最後の位置に配置します。これは、配列に作用する関数、例えば、map,reduceに対応する。

APIをうまく設計すれば、そのようなマクロはほとんど必要ありません。

+2

正直、アレックス。場合によっては、設計していない関数を介してデータをスレッド化する必要があります。私はそれを回避するために常に(#(f a1%a3))を使うことができると思います。 – jbear

+0

'nth'はコレクションで動作するコア関数の良い例ですが、最後のargではなく最初のものとして期待しています。 –

+0

'nth'は他と同様にシーケンスを返しません。ネストされたシーケンスを掘り下げるときにうまく動作します。私はそれがそのように構造化されている理由だと思います。 – deterb

32

Clojureには、1.5からas->と呼ばれる一般的なスレッドマクロがあります。

このつぶやきは、それがどのように動作するかの例を与える:https://twitter.com/borkdude/status/302881431649128448

(as-> "/tmp" x 
     (java.io.File. x) 
     (file-seq x) 
     (filter (memfn isDirectory) x) 
     (count x)) 

まず「X」は「/ tmpに」にバインドされ、ファイルがそれから作られます。 'x'は結果のファイルに再度リバウンドし、 'file-seq'関数などを介してputされます。

+0

Swiss Arrowsライブラリは楽しいものですが、これはバージョン1.5以降Clojureに組み込まれているため、おそらく2014年の時点で最良の答えです。 –

+0

ここでのGithubのコード例:https://github.com/search?q=as-%3E+extension%3A.clj&type=Code&ref=searchresults –

関連する問題