應用的常見例項
也許
Maybe
是一個包含可能不存在的值的應用函子。
instance Applicative Maybe where
pure = Just
Just f <*> Just x = Just $ f x
_ <*> _ = Nothing
pure
通過向其應用 Just
將給定值提升到 Maybe
。(<*>)
函式將包含在 Maybe
中的函式應用於 Maybe
中的值。如果函式和值都存在(使用 Just
構造),則將該函式應用於該值並返回包裝結果。如果缺少任何一個,則計算無法繼續,而是返回 Nothing
。
清單
列表適合型別簽名 <*> :: [a -> b] -> [a] -> [b]
的一種方法是採用兩個列表’笛卡爾積,將第一個列表的每個元素與第二個列表中的每個元素配對:
fs <*> xs = [f x | f <- fs, x <- xs]
-- = do { f <- fs; x <- xs; return (f x) }
pure x = [x]
這通常被解釋為模仿非確定性,其中一個值列表代表一個非確定性值,其值可能超出該列表; 因此,兩個非確定性值的組合會覆蓋兩個列表中值的所有可能組合:
ghci> [(+1),(+2)] <*> [3,30,300]
[4,31,301,5,32,302]
無限流和壓縮列表
有一類 Applicative
s 將它們的兩個輸入壓縮在一起。一個簡單的例子是無限流:
data Stream a = Stream { headS::a, tailS::Stream a }
Stream
的 Applicative
例項將點函式流應用於點引數流,按位置對兩個流中的值進行配對。pure
返回一個常量流 - 一個固定值的無限列表:
instance Applicative Stream where
pure x = let s = Stream x s in s
Stream f fs <*> Stream x xs = Stream (f x) (fs <*> xs)
列表也承認了一個 zippy``Applicative
例項,其中存在 ZipList
newtype:
newtype ZipList a = ZipList { getZipList :: [a] }
instance Applicative ZipList where
ZipList xs <*> ZipList ys = ZipList $ zipWith ($) xs ys
由於 zip
根據最短的輸入修剪其結果,因此滿足 Applicative
定律的 pure
的唯一實現是返回無限列表的實現:
pure a = ZipList (repeat a) -- ZipList (fix (a:)) = ZipList [a,a,a,a,...
例如:
ghci> getZipList $ ZipList [(+1),(+2)] <*> ZipList [3,30,300]
[4,32]
這兩種可能性提醒我們外部和內部產品,類似於在第一種情況下將 1 列(n x 1
)矩陣與 1 行(1 x m
)矩陣相乘,從而獲得 n x m
矩陣(但是扁平化); 或者在第二種情況下乘以 1 行和 1 列矩陣(但沒有求和)。
功能
當專門用於 (->) r
時,pure
和 <*>
的型別簽名分別與 K
和 S
組合的型別簽名:
pure::a -> (r -> a)
<*> :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
pure
必須是 const
,<*>
接受一對函式並將它們分別應用於固定引數,應用兩個結果:
instance Applicative ((->) r) where
pure = const
f <*> g = \x -> f x (g x)
函式是典型的 zippy
應用程式。例如,由於無限流與 (->) Nat
同構,…
-- | Index into a stream
to::Stream a -> (Nat -> a)
to (Stream x xs) Zero = x
to (Stream x xs) (Suc n) = to xs n
-- | List all the return values of the function in order
from :: (Nat -> a) -> Stream a
from f = from' Zero
where from' n = Stream (f n) (from' (Suc n))
…以更高階的方式表示流自動生成 zippy Applicative
例項。