Clojure入門中です。Scalaをやっていたので、Scalaのapplyとは明らかに異なるapply関数に戸惑いました。
そこでメンターが色々と教えてくれたので、咀嚼するために(+世の中に還元できたらいいなという気持ちで)軽くまとめました。
Clojureにおけるapplyとは
可変長引数と対になるようなもので、最終引数のシーケンスの中身を取り出して適用してくれる。
まあ概要はこんな感じ。以下で説明していく。
そもそも可変長引数ってどんなのだっけ
可変長引数(variable argument)とは、関数に与えた0個以上の実引数を1つのシーケンス(≒リストのようなもの)にまとめてくれるもの。
& <名前>
で可変長引数にできる
dev> (defn hello [& who]
(println who))
#'dev/hello
dev> (hello "hoge")
(hoge)
nil
dev> (hello "hoge" "hoge")
(hoge hoge)
nil
標準ライブラリの+
, -
, *
, /
も可変長引数関数
dev> (+)
0
dev> (+ 0)
0
dev> (+ 1 2)
3
dev> (+ 1 (- 1 2 3) (* 1 2 3))
3
で、可変長引数だと何ができないのか
ベクター [1 2 3]
があって可変長引数関数 +
を適用しようとしたとき、単純に適用することはできない。
dev> (let [xs [1 2 3]]
(+ xs))
Execution error (ClassCastException) at java.lang.Class/cast (Class.java:3606).
Cannot cast clojure.lang.PersistentVector to java.lang.Number
+
は引数として0個以上の数値(java.lang.Number
)型の値を期待している。
とはいえ、ベクターの個々の要素を手でバラバラにして適用するのは汎用性に欠ける
そこで apply
の出番。
じゃあapplyをどうやって使う?
シンプルに apply
をつければいい。
dev> (apply + 1 2 3 [4 5])
15
dev> (apply + [1 2 3 4 5])
15
上記はいずれも(+ 1 2 3 4 5) と等価である。
Clojureでは標準ライブラリ関数にも可変長引数関数がとても多いらしく、コレクション(シーケンス)に可変長引数関数を適用したい状況で apply
をよく使うとのこと。
最後に
勉強したことを整理するために備忘録的に書きました。
何か間違っていることや補足したい点があったら優しくマサカリを投げてください。