首页 文章

<*>对于按表示法实现的列表 - 这不是“作弊”吗?

提问于
浏览
9

根据'Learn you a Haskell',列表的 <*> 的实现是:

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

我错了,还是基于 >>= 的这个含糖的monadic代码?

据我所知,应该可以仅使用 fmap 来实现<*>,因为应用的是Maybe的情况 .

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

顺便说一下,几页之后我看到了关于 <*> 的应用 IO 的实施问题 .

4 回答

  • 3

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

    据我所知,应该可以仅使用fmap为列表实现<*>,就像应用Maybe的情况一样 . 怎么样?

    你好像是指this implementation

    实例适用可能在哪里
    pure = Just
    什么<> _ =没什么
    (只是f)<
    >某事= fmap f

    好吧,是的,我们也可以为列表做到这一点 - 只使用 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 .

  • 8

    不,这不是基于 >>= 的含糖单子代码 . 如果是, Monad [] 实例中的definition of >>=将是循环的 .

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

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

    [e | b,Q] =如果b则[e |问]其他[]
    [e |让decls,Q] =让[e |问]
    [e | p < - l,Q] =设ok p = [e |问]
    ok _ = []
    在concatMap中确定l

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

    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 .

  • 16

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

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

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

    Functor > Applicative > Monad
    

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

  • 10

    我错了,还是基于>> =这个含糖的monadic代码?

    我不知道 >>= 是否实际上用于去糖列表理解(但请参阅Cirdec 's answer for evidence that it'不),但根据 >>= 定义 <*> 实际上是完全合法的 . 在数学术语中,每个 Monad 实例都会引发一个唯一对应的 Applicative 实例

    instance Applicative F where
        pure = return
        af <*> ax = af >>= \ f -> ax >>= \ x -> return (f x)
    

    每当 F 有一个遵纪守法的 Monad 实例时,这是一个守法的 Applicative 实例 .

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

    类似地,对于每个monad结构,都存在兼容的应用结构,并且对于每个应用结构都存在兼容的 fmapfmap f ax = pure f <*> ax ),但反过来的含义并不成立 .

    据我所知,应该可以仅使用fmap实现<*>,因为应用的是Maybe的情况 .

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

相关问题