昨日は無名関数について簡単に勉強したので今日は名前付き関数について勉強してみる。
モジュール・関数については、は参考書籍として使っているプログラミングElixirの6章で説明があるので読みながら勉強してみる。
- 作者: Dave Thomas,笹田耕一,鳥井雪
- 出版社/メーカー: オーム社
- 発売日: 2016/08/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
モジュールと名前付き関数
名前付き関数はモジュールの内側で書く必要があるそうだ。
6章のtimes.exsを写経して動かしてみた。
defmodule Times do def double(n) do n * 2 end end
モジュールの定義は
defmodule モジュール名 do end
と書く。do~endで囲むあたりはrubyと似ている。
名前付き関数は、モジュールの内部で、
def 関数名(引数) do end
とすればよいみたい。
elixirは動的型付けなので引数は引数名だけでよい。
ファイルに書いたコードを実行するためにはいくつか方法がある。
1.iexの起動時に引数でファイル名を指定してロードする方法。
iex times.exs
2.iex内でc ファイル名として、c ヘルパーの機能でロードする方法。
コンパイルコマンドであるelixircを使う方法はここでは紹介されていない。
検索してみても見つからなかったのでこの本自体ではelixircに関する説明がなさそうだ。
名前付き関数の呼び出しは
モジュール名.関数名(引数)
の形になる。
iex(1)> Times.double(3) 6 iex(2)>
気になって試したこと
- iex ファイル名を指定して読み込めるのは1ファイルだけのようだ。2ファイル目以降を指定してもロードされていないっぽい。
- モジュール名は大文字で、関数名は小文字ではじめないといけないみたい。
defmodule times do def double(n) do n * 2 end end
や
defmodule Times do def Double(n) do n * 2 end end
はコンパイルに失敗する。コンパイルに失敗するとiexは起動せずエラーメッセージが出力されて終了する。
$ iex times.exs Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] =INFO REPORT==== 10-Sep-2017::15:42:48 === application: logger exited: {{shutdown, {failed_to_start_child,'Elixir.GenEvent', {undef, [{gen,debug_options,[[]],[]}, {'Elixir.GenEvent',init_it,6, [{file,"lib/gen_event.ex"},{line,538}]}, {proc_lib,init_p_do_apply,3, [{file,"proc_lib.erl"},{line,247}]}]}}}, {'Elixir.Logger.App',start,[normal,[]]}} type: temporary ** (CompileError) times.exs:1: undefined function times/0 (elixir) expanding macro: Kernel.defmodule/2 times.exs:1: (file)
iexの起動時にINFO REPORT==== というのがでているがこれは何なのかよくわかっていない。
別に害があるわけではないけどなんか気になる。
今は意図的に失敗させてわけだけど、このエラーメッセージから間違いに気づくのは慣れないと難しいかもしれないな。
ちなみに先頭以外は大文字でも小文字でもよくて、
defmodule TIMES do def dOuble(n) do n * 2 end end
は問題なくコンパイルが通る。
- モジュール外で関数は定義できない。
モジュールの外側で関数を定義しようとするとどうなるか?
def double(n) do n * 2 end
コンパイル時のメッセージは以下の通り、
** (ArgumentError) cannot invoke def/2 outside module (elixir) lib/kernel.ex:3772: Kernel.assert_module_scope/3 (elixir) lib/kernel.ex:2977: Kernel.define/4 (elixir) expanding macro: Kernel.def/2 test.exs:1: (file)
cannot invoke def/2 outside module と書いているのでこれは比較的わかりやすい気がする。
rubyのようにトップレベルでの関数定義はできないようだ。
もっともrubyの場合はKernelモジュールの省略という話があるので、思想としてはそんなに違わないのかもしれない。
今日はこれくらいにしておこう。