DAY 28
1
Software Development

## mostly:functional 第二十七章：Applicative 的法則

a new born baby rest her head on the earth of mother
everything else is outer space.

-- Mike Birbiglia, The New One

-- 1209

Applicative 的實作：

``````class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
{-# MINIMAL pure, ((<*>) | liftA2) #-}
``````

Applicative 的法則：

1. 單位元素
2. 結合律
3. 同態
4. 交換律

Applicative 的概念似乎是許多其它程式語言的使用者開始卡關的點，探究其原因，應該是惰性函式，以及函式組合的手法在其它語言裡使用機率較少，因此用這兩個概念繼續往下延伸的手法想來也就更加乏人問津了。或者用另一個說法，在其它語言裡，傾向用別的方式解決類似的問題。

## 如果傳給 `fmap` 的函式，需要兩個參數怎麼辦？

``````-- Haskell 語法

fmap (\x -> x + 1) [1, 2] -- => [2, 3]
--   ^^^^^^^^^^^^^
--       就是它
``````

``````# Elixir 語法
Enum.map([1, 2], fn x, y -> x + y end)

# 錯誤
# => ** (BadArityError) #Function<43.97283095/2 in :erl_eval.expr/5> with arity 2 called with 1 argument (1)
``````

## 把惰性求值的函式考慮進來

``````-- Haskell 語法
f a b = a + b
g = f 1 -- 這是一個還沒有飽和的函式，也就是個 *partial application*
``````

``````-- Haskell 語法
f a b = a + b

fmap f [1, 2] -- => [ (1+), (2+) ]
``````

``````-- Haskell 語法
fmap (+) [1, 2] -- => [ (1+), (2+) ]
``````

## 這要怎麼用？

``````-- Haskell 語法
fmap (+) \$ Just 1 -- => Just (+1)
``````

``````-- Haskell
(Just (+1)) ??? (Just 2)
``````

``````-- Haskell
(\$)   ::   (a -> b) ->   a   -> b -- 函式應用
(<\$>) ::   (a -> b) -> f a -> f b -- fmap
(<*>) :: f (a -> b) -> f a -> f b -- ap
``````

## 隱含的 monoid 特性

``````-- 把型別裡，容器外殼跟裡面的內容上下錯開一點
(<*>) :: f (a -> b) -> f a -> f b

f             f      f     --- 外殼
(a -> b)      a      b   --- 內容
``````

``````mappend ::  f             f      f
\$       ::    (a -> b)      a      b

(<*>) ::    f (a -> b) -> f a -> f b
``````

## Maybe 上的 Applicative

``````-- Haskell 語法
(+) <\$> (Just 1) <*> (Just 2) -- => Just 3
(+) <\$> (Just 1) <*> Nothing  -- => Nothing
(+) <\$> Nothing  <*> (Just 2) -- => Nothing
``````

``````-- Haskell 語法

instance Applicative Maybe where
Nothing  <*> _         = Nothing
(Just f) <*> something = fmap f something
``````

## 最基本的包裝函式： `pure`

``````-- Haskell 語法

instance Applicative Maybe where
pure = Just               -- 多了這行
Nothing  <*> _         = Nothing
(Just f) <*> something = fmap f something
``````

## 法則

### 單位元素

``````-- Haskell 語法
pure id <*> v -- => v

-- 示範
pure id <*> [1, 2, 3]     -- => [1, 2, 3]
pure id <*> Just "test"   -- => Just "test"
pure id <*> Left "wrong!" -- => Left "wrong!"
``````

### 結合律

``````pure (.) <*> f <*> g -- 把函式結合這件事也放到容器裡，再去 ap 兩個容器裡的函式

-- 所以
pure (.) <*> f <*> g <*> x
=
f <*> (g <*> x)

-- 示範
pure (.) <*> Just (+10) <*> Just (*3) <*> Just 2 -- => Just 16

Just (+10) <*> (Just <*3> <*> Just 2)            -- => Just 16
``````

### 同態

``````pure f <*> pure x = pure (f x)

-- 示範
pure (*2) <*> pure 3
=
pure ((*2) 3)

``````

### 交換律

``````--- Haskell

pure (\$ 2) <*> Just (+10)  -- => Just 12
``````

[to be continue]