Clojureでコマンドライン引数パースめも

tools.cliを用いれば簡単にできる。

導入

  • project.clj の :dependencies に以下を追記
[org.clojure/tools.cli "0.2.2"]

利用例

  • use に以下を追加
[clojure.tools.cli :only (cli)]
  • main関数の実装例
(defn -main [& args]
  (let [[options extra-args banner]
        (cli args
             ["-p" "--port"          "Listen on this port" :default 9999 :parse-fn #(Integer. %)] 
             ["-h" "--host"          "The hostname"        :default "localhost"]
             ["-v" "--[no-]verbose"  "Verbose"             :default true]
             ["-h" "--help"          "Show Help"           :flag true])]
    (if (:help options) (println banner) ; ヘルプオプションが指定された場合はbannerを表示して終了
        (my-function (:port options)     ; そうでない場合は、各オプションとオプション以外の引数を渡して主処理実行
                     (:host options)
                     (:verbose options)
                     extra-args))))
  • 実行例
lein run -- --help
;=>
;Usage:
;
; Switches                     Default     Desc
; --------                     -------     ----
; -p, --port                   9999        Listen on this port
; -h, --host                   localhost   The hostname
; -v, --no-verbose, --verbose  true        Verbose
; -h, --no-help, --help        false       Show Help

lein uberjar
java -jar target/該当のjar --help
;=> (同上)

lein repl
(use :reload 'myapp.core)
(-main "--help")
;=> (同上)

補足

  • cli 関数の戻り値は options extra-args banner からなるベクタ
    • options コマンドオプション部分をパースしてマップにしたもの
    • extra-args コマンドオプション以外の引数のベクタ
    • banner ヘルプ表示用の整形された文字列

ClojureコードのAPIドキュメント生成メモ

Codoxを使って簡単に生成できる。
Compojure、Hiccup、RingもCodoxを使ってAPIドキュメント生成しているよう。

導入

  • project.clj の :plugins に以下を追記
[codox "0.6.4"]

実行

下記コマンドを実行すると、docフォルダ内にAPIドキュメントが生成される。

lein doc

なお、ドキュメント化されるVarは以下を満たすもののみである。

  • パブリックである
  • doc-stringが指定されている
  • メタデータ「:no-doc true」が指定されていない

実行オプション

project.cljに追記する形で以下のオプション指定可能。

対象の指定
:codox {:sources ["path/to/source"]}
:codox {:exclude [my.private.ns another.private.ns]}
:codox {:include [library.core library.io]}
出力内容の指定
  • 異なる出力関数を用いるように指定
:codox {:writer codox.writer.html/write-docs}
  • APIドキュメント内にソースのURIへのリンクを出力(ソースをURIで参照できる場合のみ可能)
:codox {:src-dir-uri "http://github.com/clojure/clojure/blob/master"}
    • 関数のリンクについて、その関数の定義行のアンカーにダイレクトにリンクさせる
:codox {:src-dir-uri "http://github.com/clojure/clojure/blob/master"
        :src-linenum-anchor-prefix "L"}

Emacsの操作メモ

今更ながら、Emacsの操作メモ

ヘルプ

私はC-hをBSに当てて、ヘルプはC-?に当てている。
そのためC-h C-hは打てないので、ヘルプのヘルプは「M-x help-for-help」で参照する。

ヘルプサブコマンド
  • a コマンド名検索(apropos)
  • b 現在のキーバインド一覧(bindings)
  • k 指定したキーにバインドされているコマンドの表示(key)
  • w 指定したコマンドにバインドされているキーの表示(where)
  • f 指定した関数の説明を表示(function)
  • v 指定した変数の説明を表示(val)

シェル

  • M-! カレントバッファをカレントディレクトリとしてシェルコマンドを実行
  • M-x shell Emacs標準のシェル起動
その他の選択肢メモ
  • M-x ansi-term
  • multi-term(ansi-termの改良版)

検索(isearch)(C-s)中のコマンド

  • C-w 現在のカーソル位置の内容に沿って、検索文字を広げる
  • M-y 検索窓へのyank
  • C-h b キーバインド一覧(C-hを殺してると使えない。。)
  • C-h m ヘルプ(C-hを殺してると使えない。。)

その他

  • M-x grep grepの実行
  • M-% 置換
  • M-x Elisp関数の実行
  • M-; コメント化
  • M-g g 指定行へカーソルを移動

気になる拡張機能(要導入)

  • grep-edit
  • color-moccur
  • moccur-edit
  • wdired
  • undohist
  • undo-tree

(個人的)Clojureのコーディングルールめも

Clojureの個人的なコーディングルールを整理しておく。

シンボルの命名

全般
  • 「-」区切りの単語列
関数
  • 状態を変化させる関数には末尾に「!」を付与
  • 述語には末尾に「?」を付与
関数以外のvar
  • グローバルを意識したvarのシンボルには、接頭と末尾に「*」を付与
束縛
  • 値を気にしない束縛には「_」を使う

名前空間

  • プロジェクト内のライブラリは use で読み込む
  • 外部ライブラリは基本的に require :as で読み込む
    • 頻用する関数等、名前空間に直接読み込んだ方が明らかに可読性が上がる場合は use :only で読み込む
(参考)OSSプロジェクトでの例
  • プロジェクト内ライブラリの読み込み
    • require :as で読み込んでいる:Ring, Korma, ...
    • use で読み込んでいる:Compojure, Hiccup, ...

メタデータ

  • doc-stringは必ず記述する(nsおよび各種def)
  • :author を記述する?(←ソースに著者情報とか入れるべきか迷い中。clojure.coreのnsには記述されているが・・・。RingみたいにCONTRIBUTORS.mdとか作って関係者列挙とかの手もある)
  • :added で追加されたバージョンを明記する?(←同じく迷い中。バージョン管理システム側に任せて良い気もする)

スコープ

  • 純粋関数は基本的にグローバルで定義(defn)すること?(←迷い中。再利用奨励したいのが意図だが)
  • グローバルで定義した関数の外部仕様は無断変更禁止
    • 嫌なら defn- で定義すること

(参考)既存のコーディングスタイルガイド

  http://dev.clojure.org/display/community/Library+Coding+Standards

  https://google-styleguide.googlecode.com/svn/trunk/lispguide.xml

Clojureの基礎〜中身確認系、クオート、その他記号系〜

Clojureの基礎〜Clojureの特徴〜 - oknknicの日記」に引き続きClojureの基礎メモ。

中身確認系

  • #' varスペシャルフォーム(シンボルをvarに解決し、Varオブジェクトそのものを返す)に展開されるリーダーマクロ
#'str
; #'clojure.core/str

(meta #'str) ;メタデータの取得
; {:arglists ([] [x] [x & ys]), :ns #<Namespace clojure.core>, :name str, :column 1, :added "1.0", :static true, :doc "With no args, returns the empty string. With one arg x, returns\n  x.toString().  (str nil) returns the empty string. With more than\n  one arg, returns the concatenation of the str values of the args.", :line 504, :file "clojure/core.clj", :tag java.lang.String}
  • @ deref関数(参照先の値を返す)に展開されるリーダーマクロ
(def hoge (ref "hogehoge"))
@hoge
; "hogehoge"

(def toge "togetoge")
@#'toge
; "togetoge"

クオート

  • ' quoteスペシャルフォーム(評価されないフォームの生成(つまり単なるリストやシンボル))に展開されるリーダーマクロ
  • ` 構文クオート(一部をアンクオートできるクオート)のリーダーマクロ
  • ~ 構文クオート中のアンクオートのリーダーマクロ
  • ~@ 構文クオート中のスプライシングアンクオートのリーダーマクロ

その他、記号系

(def ^{:info "info-val"} metatest)
(meta #'metatest)
; {:info "info-val", :ns #<Namespace xml.core>, :name metatest, :column 1, :line 1, :file "NO_SOURCE_PATH"}

; なお、関数定義の場合は下記のようにメタデータを記載できる
(defn meta-test-fn "ドキュメント" {:metadata "メタデータ"} [] 1)
(meta #'meta-test-fn)
; {:arglists ([]), :metadata "メタデータ", :ns #<Namespace xml.core>, :name meta-test-fn, :column 1, :doc "ドキュメント", :line 1, :file "NO_SOURCE_PATH"}

; :tagメタデータ(戻り値および引数の期待する型)は下記のように略記可能
(defn ^String upper [^String s] (.toUpperCase s))
  • -> 第1引数を引数として第2引数の関数を実行し、その結果を引数として第3引数の関数を実行、・・・この繰り返し
(defn square [x] (* x x))
(-> 2 square square)
; 16
  • #{リスト} セットのフォーム
  • #"正規表現" 正規表現パターン(java.util.regex.Pattern)に展開されるリーダーマクロ
  • #フォーム 無名関数のリーダーマクロ
  • 名前# 自動gensym(構文クオートされたコード内で、指定された名前を接頭辞とするユニークな名前を生成)

参考

プログラミングClojure 第2版

プログラミングClojure 第2版

Clojureの基礎〜Clojureの特徴〜

Clojureの基礎〜名前空間〜 - oknknicの日記」に引き続き基礎メモ。
基本に立ち返って、Clojureの特徴を整理。

Lispである

構文をほとんどもたず、同図像性がある
  • 言語を拡張し易い
    • コードはデータであるため、コードを生成するコード(メタプログラム)を簡潔に記述できる
    • コードを生成するコードを記述する仕組みであるマクロ
    • マクロにより、実装対象の領域に合わせて言語拡張(DSL開発)(ボトムアップ開発)
関数型言語(ただし非純粋)
  • 関数が第一級のオブジェクト
    • 実行時に関数を生成できる
    • 関数を引数にした関数を定義できる(高階関数
    • 関数を返す関数を定義できる
  • 純粋関数は副作用をもたない
    • データは不変になるため、必然的にスレッドセーフ
    • 複数の関数を組み合わせても、想定外の相互作用が発生し辛い
  • 純粋関数は参照透過性をもつ
    • 遅延評価できる
    • メモ化できる
    • 並列化できる
  • 関数実行に必要な情報は引数のみである
    • 引数のみ準備すればよいため、テストし易い
非純粋関数型言語としての特徴
  • 副作用のサポート
    • 参照、エージェント、アトム、そしてソフトウェアトランザクショナルメモリ
    • 動的束縛

JVM上で動く

  • JVMは安定した基盤である
  • 多くの環境に導入されているため、実行環境の敷居が低い
  • 豊富なライブラリを直接利用可能である
  • 再帰における末尾呼び出し最適化はできない(JVMの制約)
    • 自己再帰(recur)や遅延評価による対処は可能

JVM以外でも動く

  • ClojureScript
  • ClojureCLR

その他便利な点

参考文献

プログラミングClojure 第2版

プログラミングClojure 第2版

nrepl.el(nREPLのEmacsクライアント)の使い方メモ

EmacsでClojure開発環境構築メモ - oknknicの日記」でも少し言及したnrepl.el。
今回は実用メモ。

REPL操作

REPLの起動
  • C-c M-j nREPL-Server と Client を起動し、Client から Server へ接続
    • leiningenで生成したプロジェクトのcljファイルを開いた状態で実行すると、そのプロジェクトのREPLが起動
    • C-u を前段で実行すると、プロジェクトをエコーエリアで選択可能
  • C-c C-z REPLバッファにカーソルを移動
REPL操作
  • TAB シンボルのコンプリート
  • C-j 改行+インデント
  • C-RET 必要な括弧を全て閉じた上で評価
  • C-c M-o REPLバッファのクリア

エディタ操作

なお、以下の操作は C-右クリック で選択して実行も可能。

REPLへ影響を与える操作
  • C-c M-n REPLのネームスペースを、現在のバッファのネームスペースへスイッチ
  • C-c C-k 現在のバッファを読み込み
  • C-c C-l プロジェクト外ファイルの読み込み(エコーエリアでファイル指定)
  • フォームを評価し、結果をエコーエリアに表示
    • C-c C-c カーソル位置のトップレベルフォームを評価
    • C-c C-r 選択範囲のフォームを評価
    • C-x C-e カーソル位置直前のフォームを評価
編集補助
  • M-TAB(ESC TAB) シンボルのコンプリート
カーソル移動
  • M-. シンボルの定義へ移動
  • M-, 移動前へ戻る
情報表示
  • C-c C-d カーソル位置のシンボルのドキュメントを表示
  • C-c C-s カーソル位置のシンボルのソースを表示
  • C-c C-j カーソル位置のシンボルのJavaDocを標準ブラウザで表示
マクロエキスパンド
  • C-c C-m カーソル位置のシンボルをmacroexpand-1し、別バッファへ表示
  • C-c M-m カーソル位置のシンボルをclojure.walk/macroexpand-allし、別バッファへ表示

参考:nREPLサーバをClojureアプリケーションに組み込む

project.cljに追記

[org.clojure/tools.nrepl "0.2.3"]

アプリケーションに追記

(use '[clojure.tools.nrepl.server :only (start-server stop-server)])
(defonce server (start-server :port 7888))