我试图理解MonadPlus
背后的动机。如果已经存在类型类Monad
和Monoid
,为什么有必要呢?
诚然,Monoid
的实例是具体的类型,而Monad
的实例需要一个类型参数。(有关有用的解释,请参见Monoid vs MonadPlus。)但是你不能重写任何类型的约束吗
(MonadPlus m) => ...
作为Monad
和Monoid
的组合?
(Monad m, Monoid (m a)) => ...
从控件获取
。它的实施是:防护
功能。例如Monad
guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero
我只能使用Monad
和Monoid
实现它:
guard' :: (Monad m, Monoid (m ())) => Bool -> m ()
guard' True = return ()
guard' False = mempty
有人能澄清MonadPlus
和Monad
Monid
之间的真正区别吗?
通过量化约束
语言扩展,您可以表示幺半群(ma)
实例必须在a
的所有选择中保持一致:
{-# LANGUAGE QuantifiedConstraints #-}
class (Monad m, forall a. Monoid (m a)) => MonadPlus m
mzero :: (MonadPlus m) => m a
mzero = mempty
mplus :: (MonadPlus m) => m a -> m a -> m a
mplus = mappend
Alternative
ly,我们可以为所有这样的幺半群单子实现“real”MonadPlus
类:
{-# LANGUAGE GeneralizedNewtypeDeriving, DerivingStrategies, QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
import Control.Monad
import Control.Applicative
newtype MonoidMonad m a = MonoidMonad{ runMonoidMonad :: m a }
deriving (Functor, Applicative, Monad)
instance (Applicative m, forall a. Monoid (m a)) => Alternative (MonoidMonad m) where
empty = MonoidMonad mempty
(MonoidMonad x) <|> (MonoidMonad y) = MonoidMonad (x <> y)
instance (Monad m, forall a. Monoid (m a)) => MonadPlus (MonoidMonad m)
请注意,根据您选择的m
,这可能会或可能不会为您提供所需的MonadPlus
;例如,MonoidMonad[]
实际上与[]
相同;但是对于Maybe
,Monoid
实例通过人为地给它一个标识元素来提升一些基础半群,而MonadPlus
实例是左偏选择;所以我们必须首先使用MonoidMonad
而不是MonoidMonad,也许
来获得正确的实例。
你的guard'
与你的Monoid MA
类型不匹配。
如果你的意思是Monoid(ma)
,那么你需要定义mempty
对于m()
是什么。完成后,就定义了一个MonadPlus
。
换句话说,MonadPlus
定义了两个操作部分:mzero
和mplus
满足两个规则:mzero
相对于mplus
是中性的,mplus
是关联的。这满足了幺半群的定义,因此
mzero
是mempty
,mplus
是mappend
。
不同之处在于,
MonadPlus m
对于任何a
都是一个幺半群ma
,但是monoid m
只为m
定义了一个幺半群。你的guard'
之所以有效,是因为你只需要m
就可以成为Monoid
,只用于()
。但是MonadPlus
更强,它声称ma
是任何a
的幺半群。
但是你不能重写任何类型的约束吗
(MonadPlus m) => ...
作为单子和幺半群的组合?
不。在你链接的问题的顶部答案中,已经有一个很好的解释了MonadPlus和Monoid的定律。但是,即使我们忽略了类型类法则,也存在差异。
幺半群(ma)=
>
如果我们不想告诉调用者我们打算使用什么
a
。MonadPlus m=
如果我们想使用多个不同的
a
MonadPlus m=
如果我们想使用无限多个不同的
a
MonadPlus m=
如果我们不知道我们需要什么<代码>MonadPlus m=
做对了"。事实证明,可以用来表示任何类似ListT-dod-right的东西。引用加布里埃尔·冈萨雷斯的话: 请注意,您可以仅使用变压器依赖项构建任何(不仅仅是管道中的那个)。例如,下面是如何实现: 这将在那里键入check作为any,并为所有人做正确的事情。 所以我的问题是:对于管道的消费者部分,是否有一个对偶到和到? 要求: 从不使用,只返回(或从不返回),但使用的管道可以表示为“双重到列表”
在他对问题“类型类,和之间的区别”的回答中,Edward Kmett说 此外,即使是的一个超类,您最终还是需要类,因为遵守 严格来说还不足以证明这一点 因此,声称某样东西是一个比声称它是更强。 很明显,任何不是单子的应用函子都会自动成为的一个例子,它不是,但爱德华·科米特的回答暗示存在一个单子,它是,而不是:它的和
问题内容: 这一直使我感到困惑。看起来这样会更好: 比这个: 是否有特定原因? 问题答案: 这是因为任何可迭代对象都可以连接(例如,列表,元组,字典,集合),但是其内容和“连接器” 必须是 字符串。 例如: 使用字符串以外的其他东西会引发以下错误:
我的讲师在课堂上问过我这个问题,我想知道为什么是宏而不是函数?
rank ▲ ✰ vote url 37 511 93 416 url 为什么是string.join(list)而不是list.join(string)? 我一直被这个问题困扰.如果这样写更好: my_list = ["Hello", "world"] print my_list.join("-") # Produce: "Hello-world" 而不是: my_list = ["Hello
问题内容: 我已经在Android代码中使用FloatBuffers一段时间了(从一些opengles教程中复制了它),但是我无法确切地理解此构造是什么以及为什么需要它。 例如,我在许多人的代码和android教程中看到了以下代码(或类似代码): 就我所知,这似乎是冗长和混乱的,我只是说它们只是一个浮点数的包装而已。 问题: 与任何其他类型的float集合或简单数组相反,这种类型的类(ByteBu