読みやすいClojureコードの書き方


13

私はClojureを初めて使用します。書いたコードは理解できますが、後で理解するのが難しくなります。
括弧を一致させることが難しくなります。

さまざまな状況での命名規則とインデントに関して従うべき一般的な規則は何ですか?

たとえば、理解するためにサンプルの非構造化例を作成しましたが、2回目には完全に判読できません。

(defn f [{x :x y :y z :z [a b c] :coll}] (print x " " y  " " z " " a " " b " " c)) 

構造化を解除する場合、パラメータレベルで直接行うか、letフォームを開始してから続行する方が良いでしょうか?


3
Stack Overflowには、読みやすさに関する良い答えがあります。あなたはそれをチェックアウトできます。stackoverflow.com/a/1894891/1969106
yfklon

2
読みやすいLispコードを書くことは一般的に難しい。彼らは、理由のために「Lost In Superfluous Parenthesis」という逆称を発明しました。
メイソンウィーラー

回答:


23

命名規則

  • 関数の小文字のまま
  • -ハイフネーションに使用します(他の言語ではアンダースコアまたはキャメルケースになります)。

    (defn add-one [i] (inc i))

  • 述語(? 例:trueまたはfalseを返す関数)は例で終わります:odd? even? nil? empty?

  • 状態変更手順はで終わり!ます。覚えてるset!?またはswap!

  • リーチに応じて、短い変数名の長さを選択します。つまり、本当に小さな補助変数がある場合は、1文字の名前を使用できることがよくあります。(map (fn [[k v]] (inc v)) {:test 4 :blub 5})特に多くのコード行で使用され、すぐに目的を推測できない場合は、必要に応じてより長い変数名を選択してください。(私の意見)。

    多くのclojureプログラマーは、一般的で短い名前を使う傾向があると感じています。しかし、これはもちろん実際に客観的な観察ではありません。ポイントは、多くのclojure関数が実際には非常に汎用的であることです。

    • 意味のある名前を使用します。手順は何かをしているので、動詞を使用してそれらを最もよく説明できます。:Clojureのは正しい軌道に乗ってあなたを置くべき機能を内蔵droptakeassoc、などそして、意味のある名前を選択する方法を記述した素敵な記事があります:http://ecmendenhall.github.io/blog/blog/2013/09/ 02 / clean-clojure-meaningful-names /

ラムダ関数

  • 実際にラムダ関数に名前を付けることができます。これはデバッグとプロファイリングに便利です(ここでの私の経験はClojureScriptを使用したものです)。

    (fn square-em [[k v]] {k (* v v)})

  • #()便利なインラインラムダ関数を使用する

空白

  • 括弧のみの行はありません。すなわち、すぐに括弧を閉じます。括弧はエディターとコンパイラーのためにあり、インデントはあなたのためです。

  • 関数パラメーターリストは新しい行に移動します

   (定義短所
     [ab]
     (リストab))

doc文字列について考える場合、これは理にかなっています。それらは関数名とパラメーターの間にあります。次のドキュメント文字列はおそらく賢明ではありません;)

   (定義短所
     「ペアリング」
     [ab]
     (リストab))
  • ペアリングを保持している限り、ペアのデータは改行で区切ることができます
  (定義f 
    [{x:x 
      y:y 
      グーグー  
      [abc]:coll}] 
    (print x "" y "" z "" a "" b "" c)) 

,好きなように入力することもできますが、これはまともな感じではありません)。

  • インデントには、十分に優れたエディターを使用します。数年前、これはLisp編集のemacsでしたが、vimも今日は素晴らしいです。典型的なclojure IDEもこの機能を提供するはずです。ランダムテキストエディターを使用しないでください。

    コマンドモードのvimでは、=コマンドを使用して適切にインデントできます。

  • コマンドが長すぎる場合(ネストなど)、最初の引数の後に改行を挿入できます。次のコードはかなり無意味ですが、式をグループ化およびインデントする方法を示しています。

(+(if-let [age(:personal-age coll)]
     (if(> age 18)の場合
       年齢
       0))
   (カウント(範囲(-3 b)
                 (削減+ 
                         (範囲b 10))))))

良いインデントは、括弧を数える必要がないことを意味します。括弧はコンピューター用です(ソースコードを解釈し、インデントするため)。インデントは理解を容易にするためのものです。

高階関数fordoseqフォーム

Schemeの背景から来て、私はmapラムダ関数などを理解していることをかなり誇りに思っていました。だから非常に頻繁に、私はこのようなものを書くでしょう

(map (fn [[k x]] (+ x (k data))) {:a 10 :b 20 :c 30})

これは非常に読みにくいです。forフォームは、道のよりよいです:

(for [[k x] {:a 10 :b 20 :c30}]
  (+ x (k data)))

`mapには多くの用途があり、名前付き関数を使用している場合は本当に便利です。すなわち

(map inc [12 30 10]

(map count [[10 20 23] [1 2 3 4 5] (range 5)])

スレッドマクロを使用する

スレッドマクロ使用->->>同様にdoto該当する場合を。

重要なのは、スレッドマクロにより、ソースコードが関数の合成よりも直線的に見えるようになるということです。次のコードは、スレッドマクロがないと非常に読みにくくなります。

   (f (g (h 3) 10) [10 3 2 3])

と比べて

   (-> 
     (h 3)
     (g 10)
     (f [10 3 2 3]))

スレッドマクロを使用することにより、通常、1回だけ使用される一時変数の導入を回避できます。

他のもの

  • docstringを使用する
  • 機能を短くする
  • 他のclojureコードを読む

構造化を解除したその関数は、インデントで美しく見えます!
アモグタルパリカー

機能を短くするために+1。小さな機能の多くは、はるかに自己文書化されています
ダニエルグラッツァー

1
「短距離」関数であっても、短い変数名を使用することは良い考えでないことに強く反対します。良い変数名は読みやすさのために重要であり、キーストローク以外の費用はかかりません。これは、Clojureコミュニティについて私を最も悩ませていることの1つです。記述的な変数名に対してほとんど敵対的な抵抗を持つ人々がたくさんいます。Clojureコアには、関数の引数用の1文字の変数名が散らばっています。これにより、言語の学習が非常に難しくなります(たとえば、実行中docまたはsourceREPLで)。暴言の終わり、そうでなければ優れた答え
ネイサンウォレス

@NathanWallaceある意味ではあなたに同意しますが、ある面では私はしません。長い名前は、機能を過剰に特定する傾向があります。したがって、いくつかの一般的なフィルター操作は実際には一般的であることがわかりますが、引数がのapples代わりになったときは、xsリンゴに固有であると考えました。また、関数の引数名は、たとえばforループ変数よりもさらに到達すると考えています。必要に応じて、より長くすることができます。最後の考えとして:「値ではなく名前コード」concatenative.org/wiki/view/Concatenative%20language/を
wirrbel

プライベートインターフェイスとパブリックインターフェイスのようなものに段落を追加できます。特に図書館に関して。それは十分に語られていないコード品質の側面であり、私はその答えを書いて以来、これについてたくさんのことを学びました。
ウィルベル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.