Clojure簡易まとめ
目次
文法
関数
; ---------------------------------------- ; fnを利用 ; ---------------------------------------- ; (fn [x y] (* x y)) (println ((fn [x y] (* x y)) 1 2)) ; => 2 ; ---------------------------------------- ; #を利用 ; ---------------------------------------- ; #(* %1 %2) (println (#(* %1 %2) 1 2)) ; => 2
- %1, %2について
short-handで定義した場合の引数は%と番号で表す。
なお1つ目の引数は%のみでも表せる。
; #(* % %) (println (# (* % %) 2)) ; => 4
- デフォルト値は多重定義かオプショナル引数で行う
; 多重定義 (defn add ([x] (add x 1)) ([x y] (+ x y))) ; オプショナル引数 (defn add [x & {:keys [y] :or {y 1}}] (+ x y))
命名(def)
- def関数を利用して命名する
; 変数 (def x 100) ; 関数 (def mul (fn [x y] (* x y)))
- 関数はdefnマクロを使うと楽
; 上記の関数命名は、下記のように書ける (defn mul [x y] (* x y))
一時変数
; 使い方 (let [x 1, y 1] (println (+ x y)) (let [x 1 y 1] (println (+ x y)))
NOTE
変数の定義時に、横に並べる場合、カンマを入れると見やすくなる。
カンマを入れない場合、自由変数に束縛変数を入れると、[x a y b]のようになったりする。
コレクション
; 線形リスト '(1 2 3) ; マップ(ハッシュテーブル) {:x 100 :y 200} ; 集合 #{10 20} (set '(10 20 10)) ; <=> #{10 20} (集合は要素がユニークになる) ; ベクタ [1 2 3]
メタデータ
- すべてのデータは、メタデータを持てる
; データ (def vect [1 2 3 4]) ; メタデータ付与 (def vect-with-meta (with-meta vect {:music :be-ok})) ; メタ情報アクセス (:music (meta vect-with-meta)) ; => :be-ok ; (?) (meta vect-with-meta)でメタ情報のマップを作っているのかな?
コレクション関数
ここが参考になると思う(yuwki0131-blog: Clojure(1.3-1.4)のリスト/ベクタ(シーケンス)操作関数一覧)
条件文
- 条件文はif,when,if-let,when-letなどを使う
; ---------------------------------------- ; if関数 ; ---------------------------------------- ; 基本形 (if condition then-expr else-expr) ; 例 ; (then-expr, else-exprは単一Object?のみ指定可能 ; 複数処理を行いたい場合はdoで囲む) (defn even-printer [n] (if (= (mod n 2) 0) ; condition (println "Even!") ; then-expr (println "Odd!"))) ; else-expr (defn even-printer2 [n] ; 複数処理Ver (if (= (mod n 2) 0) (println "Even!") (do (println "Odd!") (println "Odd2!")))) ; ---------------------------------------- ; when関数 (Else節が不要な場合はこっちを使う) ; ---------------------------------------- ; 基本形 (when condition expr1 expr2 ...) ; 例 (defn even-printer [n] ; condition (when (even? n) (println "Even1") ; expr1 (println "Even2") ; expr2 (println "Even3"))) ; expr3 ; ---------------------------------------- ; if-letマクロ ; ---------------------------------------- (defn p-next [lst] (if-let [element (first lst)] (println "Exist Element : " element) (println "No Elements"))) ; ---------------------------------------- ; when-letマクロ ; ---------------------------------------- (defn p-next [lst] (when-let [element (first lst)] (println "First : " element) (println "First : " element)))
遅延評価
- 値が必要になるまで、実際の計算を行わないこと
- 用語
- promise : 実際に計算を行われていない中間状態
- thunk : 計算の実体
- force : 値の計算(promiseをforceする)
; 無限リスト(正整数の生成) (defn inf-list ([] inf-list 0) ([n] (cons n (lazy-seq (inf-list (inc n)))))) ; 実行例 (println (inf-list)) ; => (0 1 2 3 ...) Infinity (println (take 3 (inf-list))) ; => (0 1 2) (println (take 3 (inf-list 100))) ; => (100 101 102)
ループ(再起処理)
; ---------------------------------------- ; Loop利用Ver (推奨) ; ---------------------------------------- (defn fact [n] (loop [i n result 1] (if (zero? i) result (recur (dec i) (* result i))))) ; ---------------------------------------- ; 通常のRecursive (非推奨?) ; ---------------------------------------- (defn fact [n] (if (zero? n) 1 (* n (fact (dec n)))))
多態性
- マルチメソッド(Nyampass tech blog: 実践(?)Clojure「マルチメソッド」)
- 多重ディスパッチ(多重ディスパッチ - Wikipedia)
- defmultiでマルチメソッドを定義し、defmethodでディスパッチメソッドを指定する
; ---------------------------------------- ; マルチメソッドでcase文的なもの ; ---------------------------------------- (defmulti class-checker class) (defmethod class-checker Integer [arg] (println "Integer!")) (defmethod class-checker Double [arg] (println "Double!")) (defmethod class-checker String [arg] (println "String!")) (defmethod class-checker :default [arg] (println "Other!")) ; (class-checker 1) ; => Integer! ; (class-checker 1.0) ; => Double! ; (class-checker (def x 100)) ; => Other! ; ---------------------------------------- ; 他の例 ; ---------------------------------------- (defmulti func (fn [x y] [(class x) (class y)])) (defmethod func [Integer Integer] [x y] (Math/pow x y)) (defmethod func [Double Integer] [x y] (Math/pow x y)) (defmethod func :default [_ _] 'other) ; (println (func 2 10)) ; => 1024.0 ; (println (func 2.0 10)) ; => 1024.0 ; (println (func "A" "B")) ; other
JavaAPI呼び出し
; 初期化は"new", "."(マクロ)を用いて行う (new java.lang.Double "100") (java.lang.Double. "100") ; java.langはデフォルトでimportされているので、下記でもよい (new Double "100") (Double. "100")
; インスタンス作成 (def value1 (Double. 10.0)) (def value2 (Double. 20.0)) (def value3 (Double. 10.0)) ; メソッド呼び出しは"."マクロを利用する ; *なお、下記の1つ目の呼び出しは"."の後に空白を入れないこと。 (.compareTo value1 value2) ; => -1 (. value1 compareTo value3) ; => 0
; "."または"/"を利用する ; static field (println (. Math PI)) ; => 3.14... (println Math/PI) ; => 3.14... ; static method (println (Double/parseDouble)) ; => 10.0 (println (. Double parseDouble)) ; => 10.0
; "memfn"又は"#"(無名関数)を利用 ; memfnを利用する場合 (map (memfn toUpperCase) ["do it" "do it"]) ; #を利用する場合 (map #(.toUpperCase %1) ["do it" "do it"])
- 間接参照(method chain的な)
- method chain的な感じで、連続的に関数を呼ぶ場合
".."又は"->"を利用する- ".." JavaAPI専用
- "->" clojureも呼べる
- method chain的な感じで、連続的に関数を呼ぶ場合
; Java API専用なので"."を端折れる (.. (Double/valueOf 10.0) toString length) ; clojureも呼び出し可能なので、JavaAPIを利用した場合は"."を付ける必要がある (-> (Double/valueOf 10.0) .toString .length)
; 1. Creates an instance (String. "doit doit") ; 2. Calls a static field/method Math/PI (Math/abs -10) ; 3. Calls a method (.length "DOIT") ; 4. 間接参照 (.. (Double/valueOf 10.0) toString length) (-> (Double/valueOf 10.0) .toString .length)
- Thread (Java API)
- TODO : 後でもうちょっと詳しくまとめる
(defn delayed-print [ms text] (Thread/sleep ms) (println text)) (.start (Thread. #(delayed-print 100 "wwwwwww"))) (print "grass")
; ---------------------------------------- ; 1. File出力 ; ---------------------------------------- (binding [*out* (java.io.FileWriter. "__my.log")] (println "YHVH1") (println "YHVH2") (println "YHVH3") (println "YHVH4") (println "Lucifer") (flush)) ; => "__my.log"が作成され、YHVH...が記述される ; ---------------------------------------- ; 2. File入力 ; ---------------------------------------- (with-open [ fr (java.io.FileReader. "__my.log") br (java.io.BufferedReader. fr)] (doseq [line (line-seq br)] ; line-seqはbuffer行の遅延シーケンスを返す ; doseqはシーケンスに対するループ (print line)))
マクロ
- Clojure - Macro入門 - Playground of oursがわかりやすいので参照する事。
又はClojure のリーダーマクロについて (lisp reader macro advent calendar 2012 の記事です)。 · GitHub - "~"(unquote)はcommon lispで言うところの","に相当
(","はclojureでは空白の意味になるので) - "~@"(unquote splice reader macro)個々の要素に分解する
(pythonの"*"に似たもの) - "#"を利用するとユニークな名前のシンボルを生成する(auto-gensym)
- "`"(backquote)を利用してテンプレートを作成する
- TODO : 後でまとめる
ライブラリ利用
; ---------------------------------------- ; 1. require関数を利用 ; ---------------------------------------- ; 基本形 (require 'clojure.string) ; => (clojure.string/join \, ["H" "M"]) ; option(as)を利用 (require '[clojure.string :as str]) ; => (str/join \, ["H" "M"]) ; option(refer)を利用 (require '[clojure.string :refer [join]]) ; => (join \, ["H" "M"]) ; option(refer)による全関数取得 (require '[clojure.string :refer :all]) ; ---------------------------------------- ; 2. use関数を利用 ; ---------------------------------------- ; 非推奨(1.4以降)らしい
; 下記の様に呼び出す (import '(java.math BigDecimal BigInteger)) (import java.io.InputStream) (import '(java.util List Set) '(java.net URL)) ; 利用例 (println (BigDecimal. 100.0)) (println (BigInteger. "10000"))
; ---------------------------------------- ; 0. フォルダ構造 ; ---------------------------------------- basedir ├── lib │ ├── another.clj │ ├── another_math.clj │ └── calc │ ├── core.clj │ └── core_math.clj ├── main.clj └── utils.clj ; ---------------------------------------- ; 1. main.clj ; ---------------------------------------- #^:shebang '[ java -cp "$CLOJUREPATH/clojure-1.6.0.jar:./" clojure.main "$0" "$@" ] ; 起動時にクラスパスを適切に設定する ; (今回は同フォルダ以下のファイルを参照するので、カレントディレクトリ(./)をクラスパスを指定する) ; モジュール読み込み (require 'utils) (require 'lib.another) (require 'lib.calc.core) ; (utils/hello) (println (lib.calc.core/myadd 1 2)) (println (lib.another/mymul 2 4)) ; ---------------------------------------- ; 2. utils.clj ; ---------------------------------------- ; ここの名前空間はファイル名と一致させておく (ns utils) (defn hello [] (println "HELLO")) ; ---------------------------------------- ; 3. another.clj ; ---------------------------------------- ; フォルダ名と一致させる(lib) & ; 名前空間をファイル名と一致させる(another) & ; 分割したモジュールを読み込む (load "another_math") (ns lib.another (load "another_math")) ; ".clj"の部分は入れない ; ---------------------------------------- ; 4. another_math.clj ; ---------------------------------------- (in-ns 'lib.another) ; ベースとなるモジュールと同じ名前空間にする (defn mymul [x y] (* x y)) ; ---------------------------------------- ; 5. calc.clj ; ---------------------------------------- ; こっちも同様にする (ns lib.calc.core (load "core_math")) ; ---------------------------------------- ; 6. calc_math.clj ; ---------------------------------------- (in-ns 'lib.calc.core) (defn myadd [x y] (+ x y))
Note(参考)
- 参考1(JavaAPI呼び出し全般)
clojureプログラミング入門-5 Javaの呼び出し - すにぺっと- 参考2(".."マクロについて)
点々マクロ (..) はもっと評価されるべき - tnoda-clojure- 参考3(マクロについて)
Clojure - Macro入門 - Playground of ours- 参考4(リーダマクロについて)
又はClojure のリーダーマクロについて (lisp reader macro advent calendar 2012 の記事です)。 · GitHub- 参考5(外部ファイル利用(import/require))
Clojureの忘れっぽいrequire、use、import - CLOVER
用語とか
first-class object
生成、代入、演算、受け渡しなどが無制限に使用できる対象の事。 定義としては、以下の能力を持つプログラムの事を言う。
DEF
オブジェクトに名前が付けられる
(defを使った命名とかかな?)引数として関数・手続きに渡す事ができる
(手続き?)結果値として関数から帰ってくる事ができる
(戻り値を"関数"としてもよいという事)データ構造に組み込む事ができる
(データ構造 : class, struct, dict, listなど
組み込む?)
History
version | date | memo |
---|---|---|
0.1 | 2015/03/21 | first create |
0.2 | 2015/03/22 | JavaAPI関連追加 |
0.3 | 2015/03/25 | 名前空間,ファイル分割追加 |
0.4 | 2016/12/17 | 文字化け修正 |
Information
Using(SW etc) | version |
---|---|
Ubuntu | 12.04 |
Clojure | 1.6.0 |
MEMO
- macro調査
- namespace調査
Note(参考)