やがてelixirになる


この記事は、fukuoka.ex Elixir/Phoenix Advent Calendar 2020 6日目です。
前日は、 hisawayさんの [Elixir]匿名関数をパターンマッチする でした。

最近もくもく会でやっていた事を紹介します。
配列の要素数をカウントする関数です。

def listlen(l):
    if (l == []):
        return 0
    else:
        return 1 + listlen(l[1:])

print(listlen([1,2,3,4]))

やってしまいました。
elixirの割にendが無いと思ったらpythonですね。
書き直します。

def listlen(l)
  if l == [] then
    0
  else
    1 + listlen(l.drop(1))
  end
end

puts(listlen([1,2,3,4]))

endをつけてreturnが不要になりました。
(最後の行の値は暗黙にreturnされる)
でもelixirはdefmoduleの中でしか関数定義できないので
これはrubyのコードです。

(defun listlen (l)
  (if (null l)
    0
    (+ 1 (listlen (cdr l)))))

(listlen (list 1 2 3 4))

今度こそ!・・・括弧が沢山増えてしまいました。
common lispです。

-module(listlen).
-export([listlen/1]).

listlen([]) -> 0;
listlen([_|T]) -> 1 + listlen(T).

うーん、括弧は減りましたがちょっとサッパリしすぎです。
これはerlangです。
erlc listlen.erlでコンパイル後に
erlで対話モードを起動して
listlen([1,2,3,4]).で実行します。
erlangでは;は行の区切りではなく
この行の関数の引数、
listlen([]) -> 0([])
に一致しない場合は次のlistlenを実行すると言う意味です。
最後に実行するlistlenには.を末尾につけて
これが最後のlistlenだよとerlangに教えます。

defmodule ListLen do
  def listlen([]) do
    0
  end

  def listlen([_|tail]) do
    1 + ListLen.listlen(tail)
  end
end

ListLen.listlen([1,2,3,4])

ようやくたどり着きました。
こいつがりんごろう
これがelixirのコードです。
elixir listlen.exsで実行します。

あとがき

そこはかとなくオライリー風に。
最初マクロについて書こうとしたけど
elixirマクロの記事そこそこあったんで
こっちにしました。