lifting
(a -> b) -> (f a -> f b)
接收一個函數a -> b
,回傳一個新的函數f a -> f b
,新函數和舊函數的差別在於新函數可以處理任何type為functor typeclass的instance的值(例如[Int]
, [
)
這件事情在Haskell中叫做lifting。
比較
使用 list comprehesion
[x * y | x <- [1..5], y <- [6..10]]
使用 Functor 和 Applicative
(*) <$> [1..5] <*> [6..10]
IO Action也是Applicative
1 | instance Applicative IO where |
IO action 也是 Applicative 的一個 instance。IO action 中的 Applicative 涉及 sequencing。
根據上面的定義,在a <*> b
當中:
先執行 IO Action a
pure is all about putting a value in a minimal context that still holds it as its result
If <*>
were specialized for IO it would have a type of (<*>) :: IO (a -> b) -> IO a -> IO b
. It would take an I/O action that yields a function as its result and another I/O action and create a new I/O action from those two that, when performed, first performs the first one to get the function and then performs the second one to get the value and then it would yield that function applied to the value as its result. We used do syntax to implement it here. Remember, do syntax is about taking several I/O actions and gluing them into one, which is exactly what we do here.
With Maybe and [], we could think of <*> as simply extracting a function from its left parameter and then sort of applying it over the right one. With IO, extracting is still in the game, but now we also have a notion of sequencing, because we’re taking two I/O actions and we’re sequencing, or gluing, them into one. We have to extract the function from the first I/O action, but to extract a result from an I/O action, it has to be performed.