「Rubyistに贈るHaskell入門」 again



この記事はHaskell初心者が躓くところピックアップし、Rubyのコードで解説したものです。


基本的には、これらの記事の二番煎じネタですのであしからず。

[Rubyistに贈るHaskell入門](http://qiita.com/techno-tanoC/items/1549d0efc044faf16c36)

["Rubyistに贈るHaskell入門"がちょっと微妙だったので補足記事その1](http://qiita.com/nobkz/items/1ed1600bb2f0268070b3)



# 対象
・Rubyのコードがある程度分かる人(proc, curry化等も出てきます。)
・HaskellでHello Worldしたことある人
・Haskellの独特な文法の理解に苦しんでいる人


# Haskell勉強してよかったこと(期待していること)


[「関数型Rubyという病」](http://yuroyoro.hatenablog.com/entry/2012/08/08/201720)

ここらへんの記事が理解できるようになります。(前は読めなかった)
副作用のないコードを書けるようになります。(期待)
抽象的なロジックが組めるようになります。（期待）

# 学習手順

この記事を見てHaskellをセットアップ(超簡単！)
[Stack を使って Haskell をインストールする](http://qiita.com/usamik26/items/fa7c1f14c5ce2a0bd9fc)


このサイトを一周しました。（手っ取り早く学べる）
[ウォークスルーHaskell](http://walk.wgag.net/haskell/index.html)


# 目次
セクションごとに独立しているのでどこから呼んでも構いません。
私もHaskell初心者ですので誤った解釈をしている可能性もあります。　


・関数定義
・局所定義
・高階関数
・ラムダ抽象
・部分適用
・合成関数
・パターンマッチング
・リスト
・型クラス制約
・data宣言
・class宣言




# 関数定義
Rubyではメソッドですが、Haskellでは関数と呼びます。
メソッドは状態に依存しますが、関数は状態に依存しません。
つまり、関数は返り値が引数に一意に決まるという性質を持っています。


### haskell

関数の型を定義できる。
変数のように定義する。

```haskell
add :: Int -> Int -> Int
add x y = x * y

add 1 2 -- > 3
```

### ruby
メソッドですが、おなじみ。

```ruby
def add(x, y)
  x + y
end

add(1,2)
```


# 局所定義
局所で評価されない関数プログラムの定義の仕方。
-> 関数内で関数を定義することです。


### haskell
haskellだとlet, where等を使うことが出来ます。

#### let {宣言1 ; 宣言2 ; ... 宣言n } in 式

```haskell
circle :: Int -> Int

circle r = let square x = x * x
  			in 3.14 * square 

circle 3 -- > 28.26
```

#### where {宣言1 ; 宣言2 ; ... 宣言n } 

```haskell
circle :: Int -> Int

circle r = 3.14 * square r 
	where square x = x * x  			

circle 3 -- > 28.26
```

### ruby
rubyではproc, lambda等を使うしかありません。

```ruby

def circle(r)
  square = lambda { |x| x * x }
  3.14 * square.call(r)
end
```



# 高階関数
関数を引数にとったり、関数を返り値にする関数。
-> 実は全然難しくない。

## 関数を引数にとる高階関数


### haskell
haskellのmapです。rubyでももちろん書けますね。

```haskell
double :: Int -> Int
double x = 2 * x

map double [1,2,3,4,5] -- > [2,4,6,8,10]
```

### ruby
おなじみのmapメソッド。

```ruby

class Integer
  def double
    2 * self
  end
end

[1,2,3,4,5].map(&:double)
```


## 関数を返り値に返す関数



### haskell

```haskell
-- Intを受け取ってIntを返す関数を受け取り、Intを受け取ってIntを受け取る関数を返す。
return_function :: (Int -> Int) -> (Int -> Int)
return_function f = \ x -> f(x)

double x = x * 2
main = print $ (return_function double) 3
```

### ruby

rubyは遅延評価ではないので、カリー化を明示的に宣言する必要があります。。
あんまりピンとこないですが、こんな感じでしょうかね。
関数を返して、最後に引数を渡します。

```ruby

def double
  proc { |x| 2 * x }
end

def return_func(f)
  f.curry
end

return_func(double)[3]

```

# ラムダ抽象

関数を式で記述したもの。
匿名関数。
Rubyでも無名関数等とよばれるものがありますね。


### haskell

```haskell

let hoge = (\i -> i * 2)
```

こんな感じで使います。

```haskell
map (\i -> i * 2) [1,2,3]
```

### ruby
proc, lambda等

```ruby
hoge = proc { |i| i * 2 }
```



# 部分適用

関数に対して全ての引数を一度に渡さず、一部の引数だけを渡すことが出来る仕組み。 
後で説明するカリー化とは違う。

・関数を引数一つづつに分割してネストさせることをカリー化
・一部の引数を固定化して新しい関数を作り出すことを部分適用

### haskell 

```haskell
multiply :: Int -> Int -> Int

-- 二つの引数が必要
multiply x y = x * y

double :: Int -> Int
double = 2 * multiply 2 

--- 後からmultiplyの第二引数を渡している。
double 3 -- > 12
```


### ruby
高階関数はcurry化ばかりですね。


```ruby
def multiply
  proc { |x, y| x * y }
end

def double(x)
  2 * multiply.curry[2][x]
end

double(3)
```


# 関数合成

## 合成関数について復讐
連立方程式

```math
z = g(y)\\
y = f(x)\\
z = g(f(x))
```

と変換することが出来、fとgの合成関数と呼びます。
また、以下のように表現することが出来ます。

```math

z = g ○ f
```



例えば

```math

z = 2y　\\
y = x + 1 \\
z = 2(x + 1) \\
x = 3の時\\
z = 8　\\
```

です。



### haskell
haskellは数学知っていれば読めますね。

```haskell
g y = 2 * y
f x = x + 1

z x = (g . f) x
main = print $ z 3 -- > 8
```


### ruby

rubyでも関数の合成を行うことが出来ます。

```ruby

g = proc { |y| 2 * y }
f = proc { |x| x + 1 }


z = proc{ |x| g.call(f.call(x)) }
z.call(3) 

# もう少し格好良く書くと

z = proc { |x| g.(f.(x)) }
z.(3)

```

# パターンマッチング

疲れました。rubyのコードはここからはありません。

## ワイルドカード
なんでも良い時です。

```haskell
return_three :: Int -> Int
return_three _ = 3

return_three 1 -- > 3
return_three 2 -- > 3
return_three 3 -- > 3
return_three 1000 -- > 3
```

## ガード

定義を適用する条件を論理式によって記述できます。

```haskell
power :: Int -> Int -> Int
power 0 _ = 1
power x y | x > 0 = x * y
power x y | otherwise = power (-x) y

power 3 4  -- > 12
power (-3) 4  -- > 12

```


## case式

case 式 of { 選択肢1 ; 選択肢2 ; ... 選択肢n }
ガードで書いたのをcase式で書いてみます。


```haskell
power :: Int -> Int -> Int
power x y = case (x, y) of
    (0, _)             -> 1
    (x, y) | x > 0     -> x * y
           | otherwise -> power (-x) y

```


# リスト


```haskell

-- [1, 2, 3]
[1, 2, 3]
1 : (2 : (3 : []))
1 : 2 : 3 : []


-- get element by index
arr = [1, 2, 3]
arr !! 0 -- > 1
arr !! 1 -- > 2
arr !! 2 -- > 3

-- range

[1..5] -- [1, 2, 3, 4, 5]
[1, 3..6] -- [1, 3, 4, 5, 6]

-- リスト内包

[(x, y) | x <- [1, 2], y <- [3, 4]] -- [(1, 3), (1, 4), (2, 3), (2, 4)]
[x | x <- [1..10], odd x]    -- [1, 3, 5, 7, 9]
[(x, y) | x <- [1, 2, 3], let y = 4]   -- [(1,4), (2,4), (3,4)]

```


# 型クラス制約

リストの総和を求める関数sum

```haskell
sum :: [a] -> a
```

これだと、広すぎる。

```haskell
sum :: [Int] -> Int
```

これだと、浮動小数点には使えない。

そこで、

```haskell
sum :: Num a => [a] -> a
```

このように書くことで、Int, Integer, Float, Double等のクラスにおいても使える。



# data宣言
型を宣言する事ができます。

```haskell

data Point = Pt Double Double

norm :: Point -> Double
norm (Pt x y) = sqrt (x * x + y * y)

norm (Pt 3 4) -- > 5
```

# class宣言

・引数の型によって動作を変えるような関数を集めたもの
・Javaのインターフェースっぽい感じのもの

あまり使い方は分かっていない。

http://d.hatena.ne.jp/bi_na/20100913/1284363947


```haskell
class Hoge a where
  foo::a -> String -- fooは何かを受け取ってStringとして返す
  
d = D "AAA"
dd = DD "BBB" "CCC"

instance Hoge D where
  foo(D x) = "> " ++ x


instance Hoge DD where
  foo(DD x y) = "> " ++ x ++ y
  

main = do {
  print(foo d);
  print(foo dd);
}

--- "> AAA"
--- "> BBBCCC"
```