Haskell: 简单解析sequenceA

痴心易碎 提交于 2020-02-02 02:31:32

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的理论寓意一样…这个部分待补

参考

趣学指南 Applicative

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!