为什么这两个等价物?

我不太明白为什么要给出两个列表xss :: [[a]]yss :: [[a]]

liftA2 (++) xss yss

等同于

[xs ++ ys | xs <- xss,ys <- yss]
shimin_3333 回答:为什么这两个等价物?

原因是源代码中的right here

instance Applicative [] where
    pure x    = [x]
    fs <*> xs = [f x | f <- fs,x <- xs]
    liftA2 f xs ys = [f x y | x <- xs,y <- ys]

liftA2定义是一种优化,我们也可以使用默认的liftA2手动完成它:

liftA2 f x y = f <$> x <*> y

所以

liftA2 (++) xs ys
   = (++) <$> xs <*> ys
   = fmap (++) xs <*> ys                  -- definition of <$> 
   = [ f y | f <- fmap (++) xs,y <- ys ] -- definition of <*> above
   = [ (++) x y | x <- xs,y <- ys ]      -- some law about fmap/bind
   = [ x ++ y | x <- xs,y <- ys ]

那里有。


“关于fmap / bind的一些法律”是这样的:

fmap f x >>= t = x >>= t . f

,如果您了解如何理解列表推导,则适用。证明是:

fmap f x >>= t
    = x >>= pure . f >>= t             -- fmap = liftM coherence
    = x >>= (\y -> pure (f y) >>= t)   -- definition of (.)
    = x >>= (\y -> t (f y))            -- left unit monad law
    = x >>= t . f                      -- definition of (.)
,

这正是我不喜欢使用liftA<2..n>类型的函数的原因。它们是对monad抽象的抽象。之所以如此,是因为在Monad之后引入了applicative,只是为了简化包含功能值(函数)的Monad的上下文。

基本上liftA2 (++) xs ys(++) <$> xs <*> ys,因为它涉及内联形式fmap的函子运算符<$>,因此更有意义。一旦您了解了后一种liftA2的机制,就可以理解了。

fmap仅将(++)函数应用于xs列表的元素(假设xs[[1,2],[3,4]])并将其转换为适用列表(包含功能的列表),例如;

[([1,2] ++),([3,4] ++)] :: Num a => [[a] -> [a]]

并且应用运算符<*>现在可以将我们列表中的这些功能应用于另一个包含其他列表(例如[[1,4]])的列表。

此刻,我们必须了解如何单例准确地处理列表。列表是不确定的数据类型。因此,必须将第一个列表的每个元素应用于第二个列表的每个元素。所以

[([1,4] ++)] <*> [[1,4]]

原来是

[[1,2,1,[1,3,4],4,4]]

总之liftA2 (++)仅将简单的(++)函数提升到列表monad。简而言之,将内部列表彼此串联。

已经说过,列表理解版本是Haskell的一个笑话。我认为这是多余的,应避免使用。仅需将整个monad抽象降低到列表级别,而monadical方法则根据其适当的monad实例适用于所有数据类型。

本文链接:https://www.f2er.com/3156305.html

大家都在问