Haskell: 简单解析sequenceA
sequenceA的定义
-- sequenceA in Prelude
sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)
-- When applied to []: in which t is infered as []
sequenceA :: (Applicative f) => [f a] -> f [a]
sequenceA [] = pure []
sequenceA (x:xs) = (:) <$> x <*> (sequenceA xs)
-- Another definition
sequenceA :: (Applicative f) => [f a] -> f [a]
sequenceA = foldr (liftA2 (:)) (pure [])
where liftA2 f a b = f <$> a <*> b
-- liftA2 in Control.Applicative
liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
sequenceA的实用性
根据一些案例来说明sequenceA
是怎么用的,从中可以管窥其设计思路。
# f as a Container: Wrapping a list
## f as Maybe
ghci> sequenceA [Just 3, Just 2, Just 1]
Just [3,2,1]
ghci> sequenceA [Just 3, Nothing, Just 1]
Nothing
## f as Either a
ghci> sequenceA [Right 2, Left 1]
Left 1
ghci> sequenceA [Right 2, Right 1]
Right [2,1]
ghci> sequenceA [Right 2, Left 2, Left 1]
Left 2
# f as (->) r: Map
ghci> sequenceA [(+3),(+2),(+1)] 3
[6,5,4]
ghci> sequenceA [(>4),(<10),odd] 7
[True,True,True]
ghci> and $ sequenceA [(>4),(<10),odd] 7
True
ghci> sequenceA (sequenceA [(+), (*)] 2) 5 # nesting structure of sequenceA
[7, 10]
# f as []: Permutation
ghci> sequenceA [[1,2,3],[4,5,6]]
[[1,4],[1,5],[1,6],[2,4],[2,5],[2,6],[3,4],[3,5],[3,6]]
ghci> sequenceA [[1,2,3],[4,5,6],[3,4,4],[]]
[]
# sequenceA [xs, ys, zs] = [[x, y, z] | x <- xs, y <- ys, z <- zs]
# f as IO
ghci> sequenceA [getLine, getLine, getLine]
heyh
ho
woo
["heyh","ho","woo"]
这里面比较不好理解的就是f
作为(->) r
的使用,下面举一个例子sequenceA [(*2), (*3), (*5)]
来解释一下。
首先根据函子的类型(->) r
确定,在下边的推导中:
pure :: a -> (r -> a)
pure x _ = x
fmap :: (b -> c) -> (r -> b) -> (r -> c)
fmap = (.)
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
f <*> g x = f x (g x)
以下为推导过程:
sequenceA [(*2), (*3), (*5)] 2
= (:) <$> (*2) <*> (sequenceA [(*3), (*5)]) 2 (unfold sequenceA)
= ((:) . (*2)) <*> (sequenceA [(*3), (*5)]) 2 (unfold <$>)
= ((:) . (*2)) 2 ((sequenceA [(*3), (*5)]) 2) (unfold <*>)
= (:) 4 ((sequenceA [(*3), (*5)]) 2) (evaluation (*2) 2)
= (4:) (sequenceA [(*3), (*5)] 2) (evaluation (:) 4)
= (4:) ((6:) ((10:) (sequenceA [] 2))) (unfold, similarly)
= (4:) ((6:) ((10:) (pure [] 2))) (unfold sequenceA)
= (4:) ((6:) ((10:) [])) (unfold pure)
= (4:) ((6:) [10]) (evaluation (10:) [])
= (4:) [6, 10]
= [4, 6, 10]
sequenceA的意义
其实并没有搞懂sequenceA
有什么深刻的理论寓意,正如我也没有搞懂pure
的理论寓意一样…这个部分待补
参考
来源:CSDN
作者:WinterShiver
链接:https://blog.csdn.net/WinterShiver/article/details/104138523