&LT * GT;对于按照表示法实现的列表 - 不是这个"作弊"?

时间:2015-03-30 14:13:26

标签: list haskell applicative

根据“了解你一个Haskell”,列表<*>的实现是:

fs <*> xs = [f x | f <- fs, x <- xs]

我错了,或者是基于>>=

的这个含糖的monadic代码?

据我了解,应该可以实现&lt; *&gt;仅使用fmap,因为适用的是Maybe。

如何仅使用<*>来实现列表的fmap? (可能没有连接东西?)

顺便说一句,几页之后,我发现有关应用<*> IO的实施方面存在同样的问题。

4 个答案:

答案 0 :(得分:16)

不,这不是基于>>=的含糖单子代码。如果是,则Monad []实例中的definition of >>=将为圆形。

instance Monad []  where
    {-# INLINE (>>=) #-}
    xs >>= f             = [y | x <- xs, y <- f x]
    ...

列表推导是letifconcatMap的语法糖。来自Haskell Report

[  e | b,          Q ] = if  b     then [ e | Q ] else []
[  e | let decls,  Q ] = let decls in   [ e | Q ]
[  e | p <- l,     Q ] = let ok p  =    [ e | Q ]
                             ok _  =    []
                         in concatMap ok l

Monad []实例很容易根据concatMap定义,concatMapGHC.List中定义(现在可能在Data.Foldable中定义) 。 GHC.ListData.Foldable都未导入GHC.Base,因此根据MonadGHC.Base中的列表定义concatMap实例是不可能的:< / p>

instance Monad [] where
    (>>=) = flip concatMap -- concatMap isn't imported

根据列表理解来定义这些实例需要导入包含concatMap的模块以重用它来定义>>=

在GHC中有两个implementations of list comprehensions。一个用GHC.Base buildfoldr重写它们,类似于Data.Foldable concatMap。另一个实现生成递归函数来代替concatMap as described by Wadler

答案 1 :(得分:10)

很多情况下Applicative实例满足monadic函数,我见过

instance Applicative MyMonadThatIsAlreadyDefined where
    pure = return
    (<*>) = ap

此外,<*>无法仅使用fmap编写,至少一般不会。这就是<*>的要点。尝试用<*>来表达fmap,如果你管理它,我将会非常惊讶(以一种表现良好并符合适用法律的方式)。请记住链是

Functor > Applicative > Monad

>可以被认为是超集。这就是说所有仿函数的集合包含所有应用程序的集合,其中包含所有monad的集合。如果你有一个monad,那么你拥有将它用作应用程序和仿函数所需的所有工具。有些类型是functorial但不适用,类型是非monadic的应用。我认为以这种方式定义应用实例没有问题。

答案 2 :(得分:8)

  

我错了,或者这是基于&gt;&gt; =?

的加糖单码

我不知道>>=是否实际上用于减少列表理解(但是请参阅Cirdec的答案,证明它不是),但是用<*>来定义>>=实际上是完全合法的。 Monad。在数学术语中,每个Applicative实例都会引发一个唯一的对应instance Applicative F where pure = return af <*> ax = af >>= \ f -> ax >>= \ x -> return (f x) 实例,在这个意义上

Applicative
只要F有一个守法的Monad实例,

就是一个守法的fmap实例。

如果您熟悉数学,那么这里有一个类比:

同样,对于每个monad结构,都有一个兼容的应用结构,并且对于每个应用结构都有一个兼容的fmap f ax = pure f <*> axfmap),但反过来的含义并不成立。

  

据我了解,应该可以实现&lt; *&gt;只使用fmap,因为适用于Maybe的情况。

我不明白你的意思。 <*>肯定不足以定义Functor,或者每个Applicative都是Apply(好吧,{{1}})。

答案 3 :(得分:3)

这个答案是对已经给出的答案的补充,只关注问题的一部分:

  

据我了解,应该可以仅使用<*>为列表实现fmap,因为应用的是Maybe的情况。怎么样?

您好像是指this implementation

instance Applicative Maybe where
    pure = Just
    Nothing  <*> _         = Nothing
    (Just f) <*> something = fmap f something

嗯,是的,我们也可以为列表做到这一点 - 只使用fmap,模式匹配和构造函数:

instance Applicative [] where
    pure = []
    []     <*> _         = []
    (f:fs) <*> something = fmap f something ++ (fs <*> something)
      where
        []     ++ yy = ys
        (x:xs) ++ ys = x : (xs++ys)

不可否认,这确实需要某种连接,因为列表比Maybes更复杂。还有其他可能适用于列表的应用实例,这些实例需要的代码少于此类所有内容。行为,但那些与默认的monad实例不兼容(这是常见的期望)。

当然,monad符号确实简化了这一点:

instance Monad m => Applicative m where
    pure = return
    mf <*> something = mf >>= (\f -> fmap f something) -- shorter: (`fmap` something)

...适用于Maybe[] m