LoginSignup
3
3

More than 5 years have passed since last update.

Clojure で文字列から関数(含む Java のメソッド)を実行する方法幾つか

Posted at

ちょっと色々検索してて目に入った中にタイトルのようなことをしようとしている記事が幾つかあって、何故か eval に行き着いてしまっていたりやたら複雑なことをしていたりしていたのでちょっと正しい方法とか書いておこうと思います。ちなみにどの言語でもそうだと思いますが eval は最終兵器であり基本的には使うべきではないものだと認識しています(だいたいやりたいことするための API は揃っている)。

同一ネームスペースの関数を実行する

(ns example.core)

(defn foo []
  "This is 'example.core/foo' function")

こういう foo 関数があった場合に同じネームスペースから文字列を用いて実行する場合は次のようにします。

((resolve (symbol "foo"))) ;;=> This is 'example.core/foo' function

違うネームスペースの関数を実行する

(ns example.other)

(defn bar []
  "This is 'example.other/bar' function.")

こういう関数が定義してあるネームスペースがあってこれを example.core から呼び出したいときはこう書きます。

(let [s "example.other/bar"
      k (keyword s)
      ns-sym (symbol (namespace k))
      name-sym (symbol (name k))]
  ((ns-resolve ns-sym name-sym))) ;;=> This is 'example.other/bar' function.

Java のメソッドを実行する

(let [c "java.lang.String"
      m "valueOf"
      args [200]]
  (clojure.lang.Reflector/invokeStaticMethod c m (into-array args))) ;;=> 200

clojure.lang.Reflector には他にも invokeInstanceMethod など欲しくなりそうなものがあるので困ったら覗いてみるといいかもしれません。

まとめ

Clojure にはだいたい「やりたい」と思うことを簡単にやる方法が既に用意されていることが多いです。ただ、それが日本語になっていないというだけで今回の問題も clojure function call from string などと検索すればだいたい出てきます。

元ネタ

途中で言及されている if を呼び出すのはちょっと正攻法じゃ出来ない気がしてます(スペシャルフォームは流石に Compiler レベルまで降りるか eval じゃないと無理じゃないかなぁ/単純に構文的な何かを作りたいならマクロで対処出来るんですけどね)。

流石にここまでして関数を動的に呼び出す人はいないと思いますが…。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3