Skip to content

Instantly share code, notes, and snippets.

@alphaneet
Created November 11, 2011 18:47
Show Gist options
  • Save alphaneet/1358834 to your computer and use it in GitHub Desktop.
Save alphaneet/1358834 to your computer and use it in GitHub Desktop.
プログラミングClojure 勉強メモ 第1章 Getting Started. つhttp://d.hatena.ne.jp/alpha_neet/20111112/1321086082
;;; defn で関数の定義。引数は [] で囲む
(defn hello-work [a, b]
;; format を使うと printf ライクに書ける
(println (format "hello work %s %s" a, b)))
;;; 純粋 Lisp は空白を区切りとして扱うが、Clojure は「 , も空白として扱う」らしい
;;; 下記は両方とも意味は同じ
(hello-work "comma", "test")
(hello-work "space" "test")
;;; 値に名前を付けるには def を使う
;;; def は defn の違いは後述
(def PI "3.14なんちゃらかんちゃら")
(def Num 12345)
(def Persons ["dani-" "joni-" "annjero"])
(println PI)
(println Num)
(println Persons)
;;;; 関数型言語では「変数(副作用があるデータ)」は基本的には使わないが、
;;;; 純粋でない関数型言語である Clojure(Lisp) では変数を扱うことが出来る。
;;;; しかし常にトランザクション(doSync)内でしか変更することが出来ない。
;;;; だが、これにより常に並行プログラミングになっている(はず)
;;; 変数の定義には ref(リファレンス)を使用する
;;; Integer
(println (ref 0))
;;; String
(println (ref ""))
;;; Vector
(println (ref []))
;;; Set
(println (ref #{}))
;;; リファレンスに名前を付けるにも def を使う
(def kazu (ref 0))
(def moji (ref ""))
(def bekuta (ref []))
(def setto (ref #{}))
;;; alter は Java とかでいう = のようなもので代入(破壊的更新)
;;; トランザクション(doSync)を噛ませてない代入は例外が出る
;;; (alter kazu + 3) ; <= java.lang.IllegalStateException: No transaction running
(println (dosync (alter kazu + 3)))
;;; str は与えられた引数をくっつけて文字列にする関数
(println (dosync (alter moji str "oppai")))
;;; conj は要素を追加する関数
;;; よく分からないが型は大分柔軟っぽい
(println (dosync (alter bekuta conj 1 1 2 "oppai" 2 3 4)))
;;; #{} は Set なのでユニークな値で満されている
(println (dosync (alter setto conj "hoge" "hoge" "moge" 1 2 2 2)))
;;; defn は必ず引数を取らないと例外が出る
;;; (defn hoge (println "test")) ; <= java.lang.IllegalArgumentException: Parameter declaration println should be a vector
;;; def は逆に引数があると例外が出る
;;; (def moke [a] (println "aiueo")) ; <= java.lang.Exception: Too many arguments to def
;;; def は定義時に評価されるが、defn は呼び出し時に評価される。
;;; def(clojure) は val(scala) で defn(clojure) が def(scala) のような感じっぽい。
(println "===== 定義")
(def a (println "--- def"))
(defn b [v] (println "--- defn"))
(println)
(println "===== 呼び出し")
(println a)
(println b) ; 関数オブジェクトを取得してる感じだろうか?
(println (b "v")) ; 括弧を付けると関数呼び出し
;;; 別のファイルを読み込む時は require を使う。
;;; ファイルを $CLASSPATH の中から検索する。
;;; 名前に - を使用した場合、実際のファイル名の方は _ にするっぽい。
;;; 複数該当があったらどうなるのか謎 -> 多分例外 -> 調べるのめんどかったれす^q^
(require 'no-ns)
;;; だと $CLASSPATH/no_ns.clj を読み込む。
(println hatarake)
;;; ディレクトリを潜りたかったら . で区切る
(require 'libs.dir-test)
;;; だと $CLASSPATH/libs/dir_test.clj を読み込む。
(println oppai)
;;; java の package っぽく ns で名前空間を付けることが出来る
;;; ns は name space の略だと思われ
(require 'libs.use-ns)
;;; 使用する時は 名前空間名/関数名 にする
(libs.use-ns/echo "aiueo")
;;; requireパス と namespace名 は言語仕様上は同じでなくても動くっぽい
;;; でも明らかに慣習として namespace の位置にファイルを配置すること推奨っぽい
(require 'libs.tekitou)
(println nandemoii/shinpi)
;;; 毎回 namespace/function と書くのがめんどくさい場合は require の後に refer を呼ぶ
(require 'refer-test)
(println refer-test/kazu)
(refer 'refer-test)
(println kazu)
;;; use を使えば require と refer を同時にしてくれる
;;; scala の object import 的なノリ
(use 'use-test)
(println jojo)
;;; 一度読んだライブラリを再読み込みしたい場合は :reload-all フラグを付ける
(use :reload-all 'use-test)
;;; doc を使えば関数のドキュメントが見れる
(println (doc str))
;;; 自分で定義した関数にも使える。
;;; 関数にドキュメント(doc-string)を付けるには関数名の直後に文字列を置く
(defn hoge
"どきゅきゅきゅきゅーん"
[a]
(println a))
(println (doc hoge))
;; 名前をなんとなくしか覚えていない場合は find-doc を使う
;; 関数名だけでなく doc-string にもマッチしているっぽ
(println (find-doc "conj"))
;;; 関数のソースコードを見たい場合 clojure.repl/source を使う
(use 'clojure.repl)
(println (source str))
;;; Clojure は全て Java オブジェクトなので、
;;; clojure.contrib.repl-utils で裏にある Java API も見ることが出来る
;;; 通常の clj では contrib がないっぽいんですが、leiningen にはあるっぽいので、
;;; lein repl 上で load-file して使ってください。
;;; use は何か名前衝突が起きてるっぽいので例外が出ますので、require を使います
;;; (use 'clojure.contrib.repl-utils) ; <= java.lang.IllegalStateException: source already refers to: #'clojure.repl/source in namespace: user
(require 'clojure.contrib.repl-utils)
(println (clojure.contrib.repl-utils/show str))
;;; 自分で定義した関数は source は見れないが、show は見れる
(defn mymy [a]
(println "maimai"))
(println (source mymy)) ; <= Source not found
(println (clojure.contrib.repl-utils/show mymy))
;;; 値が何のクラスかを表示するには class を使う
(println (class ""))
(println (class 3))
(println (class []))
;;; 値があるクラスのインスタンスかどうかを判定するには instance? を使う
(println (instance? String ""))
(println (instance? String 3))
;;; 継承されいるクラスやインターフェースの一覧表示をしたい場合は ancestors を使う
(def bekuta (ancestors (class [])))
;;; どうやら HashSet らしいので順不同っぽい
;;; なぜ ruby のような継承ツリー(もどきでいいから)の配列を返さないのら。。。
(println (class bekuta))
(use 'clojure.pprint)
(pprint bekuta)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment