Help us understand the problem. What is going on with this article?

Elixir episode:1 リスト

環境

sh
$ lsb_release -d
Description:    Ubuntu 18.04.2 LTS

$ elixir -v
Erlang/OTP 21 [erts-10.3.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Elixir 1.8.1 (compiled with Erlang/OTP 20)

はじめに

Elixir episode:0 実行ファイル のプロジェクトを使う。
いや、使わんでもいい。

Fg.List

touch lib/fg/list.ex

fg/lib/fg/list.ex
defmodule Fg.List do
  def cons(x, y), do: [x | y]

  def head([x | _y]), do: x

  def tail([_x | y]), do: y
end

$ iex -S mix

iex
iex(1)> alias Fg.List, as: L
Fg.List
iex(2)> list = L.cons(1, L.cons(2, L.cons(3, [])))
[1, 2, 3]
iex(3)> L.head(list)
1
iex(4)> L.tail(list)
[2, 3]
iex(5)> L.head([1])
1
iex(6)> L.tail([1])
[]

おっけー?

無名関数

$ iex

iex
iex(1)> first = fn (x, _y) -> x end
#Function<12.128620087/2 in :erl_eval.expr/5>
iex(2)> second = fn (_x, y) -> y end
#Function<12.128620087/2 in :erl_eval.expr/5>
iex(3)> first.(1, 2)
1
iex(4)> second.(1, 2)
2

カリー化

全ての関数を、1引数の関数で表現すること。

iex
iex(5)> first = fn x -> fn _y -> x end end
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(6)> second = fn _x -> fn y -> y end end
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(7)> first.(1).(2)
1
iex(8)> second.(1).(2)
2

なんの役に立つのか?実利的にはあまり役に立たない。
関数とは何か?と考える場合には役に立つ。
ざっくり言えば、関数の一般化である。

ラムダ算法

ラムダ算法の説明はしない。
以下はカリー化を施した関数によって、
関数のみでリスト(データ構造)を作れることを示している。

iex
iex(9)> cons = fn x -> fn y ->  
...(9)>   fn selector -> selector.(x).(y) end
...(9)> end end
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(10)> head = fn list -> list.(first) end
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(11)> tail = fn list -> list.(second) end
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(12)> list = cons.(1).(2)   
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(13)> head.(list)
1
iex(14)> tail.(list)
2
iex(15)> list = cons.(1).(cons.(2).(cons.(3).(nil)))
#Function<6.128620087/1 in :erl_eval.expr/5>
iex(16)> head.(list)
1
iex(17)> head.(tail.(list))
2
iex(18)> head.(tail.(tail.(list)))
3
iex(19)> tail.(tail.(tail.(list)))       
nil

Fg.List を書き換える

fg/lib/fg/list.ex
defmodule Fg.List do
  def cons(x, y) do
    fn selector when is_function(selector, 2) ->
      selector.(x, y)
    end
  end

  def head(list) when is_function(list, 1) do
    fn x, _y -> x end  # first selector
    |> list.()
  end

  def tail(list) when is_function(list, 1) do
    fn _x, y -> y end  # second selector
    |> list.()
  end
end

$ iex -S mix

iex
iex(1)> alias Fg.List, as: L
Fg.List
iex(2)> list = L.cons(1, L.cons(2, L.cons(3, nil)))
#Function<0.76478687/1 in Fg.List.cons/2>
iex(3)> L.head(list)
1
iex(4)> L.tail(list)
#Function<0.76478687/1 in Fg.List.cons/2>
iex(5)> L.tail(list) |> L.head()
2
iex(6)> L.tail(list) |> L.tail() |> L.head()
3
iex(7)> L.tail(list) |> L.tail() |> L.tail()
nil

また来てくれよなーノシ

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした