mcommit's message

ソフトウェア開発の仕事をしているsimotinといいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

Elixir入門 ~4日目 モジュール・名前付き関数~

昨日は無名関数について簡単に勉強したので今日は名前付き関数について勉強してみる。

モジュール・関数については、は参考書籍として使っているプログラミングElixirの6章で説明があるので読みながら勉強してみる。

プログラミングElixir

プログラミングElixir

モジュールと名前付き関数

名前付き関数はモジュールの内側で書く必要があるそうだ。

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モジュールの省略という話があるので、思想としてはそんなに違わないのかもしれない。

今日はこれくらいにしておこう。

4日目を終えて

少しずつの勉強なので恐ろしく進展が少ない。新しい言語を勉強するときによくやるのが、

  • CSV,JSONフォーマットを扱うファイル入出力
  • ソケットプログラミング
  • HTTPのクライアント(wget的なコード)

なんかをよくやる。

要するに使い捨てのツールを書いてみるということなんだけど、Elixirは関数型言語だしそういったお手軽スクリプティングとして使うのは違う気がする。(別にしたらだめというわけではないだろうが)

File – Elixir v1.5.1

を少し読んでみたけどまた覚えないといけないことがいろいろ出てきそうだ。

明日はファイルアクセスを少し触ってみよう。