Clojure を学ぶ 公式サイト編2
以前、ちょっとだけかじった事があった Clojure を、もういっかい勉強中。
公式な日本語ドキュメントもあるけど、自分なりにまとめていきます。
https://clojure.org/guides/learn/functions
関数の宣言
; 定義
;; 名前 引数 本体
;; ----- ------ -------------------
(defn greet [name] (str "Hello, " name) )
;
; 呼び出し
(greet "world")
=> "Hello, world"
;
; 引数の数毎に関数を定義できる
(defn messenger
([] (messenger "Hello world!"))
([msg] (println msg)))
(messenger)
=> Hello world!
nil
(messenger "Hi there!")
=> Hi there!
nil
;
; 可変引数は、引数リストの最後に「&」の後ろ。
(defn hello [greeting & who]
(println greeting who))
;可変引数はリストで入っている
(hello "Hello" "Nancy")
=> Hello (Nancy)
nil
(hello "Hello" "Nancy" "Masao")
=> Hello (Nancy Masao)
nil
;
; 無名関数
((fn [message] (println message)) "Hello world!" )
; 無名関数の省略形
#(+ 6 %) ;(fn [a] (+ 6 a))
#(+ %1 %2) ;(fn [a b] (+ a b ))
#(println %1 %2 %&) ;(fn [a b & cs] (println a b cs)) 可変引数
; 引数をVectorにして返す関数を省略形で書く場合
(#([%]) 1) ;NG ([x] ([x]))こう展開されてエラーになる
(#(vector %) 1) ;ok
((fn [x] [x]) 1) ;ok
(vector 1) ;これがシンプル
;
;defn = def + fn
(defn greet [name] (str "Hello, " name))
(def greet (fn [name] (str "Hello, " name)))
apply
(apply f '(1 2 3 4))
(apply f 1 '(2 3 4))
(apply f 1 2 '(3 4))
(apply f 1 2 3 '(4)) ;全て(f 1 2 3 4)と同じ
;
(defn plot [shape coords] ;coords = [x y]
(plotxy shape (first coords) (second coords)))
;↓こう書ける
(defn plot [shape coords]
(apply plotxy shape coords))
let
;let で定義された名前は、外部コンテキスト内の名前よりも優先
(let [A 2]
(let [A 1]
(println A))
(println A))
(println A)
=> 1
2
Unable to resolve symbol: A in this context
Closure
(defn messenger-builder [greeting]
(fn [who] (println greeting who)))
;
(def hello-er (messenger-builder "Hello"))
;
;; greetingはスコープ外だが、hello-er はクロージャなので、"Hello"は有効
(hello-er "world!")
=> Hello world!
Java 相互運用
;
new Widget("foo"); //java
(Widget. "foo") ;Clojure
;
rnd.nextInt();
(.nextInt rnd)
;
object.field;
(.-field object)
;
Math.sqrt(25);
(Math/sqrt 25)
;;
Math.PI;
Math/PI
;
;;javaのメソッドは、Clojureの関数ではないので、
;;束縛したり引数として渡せない。
;;必要に応じてラップできる
(fn [obj] (.length obj))
#(.length %)
確認問題
:; 1. 引数を取らず、"Hello "を表示する関数greetを定義せよ
(defn greet [] (println "Hello"))
;
;; 2. 最初に fn 特殊形式を使用し、次に #() リーダーマクロを使用して、def を使用して greet を再定義せよ。
(fn [] (println "Hello"))
#(println "Hello")
(def greet (fn [] (println "Hello"))
;
;; 3. グリーティング関数を定義します。
; 引数がない場合、"Hello, World!"を返します。
; 引数 x が 1 つ与えられると、"Hello, x!"
; 2つの引数xとyが与えられると、"x, y!"
(defn greeting
[] "Hello, World!"
[x] (str "Hello, " x "!")
[x y] (str x ", " y "!"))
;
;; 4. 単一の引数xを取り、変更せずに返す関数do-nothingを定義せよ
(defn do-nothing [x] x)
;
;; 5. 任意の数の引数を取り、それらのすべてを無視して、数値100を返す関数always-thingを定義せよ
(defn always-thing [& xs] 100)
;
;; 6. 単一の引数xを取る関数make-thingyを定義せよ。これは、任意の数の引数を取り、常にxを返す別の関数を返す必要があります。
(defn make-thingy [x]
(fn [& xs] x))
;
;; 7. 別の関数を取り、引数なしで3回呼び出す関数triplicateを3つ定義せよ
(defn triplicate [f]
(f)(f)(f))
;
;; 8. 単一の引数fを取る関数opposite を定義せよ。これは、任意の数の引数を取り、fをそれらに適用し、結果を呼び出さない別の関数を返す必要があります。
(defn opposite [f]
(fn [& args] (map f args)))
;
;; 9. 別の関数と任意の数の引数を取り、それらの引数に対してその関数を3回呼び出す関数triplicate2を定義せよ。
; 前に定義したtriplicate関数を再利用。
(defn triplicate2 [f & args]
(triplicate (partial f args))
;
;; 10. java.lang.Mathクラスを使用して、以下の数学的な事実を示せ。
;PIのコサインは-1
(==
-1
(Math/cos (Math/PI)))
=> true
;sin(x)^2 + cos(x)^2 = 1
((fn [x]
(== 1
(+
(Math/pow (Math/sin x) 2)
(Math/pow (Math/cos x) 2))))
2)
=> true
;
ディスカッション
コメント一覧
まだ、コメントがありません