LoginSignup
5
2

More than 3 years have passed since last update.

すごいHaskellたのしく学ぼう! を学びなおしてみる(第4章)[with Elixir]

Last updated at Posted at 2020-04-18

はじめに

  • 前回
  • Elixirを使いはじめてだいたい1年くらいがたちました
  • すごいHaskellたのしく学ぼう!という本を2015年に買って、一通り読んだあとずっと本棚にしまわれていたままでした
  • 久しぶりに引っ張り出して読んでみると、こんなに愉快な内容だったけ!? という感想を持ちました
  • Elixirで関数プログラミングにだいぶ慣れたので、ユーモアの部分を楽しむ余裕ができたのだとおもいます
  • 少しずつ読み進めながら、興味が向いたところだけElixirで書き換えてみたりして理解を深めていきたいとおもいます
  • 今回はHello 再帰!

maximum

  • リストの中から一番でっかいやつを返します
baby.hs
maximum' [] = error "maximum of empty list!"
maximum' [x] = x
maximum' (x:xs) = max x (maximum' xs)

Prelude> maximum' [2,5,1]
5
awesome.exs
defmodule Awesome do
  def maximum([]), do: raise "maximum of empty list!"
  def maximum([x]), do: x
  def maximum([x|xs]), do: max(x, maximum(xs))
end

iex> Awesome.maximum([2,5,1])
5

replicate n x

  • n個の要素がxのリストを返します
baby.hs
replicate' n x
    | n <= 0    = []
    | otherwise = x : replicate' (n-1) x

Prelude> replicate' 10 3
[3,3,3,3,3,3,3,3,3,3]
awesome.exs
defmodule Awesome do
  def replicate(n, _) when n <= 0, do: []
  def replicate(n, x), do: [x | replicate(n - 1, x)]
end

iex> Awesome.replicate(10, 3)
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

take n [a]

  • リストからn個取り出します
baby.hs
take' n _ 
    | n <= 0    = []
take' _ []      = []
take' n (x:xs)  = x : take' (n-1) xs

Prelude> take' 2 [1,2,3,4,5]
[1,2]
awesome.exs
defmodule Awesome do
  def take(_, n) when n <= 0, do: []
  def take([], _), do: []
  def take([x | xs], n), do: [x | take(xs, n - 1)]
end

iex> Awesome.take([1,2,3,4,5],2)
[1, 2]

reverse

  • リストの中身をひっくり返します
baby.hs
reverse' []     = []
reverse' (x:xs) = reverse' xs ++ [x]

Prelude> reverse' [1,2,3]
[3,2,1]
awesome.exs
defmodule Awesome do
  def reverse([]), do: []
  def reverse([x | xs]), do: reverse(xs) ++ [x]
end

iex> Awesome.reverse([1,2,3])
[3, 2, 1]

repeat

  • 無限リストをつくります
baby.hs
repeat' x = x : repeat' x

Prelude> take' 10 (repeat' 3)
[3,3,3,3,3,3,3,3,3,3]
awesome.exs
defmodule Awesome do
  def repeat(x), do: Stream.cycle([x])
end

iex> Awesome.repeat(3) |> Enum.take(10)
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

zip

  • zipします
baby.hs
zip' _ [] = []
zip' [] _ = []
zip' (x:xs) (y:ys) = (x,y) : zip' xs ys

Prelude> zip' [1,2,3] ['a', 'b']
[(1,'a'),(2,'b')]
awesome.exs
defmodule Awesome do
  def zip(_, []), do: []
  def zip([], _), do: []
  def zip([x | xs], [y | ys]), do: [{x,y} | zip(xs, ys)]
end

iex> Awesome.zip([1,2,3], ["a", "b"])
[{1, "a"}, {2, "b"}]

elem

  • 値がリストに含まれるかどうか
baby.hs
elem' a [] = False
elem' a (x:xs)
    | a == x     = True
    | otherwise  = a `elem'` xs

Prelude> 3 `elem` [1,2,3]
True
Prelude> -1 `elem` [1,2,3]
False
awesome.exs
defmodule Awesome do
  def member?([], _), do: false
  def member?([x | _], element) when x == element, do: true
  def member?([_ | xs], element), do: member?(xs, element)
end

iex> Awesome.member?([1,2,3], 3)
true

iex> Awesome.member?([1,2,3], -1)
false

quicksort

  • クイックソートです
baby.hs
quicksort [] = []
quicksort (x:xs) =
    let smallerOrEqual = [a | a <- xs, a <= x]
        larger = [a | a <-xs, a > x]
    in quicksort smallerOrEqual ++ [x] ++ quicksort larger

Prelude> quicksort [10,2,5,3,1,6,7,4,2,3,4,8,9]
[1,2,2,3,3,4,4,5,6,7,8,9,10]
awesome.exs
defmodule Awesome do
  def quicksort([]), do: []
  def quicksort([x | xs]) do
    smaller_or_equal = (for a <- xs, a <= x, do: a)
    larger = (for a <- xs, a > x, do: a)
    quicksort(smaller_or_equal) ++ [x] ++ quicksort(larger)
  end
end

iex> Awesome.quicksort([10,2,5,3,1,6,7,4,2,3,4,8,9])
[1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10]

まとめ

  • 私は元来、再帰はからっきし苦手だったのですが、不思議とElixirでは書けるようになってきました
  • Elixirで慣れてきたことが手伝ってか、Haskellのほうも割とすんなり理解できました
  • Enjoy! with Elixir :rocket:
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2