2017-07-15 1 views
1

defステートメントをと同じ方法で破棄してもよいでしょうか?letスタイルのデフラグをdefに使用する

(let [[rtgs pcts] (->> (sort-by second row) 
         (apply map vector))] 
.....) 

私がしたいことのようなものである:例えば

(defs [rtgs pcts] (->> (sort-by second row) 
         (apply map vector))) 

これはREPL、ノートブックやデバッグ時に多くのことをアップしています。真剣に私はの一つの指針たいと思いますので、不足している機能のように感じている:

  • これは、すでに存在していると私はこれが原因で悪い考えでそれを
  • を欠けている...(変数捕捉を?リッチはそう言ったのですか?)
  • それは不必要で、私は邪悪な言葉から撤退することに苦しんでいるに違いありません。 (同じよう:あなたのマクロで私たちの言語ではなく混乱を行う)

A超短い実験は私のような何か与える:

(defmacro def2 [[name1 name2] form] 
    `(let [[ret1# ret2#] ~form] 
     (do (def ~name1 ret1#) 
     (def ~name2 ret2#)))) 

をそしてこの作品のように:

(def2 [three five] ((juxt dec inc) 4)) 
three ;; => 3 
five ;; => 5 

もちろん、そのマクロの「業種」のバージョンは、次のようになります。

  • 名前の数は入力の数と一致します。 (フォームからの復帰)
  • 以上の名前(私はこのようなマクロでそれを行うことができますか?)

答えて

4

私はあなたがおそらく生産で実行し、これを持つべきではないというジョシュに同意するが、私は実際に私は私のデバッグにこれをコピーすると思う(REPLで利便性としてそれを持つに害が表示されません-replキッチンシンクライブラリ)。

(それらは通常必要としていないが)、私はマクロを書く楽しむので、私は実装をホイップ。 letのようなバインディング形式を受け入れます。約

(私はこのスペック-最初に書いていますが、Clojureの< 1.9.0-alpha17にしている場合は、あなただけの仕様のものを削除することができ、それは同じように動作します。)

(ns macro-fun 
    (:require 
    [clojure.spec.alpha :as s] 
    [clojure.core.specs.alpha :as core-specs])) 

(s/fdef syms-in-binding 
    :args (s/cat :b ::core-specs/binding-form) 
    :ret (s/coll-of simple-symbol? :kind vector?)) 

(defn syms-in-binding 
    "Returns a vector of all symbols in a binding form." 
    [b] 
    (letfn [(step [acc coll] 
      (reduce (fn [acc x] 
         (cond (coll? x) (step acc x) 
          (symbol? x) (conj acc x) 
          :else acc)) 
        acc, coll))] 
    (if (symbol? b) [b] (step [] b)))) 

(s/fdef defs 
    :args (s/cat :binding ::core-specs/binding-form, :body any?)) 

(defmacro defs 
    "Like def, but can take a binding form instead of a symbol to 
    destructure the results of the body. 
    Doesn't support docstrings or other metadata." 
    [binding body] 
    `(let [~binding ~body] 
    [email protected](for [sym (syms-in-binding binding)] 
     `(def ~sym ~sym)))) 


;; Usage 

(defs {:keys [foo bar]} {:foo 42 :bar 36}) 

foo ;=> 42 

bar ;=> 36 

(defs [a b [c d]] [1 2 [3 4]]) 

[a b c d] ;=> [1 2 3 4] 

(defs baz 42) 

baz ;=> 42 

あなたのREPL主導の開発コメント:

私はIpythonに関する経験はありませんが、私はREPLワークフローについて簡単に説明し、Ipythonとの比較/対比についてコメントすることができます。

私は、コマンドを入力し、応答を待って、ターミナルのような私のREPLを使用することはありません。私のエディタは、s式の終わりにカーソルを置いてreplに送信し、カーソルの後に結果を「印刷」する(emacsだが、clojureエディタはすべきである)。

私は通常ちょうど何を入力し、それを評価し、私が作業を開始したファイルにcommentブロックを持っています。そして、私が結果に幸せになれば、それを「repl-area」から「real-code」に引き出します。

(ns stuff.core) 

;; Real code is here. 
;; I make sure that this part always basically works, 
;; ie. doesn't blow up when I evaluate the whole file 

(defn foo-fn [x] 
    ,,,) 

(comment 

    ;; Random experiments. 

    ;; I usually delete this when I'm done with a coding session, 
    ;; but I copy some forms into tests. 

    ;; Sometimes I leave it for posterity though, 
    ;; if I think it explains something well. 

    (def some-data [,,,]) 

    ;; Trying out foo-fn, maybe copy this into a test when I'm done. 
    (foo-fn some-data) 

    ;; Half-finished other stuff. 
    (defn bar-fn [x] ,,,) 

    (keys 42) ; I wonder what happens if... 

) 

あなたはclojure core source codeでこの例を見ることができます。

+0

re:私のREPLコメント。ライブラリやバックエンドの開発者よりも "データ科学者"のワークフローを考えてみてください。私はclojureが好きで、それがより広く採用されることを願っています。 Emacs/cider replは良い、非常に良いですが、それはIDE固有のものです(proto-replなど) Emacs/ciderは、その言語に来る人には登り過ぎる壁があります。 1)複数の行の編集や履歴なし、2)自動終了のブレースなし、3)pprintの使用量の増加、4)ファイル名のタブ補完、5) pwd、ls、editのようなシェルの基本を行う能力(宇宙の自由) –

3

のClojureのどの部分が持っていることをdef Sの数はプロジェクトごとに異なりますを処理するための再帰呼び出しが、私は一般に、defは、しばしば、何らかの計算の結果ではなく、それだけでは、破壊される必要がある計算の結果ではないと言いたい。多くの場合、def開始点であり、後でこの値に依存します。

通常、関数は値を計算するのに適しています。計算が高価な場合は、関数をメモすることができます。あなたが本当にこの機能を必要と感じているなら、是非、マクロを使用してください。これは、クローゼットの売り上げポイントの1つ、つまり拡張性です!しかし、一般的に、あなたがこの構築物が必要だと感じたら、あなたはグローバルな状態にあまりにも頼っている可能性を考慮してください。

いくつかの実際の例をあげると、私はちょうど約20の名前空間で2K-3Kのクローゼットラインである私の主なプロジェクトを参照しました。私たちには約20個のdefがあります。そのほとんどはプライベートとマークされていますが、実際には何も計算していません。 - しかし、本当の計算

(def path-prefix "/some-path") 
(def zk-conn (atom nil)) 
(def success? #{200}) 
(def compile* (clojure.core.memoize/ttl compiler {} ...))) 
(def ^:private nashorn-factory (NashornScriptEngineFactory.)) 
(def ^:private read-json (comp json/read-str ...)) 

compmemoizeを使用して)定義関数、列挙型、​​経由状態:私たちは、のようなものを持っています。

上記の箇条書きに基づいて、これは2〜3の間になります:これは間違いなく一般的な使用例ではありません(あなたがこれを望んでいる最初の人です、とにかく私には珍しいことです)。それが珍しい理由は、私が上記のことからです。つまり、あまりにも多くのグローバルな状態に依存していることを示すコードの匂いかもしれないので、あまり慣れないでしょう。

私は私のコードの多くを持っている

一つのリトマス試験がある:私は、この名前空間の外にこの機能を引き出し、別のに貼り付けた場合、それはまだ動作しますか?外部変数の依存関係を削除することで、テストが簡単になり、モジュラーコードが増えます。時にはそれが必要な場合もありますので、要件が何であるかを見てそれに応じて進んでください。運が良かった!

+0

私は、一般的にはグローバルな状態に訓戒に同意するが、これは私がそんなに聞く「REPL」駆動開発を抑止します。それは私が慣れていたipythonのようなより成熟したreplsと比較して、clojureでは "ok"です –

+0

REPL駆動型開発とは、状態とRDDの関係についてあなたが誤解している場合を除いて、コードをそのまま(varsに割り当てられた一時データをそのまま)取り、ソースファイルに入れることを意味するものではありません。 ipythonと比較してどのように淡色になっていますか? @PhilCooper – Josh

関連する問題