LoginSignup
31
25

More than 5 years have passed since last update.

1ヶ月間仕事でClojureを書いている今時点でよく使う関数・コマンドまとめ

Last updated at Posted at 2016-04-29

3月からClojureを仕事で書いていまして、その中で開発中によく使っているコマンドや、気に入った関数について振り返りながらまとめます。
※書く内容は4月初めに決めたのですが、投稿が遅くなってしまいました。

これからClojureを書き始める、書き始めようかなという人の参考になればいいなと思います。

Emacsを使った開発のために

Emacsのインストール

最初はEmacs For Mac OS Xを使って開発をしていたのですが、REPLと繋いでいる場合に落ちることがままありました。
そこでEmacs Mac Portを教えていただいて、乗り換えたところほぼ落ちることはなくなりました。快適です。
MacでEmacsを使う方はこちらをおすすめします。

Emacsの設定

基本的には@ayato_p さんが書いた、新: Emacs を使うモダンな Clojure 開発環境を参考にすればイケてる開発環境になると思います。

cider-mode.el

ciderのバージョンは0.12.0です。

  • cider-jack-in (C-c M-j)
    REPLに接続します。日々ここから作業スタートです。

  • cider-eval-defun-at-point (C-c C-c)
    現在カーソルのあるフォームを評価します。
    ある程度コードを書いたらほぼ無意識で使ってます。

  • cider-load-buffer (C-c C-k)
    名前空間(ファイル全体)を評価します。

  • cider-switch-to-repl-buffer (C-c C-z)
    コードとREPLを行き来します。僕は固定した場所にREPLを出しておくのではなく、これを使ってREPLと行き来するのが好きです。ほんとに便利。

  • cider-find-var (M-.)
    カーソル上のVarにジャンプしてくれます。タグジャンプですね。ただ、ライブラリやClojure.coreの関数にも飛んでいけるので非常に便利です。

  • cider-pop-back (M-,)
    IDEとかによくある"戻る"です。上のcider-find-varと組み合わせて使うことが多いです。

  • cider-eval-defun-at-point (C-u C-M-x)
    フォームにブレークポイントを貼ります。実行されるとデバッグモードに入り、nでステップ実行します。
    とても便利なのですが、たまにうまくデバッグモードに入らないときがあるのが困ったところ。

  • cider-repl-clear-output (C-u C-c C-o)
    REPLをクリアします。ターミナルのCtrl-lと一緒ですね。

  • cider-pretty-print (C-u C-c C-p)
    評価した結果をデータ構造が見やすいように表示してくれます。戻り値が意図したとおりのデータ構造になっているか確認するのに便利です。

  • cider-undef (C-c C-u)
    評価したフォームをundefします。色々書いてておかしいシンボルかぶったかな?と思った時に。
    正直使用頻度は低いです。

  • cider-doc (C-c C-d C-d)
    ドキュメントを参照します。僕はこれよりもClojureDocsで見ることのほうが多いのであまり使ってません。

  • cider-javadoc (C-c C-d C-j)
    ドキュメントを参照します。cider-docのJava版です。

clj-refactor.el

clj-refactorのうちよく使っているコマンドを紹介します。バージョンは2.0.0です。
なお、それぞれのコマンド名の右のかっこで書いたキーは、clj-refactorのprefixキーに続けて入力するキーを示しています。

例えば、僕はprefixキーをC-c jに割り当てているので、(ad)だとC-c j a dと打つことになります。

  • add require (ad) 新しいnamespaceをrequireするときに使います。 下のような状態になるのでTabで移動しながら入力します。
;;; before
(ns post.core
  (:require [plumbing.core :as pl]))

;;; after
(ns post.core
  (:require [plumbing.core :as pl]
            [ :as ]))
  • clean namespace (cn)
    名前空間の最初のns formにソートをかけ、使われていないものは削除してくれます。

  • wrap in thred first (tf)
    入れ子関数呼び出しになっている箇所をthread first macroに変えてくれます。

;;; before
(sql/from (sql/select :*) :hoge)

;;; after
(-> :*
    sql/select
    (sql/from :hoge))
  • wrap in thread last (tl)

入れ子関数呼び出しになっている箇所をthread last macroに変えてくれます。

;;; 初期状態
(map #(* % 2) (filter even? (range 1 10)))

;;; コマンド実行後
(->> 10
     (range 1)
     (filter even?)
     (map #(* % 2)))
  • unwind thread (uw)

threading macroを1段階解除してくれます。
例えば、上のwrap in thread firstwrap in thread lastの実行例では実行後に最初の値が飛び出していてあまり美しくありません。そこでこれを使い、以下のように修正します。

;;; before
(->> 10
     (range 1)
     (filter even?)
     (map #(* % 2)))

;;; after
(->> (range 1 10)
     (filter even?)
     (map #(* % 2)))
  • destructure keys (dk)

いちいちkeyを指定して取得するコードを書いてしまった時に、それらをdestructuringを使ったコードに直してくれます。

;;; before
(let [m {:hoge "ugeee" :fuga "ogeee"}]
  (str (:hoge m) (:fuga m)))

;;; after
(let [{:keys [hoge fuga]} {:hoge "ugeee" :fuga "ogeee"}]
  (str hoge fuga))

paredit.el

pareditはClojureに限らず、Lisp系言語を使うときには必須となるかっこのバランスを維持してくれる拡張です。
これについてはすでに、次の素晴らしい記事があります。この記事内で解説されている機能は全て日常的に使うものばかりです。

ParEdit チュートリアル

Clojure

これは便利だな!と思った関数

get-in/assoc-in/update-in

これらはいずれもネストしたデータ構造から簡単にデータを取得したり、変更したデータを作ったりするときにとても便利な関数です。

(def m [{:name "John"
         :profiles {:zip "111-1111"}}
        {:name "Mickel"
         :profiles {:zip "765-4321"}}])

;;; get-in
(get-in m [1 :profiles :zip])
;;=> "765-4321"

;;; assoc-in
(assoc-in m [1 :profiles] {:zip "123-4567"})
;;=> [{:name "John", :profiles {:zip "111-1111"}} {:name "Mickel", :profiles {:zip "123-4567"}}]

;;; update-in
(update-in m [0 :name] clojure.string/upper-case)
;;=> [{:name "JOHN", :profiles {:zip "111-1111"}} {:name "Mickel", :profiles {:zip "765-4321"}}]

vectorにもmapにもよしなにアクセスできていて大変素晴らしいですよね。

juxt

これも初めて知った時感動しました。
juxtについてはすでに以下の良い記事があります。

filter と remove のふたつの結果を簡単に受け取る方法

cond->/cond->>

cond->/cond->>を使うとthreading macroのそれぞれの関数適用に条件をつけることができます。

(let [condition-a true
      condition-b false
      condition-c nil]
  (cond-> "hoge"
    condition-a (str "-fuga")
    condition-b (clojure.string/capitalize)
    condition-c (clojure.string/split #"-")))
;;=> "hoge-fuga"

(let [condition-a true
      condition-b true
      condition-c nil]
  (cond-> "hoge"
    condition-a (str "-fuga")
    condition-b (clojure.string/capitalize)
    condition-c (clojure.string/split #"-")))
;;=> "Hoge-fuga"

(let [condition-a true
      condition-b false
      condition-c true]
  (cond-> "hoge"
    condition-a (str "-fuga")
    condition-b (clojure.string/capitalize)
    condition-c (clojure.string/split #"-")))
;;=> ["hoge" "fuga"]

開発中に参照している資料

書籍

  • Living Clojure
    Clojureの入門書です。この本の素晴らしいところは説明の構成です。前から読んでいけば段階的にわかるように書かれています。今現時点でこれ以上の入門書はないでしょう。

  • Clojure Applied
    他の言語でいう、Effectiveシリーズくらいのレベル感の書籍です。文法を超えて実践的にはどうすればいいのかって疑問に答えてくれます。僕もまだ読み途中です。

Web

31
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
25