/var/log/messages

Jan 19, 2019 - 3 minute read - Comments - programming

プログラミング Elixir (7)

あまりドキュメントの確認の仕方って理解できていないかも。来週の勉強会で質問してみようかな。ともあれ、10 章の Enum と Stream 確認開始。

Enum

なかなか凄い。コード例眺めてるだけで面白い。

ListsAndRecursion-5

ひとまず all? から検討着手。例を確認してみます。

iex(1)> list = Enum.to_list 1..5
[1, 2, 3, 4, 5]
iex(2)> Enum.all?(list, &(&1 < 4))
false

以下をでっちあげたのですがコンパイルできない。

defmodule MyEnum do
  def all?([], _func), do: true
  def all?([head | tail], func) do
    if func(head) do
      all?(tail, func)
    else
      false
    end
  end
end

func の呼び出し方法がダウトでした。正しくは以下。

    if func.(head) do
      all?(tail, func)

一応うまく動いてはいるみたい。次は each とのこと。each て何だ。ググッてみるに以下な用例とのこと。

iex(11)> Enum.each list, &IO.puts(&1)       
1
2
3
4
5
:ok

最初以下な手続き渡してたら :ok しか戻ってこず。

Enum.each list, &(&1 + 1)

これは以下なカンジで良いのかどうか。

  def each([], _func), do: :ok
  def each([head | tail], func) do
    func.(head)
    each(tail, func)
  end

こんな書き方できるのかしら。できるみたい、動きました。次は filter とのこと。例示されているのは以下。

iex(15)> require Integer
Integer
iex(16)> Enum.filter list, &Integer.is_even/1
[2, 4]

これも all? のパターンなのかな。

  def filter([], func), do: true
  def filter([head | tail], func) do
    if func.(head) do
      filter(tail, func)
    else
      false
    end
  end

間違えた。true になる要素をリストにして戻すのでした。

  def filter([], func), do: []
  def filter([head | tail], func) do
    if func.(head) do
      [head | func.(tail)]
    else
      func.(tail)
    end
  end

で、書き換えてコンパイルしてるのですが、実行結果が変わらず。なんだこれ。って思ったら func 呼び出してるじゃん何してるのorz

  def filter([head | tail], func) do
    if func.(head) do
      [head | filter(tail, func)]
    else
      filter(tail, func)
    end
  end

とほほ。焦って書くとロクなことないスね。次は split です。

iex(9)> MyEnum.filter list, &Integer.is_even/1
[2, 4]
iex(10)> Enum.split list, 3
{[1, 2, 3], [4, 5]}

カウントすりゃいいのかな。

  def split([head | tail], end) do: split([head | tail], end, 0, [])
  defp _split([], end, count, list), do: list
  defp _split([head | tail], end, count, list) do
    if count > end do
      [list | tail]
    else
      _split(tail, end, count + 1, [list | [head | []]])
    end
  end

なんだろう、コンパイルエラーがある、って言われるのですが原因不明。。開き括弧が閉じていないと。こうしても同じですね。

  def split(list, end) do 
    _split(list, end, 0, [])
  end
  defp _split([], end, count, list), do: list
  defp _split([head | tail], end, count, list) do
    if count > end do
      [list | tail]
    else
      _split(tail, end, count + 1, [list | [head | []]])
    end
  end

上二つの手続き定義を消しても同じエラーが出ますね。

わかったorz end が予約語なのかorz そして実行してみたら駄目なナニがorz なんか根本的に色々間違えてる感満点ですねorz

最初がマズい

head をおしりに追加、ってのがアレなんですよね。[head] を、なのか。最初がアレなんですが。つうか、色々確認してみるに戻ってきてるの何だろ。

iex(24)> Enum.split list, 10
{[1, 2, 3, 4, 5], []}

この { って何なのかと。つうか前のページ見てみれば ++ って演算子がありますね。

  def split(l, term), do: _split(l, term, 1, [])
  defp _split([], term, c, l), do: {l, []}
  defp _split([head | tail], term, c, l) do
    if c < term do
      _split(tail, term, c + 1, l ++ [head])
    else
      [l | [[head | tail]]]
    end
  end

出力が微妙に違いますがヨシってことにします (を

take

ようやく最後だ。例示されてる実行例が以下?

iex(38)> Enum.take(list, 3)
[1, 2, 3]

これは split の前半を戻せば良いので簡単すね。

  def take(l, term), do: _take(l, term, 1, [])
  defp _take([], term, c, l), do: l
  defp _take([head | tail], term, c, l) do
    if c > term do
      l
    else
      _take(tail, term, c + 1, l ++ [head])
    end
  end

条件式に微妙さを感じております。

kokura.ex#1 プログラミング Elixir (8)

comments powered by Disqus