理解正确应用
Understanding Right Apply
对于列表,为什么 right apply (*>)
会重复和附加第二个参数 n
次,其中 n
是第一个参数的长度?
ghci> [1,2,3] *> [4,5]
[4,5,4,5,4,5]
默认情况下,*>
运算符定义为
xs *> ys = id <$ xs <*> ys
默认情况下又转换为
const id <$> xs <*> ys
即用id
替换xs
的每个元素得到xs'
,然后计算xs' <*> ys
。 []
是一个 Monad
实例,其中 (=<<) = concatMap
。 Applicative
的其中一条定律阐明了 Applicative
和 Monad
实例之间的关系:
pure = return
fs <*> as = fs `ap` as = fs >>= \f -> as >>= \a -> f a
对于列表,这是
fs <*> as = [f a | f <- fs, a <- as]
所以列表的 *>
最终由 Monad
实例决定。
请注意,还有另一个非常明智的 Applicative
列表实例,可通过 Control.Applicative
中的新类型获得:
newtype ZipList a = ZipList [a]
instance Applicative ZipList where
pure = repeat
(<*>) = zipWith ($)
对于列表,为什么 right apply (*>)
会重复和附加第二个参数 n
次,其中 n
是第一个参数的长度?
ghci> [1,2,3] *> [4,5]
[4,5,4,5,4,5]
默认情况下,*>
运算符定义为
xs *> ys = id <$ xs <*> ys
默认情况下又转换为
const id <$> xs <*> ys
即用id
替换xs
的每个元素得到xs'
,然后计算xs' <*> ys
。 []
是一个 Monad
实例,其中 (=<<) = concatMap
。 Applicative
的其中一条定律阐明了 Applicative
和 Monad
实例之间的关系:
pure = return
fs <*> as = fs `ap` as = fs >>= \f -> as >>= \a -> f a
对于列表,这是
fs <*> as = [f a | f <- fs, a <- as]
所以列表的 *>
最终由 Monad
实例决定。
请注意,还有另一个非常明智的 Applicative
列表实例,可通过 Control.Applicative
中的新类型获得:
newtype ZipList a = ZipList [a]
instance Applicative ZipList where
pure = repeat
(<*>) = zipWith ($)