2016-07-08 9 views
1

Clojureコードには頻繁に出てくるフォームがあります。単純化する方法があるかどうかを知りたいと思います。 。Clojureの条件付きバインディングと実行

は、ここでの操作の結果は、述語に一致した場合、動作Xを行う変数Yに結果を結合して、いくつかのコードを実行し、」行動の説明だ

ここで私が今使っている実装です:

(let [op-result (op ...)] 
    (if-let [my-var (when (pred op-result) op-result)] 
    then else)) 

は私が達成しようとしている何のためにあまりにも冗長ようです。誰もが(私自身のマクロを書くことから離れて)任意の提案を持っていますか?

+4

"my-var"に対して 'op-result'を省略することができるので、単純な'(if(pred op-result)then else) 'だけです。あるいはあなたの例はもっと複雑ですか? – ClojureMostly

答えて

0

私はあなたが「それから」でop-resultを使用したい推測していますしかし、多くの述語関数彼らの議論ではないtrueを返します。だから、単純にこれを書き込むことはできません。

(if-let [op-result (pred (op))] 
    op-result ;maybe `true`, but you want `(op)` 
    false) 

したいコア式は次のとおりです。

(and (pred x) x) 

あなたは

(if-let [op-result (and (pred (op)) (op))] 
    op-result 
    false) 

を書くことができしかし(op)が高価である場合、これは良いです。

(if-let [op-result (let [x (op)] (and (pred x) x))] 
    op-result 
    false) 

もちろん、ちょっと退屈なので、それがたくさん必要な場合は、マクロを書く価値があるかもしれません。


私は別のアプローチは、述語は "truthy" にすることですとします

(defn truthy 
    "Given a predicate function, return a new function. 
    When the original predicate function returns true for some value, 
    the new function returns the value (instead of true). Else returns 
    false." 
    [pred] 
    (fn [v] 
    (and (pred v) v))) 

((truthy even?) 2) ; 2 
((truthy even?) 3) ; false 

(if-let [op-result ((truthy pred) (op))] 
    op-result ;use op-result 
    false) 

再度、マクロが便利かもしれません。


いくつかのLispでIは、(Emacs Lispのラケットでmatchpcase)パターンマッチングを使用したいです。これらは、condのような形式です。多くの場合、テストの述語を適用し、元の値をバインドすることができます。私はcore.matchがこれを行うことができるかどうか、またはあなたがこれを行うためだけにそれを含める場合は分かりません。


最後に、私は完全に誰かがこのようなものは、すでに私は知らないのClojureでワンライナーとして存在することを指摘して期待しています。 :)しかし、私は誰もまだ持っていないので、私は答えを試みると思った。

+0

'(と(pred x)x)'の問題は、すでにどこかで 'x'をバインドしなければならないということです。追加の文をどこかに置く必要があります。 –

+0

正確です。私が見ることができる2つのアプローチは、(a)余分な「let」バインディングを使用するか、(b)述語が「真実」の方法で動作するように「強化」することです。 (あるレベルでは、関数は引数が束縛されているので同等ですが、理論的に関数アプリケーションの観点からは 'let'を構築することができますが、どちらの方が好きですか?)マクロですが、通常は、マクロがあなたのために書いて欲しいと思っているコードを調べたり、試したりするのは良いことです。 –

関連する問題