🧪

Elixirでライフゲームを作ってみる

2022/12/20に公開


開発者に愛されている言語、Rustに続いて2位となったElixirというプログラミング言語が気になっていたので、とりあえずライフゲームを作ってみました。
この言語を初めて触って思ったことなど、備忘録的な内容の記事であるため、詳しい実装については記しておりません。
https://survey.stackoverflow.co/2022/#technology-most-loved-dreaded-and-wanted

Elixir

関数型のプログラミング言語です。
高い拡張性があり、Erlangの仮想環境上で動くとのこと。
あまり利用する場面を想像することが出来ていないですが、新しい言語は楽しいので触ります。

兎にも角にもHello, world

IO.puts "Hello, world!"

このプログラムは、IOモジュールのputs関数を使って、文字列 "Hello, world!" を出力しています。
Elixirは、標準ライブラリに含まれる IO モジュールを使うことで、標準入出力を行うことができる様です。

関数

Elixirでの関数は、基本的にModuleと呼ばれるものの中でないと定義できません

def add(x, y) do
  x + y
end
❯ elixir hello_world.exs
** (ArgumentError) cannot invoke def/2 outside module
    (elixir 1.14.2) lib/kernel.ex:6387: Kernel.assert_module_scope/3
    (elixir 1.14.2) lib/kernel.ex:5084: Kernel.define/4
    (elixir 1.14.2) expanding macro: Kernel.def/2
    hello_world.exs:1: (file)

次のように書かなければなりません。

defmodule MyModule do
  def add(x, y) do
    x + y
  end
end

また、returnは使わず、関数の最後の値が戻り値となります。
ここはRustと同じような感じですね

定数

定数はモジュール属性として次のように定義する。

defmodule LifeGame do
  @height 32
  @width 32
end

リスト

Pythonなどと同じように次のように書けます。

list1d = [1, 2, 3, 4]
list2d = [
  [1, 2, 3, 4],
  [5, 6, 7, 8]
]

ただし、要素へのアクセスの仕方が特殊でした。

list1d[0]
list2d[1][0]

これではエラーが出てしまいます。

** (ArgumentError) the Access calls for keywords expect the key to be an atom, got: 0

次のように書く必要があります。

Enum.at(list1d,0)
Enum.at(Enum.at(list2d,1),0

このEnumがElixirで頻繁に使われます。

例えば、配列をある値で初期化する場合は次のように書きます。

list = Enum.map(1..5, fn(_) -> 0 end) 

これは長さ5で全てが0のリストを作るプログラムです。
1..5で`1から5までのリストを作れるようです。また、第二引数で関数を渡しています。

Enum

とりあえず、Elixir初心者はまずこのEnumを使いこなせるようになることが第一目標となりそうです。for文なども用意はされていますが、Enumを使えばほとんど出番がないかと思います。
Enumは70個以上の関数を持ち、Elixir SchoolというElixirについて学べるサイト内でも序盤に学ぶので、かなり重要であることが伺えます。

Enum モジュールが非常に多くの機能を持っていることは一目瞭然ですが、これには明確な理由があります。 列挙は関数型プログラミングの中核であり、Elixirが開発者にもたらす驚くべきその他の恩恵と基部で統合的に用意されているおかげです。

https://elixirschool.com/ja
私がEnumという単語を最初に目にしたのはC++を触っていた時で、そこまで目立つ機能ではなかった(ElixirのEnumとは全然違う)ので、初めてElixirでEnumを見たときは少し変な感じがしました。
ただ、Enumを使いこなせればElixirらしいプログラミングが出来る気がします。

Enumまみれな関数

def display(matrix) do
  IO.puts(
    Enum.join(
      Enum.map(matrix, fn row ->
        Enum.join(
          Enum.map(
            row, fn cell -> if cell, do: "🟩", else: "⬜️" end), "") end), "\n"))
end

Enumとは関係ないですが、if文やfor文が戻り値を持つというのも面白かった。

感想

関数型言語はとっつきにくい印象がありますが、Elixirは分かり易い文法になっていたので書きやすかったです。(endを書くのが少し面倒ですが...)
今どきな機能はもちろんですが、Lispっぽさも感じたので自分は少し好きになりました。
普段使っている言語と異なるパラダイムを持つ言語を触ると、頭の体操をしているみたいで楽しいですね。
ただ、並行処理や拡張性などの実用面での利点を理解できていないので、そこを理解して自分の選択肢に組み込めたら面白そうです。

ちなみに、Elixir完全初心者の状態からChatGPTと共に勉強していきましたが、かなり嘘を教えられました。特にリストに関する部分は間違った情報が多かったです。

作ったもの

https://github.com/k41531/lifegame-elixir

Discussion