放置的 MonadFix 实例


一个简单的

问题,我希望:binary包定义了两种类型,GetPut。前者本质上是国家单体,后者本质上是作家。状态和作家都有合理的MonadFix实例,所以我希望GetPut也会。

Get确实如此。 Put没有。那么,是否可以为Put定义一个合适的MonadFix实例(实际上是PutM)?

一个更普遍的问题是:通常如何验证类型类实例是否确实满足该类型类的定律?

正如您在二进制包的源代码(Data.Binary.Put:71)中看到的那样,用于一元值的数据结构在构建器中是严格的。 由于从 monad 中提取值必须强制找到该值的结构,因此如果构建器依赖于输入,这将导致无限循环。

data PairS a = PairS a !Builder
newtype PutM a = Put { unPut :: PairS a }

因此,您可以编写一个MonadFix实例,但您将无法对它执行任何有用的操作。 但是我认为无论如何你都可以在这里用MonadFix做任何有用的事情,至少你不能用普通的旧fix做任何事情,因为 PutM monad 基本上是Writer Builder的(但有一个专门的实现)。

至于你的第二个问题,它与第一个问题无关,所以你应该把它作为一个单独的问题来问。

这是对你的第二个问题的答案,也是丹尼尔评论的后续。 您手动验证法律,我将使用Functor定律的示例来Maybe

-- First law
fmap id = id
-- Proof
fmap id
= x -> case x of
    Nothing -> Nothing
    Just a  -> Just (id a)
= x -> case x of
    Nothing -> Nothing
    Just a -> Just a
= x -> case x of
    Nothing -> x
    Just a  -> x
= x -> case x of
    _ -> x
= x -> x
= id
-- Second law
fmap f . fmap g = fmap (f . g)
-- Proof
fmap f . fmap g
= x -> fmap f (fmap g x)
= x -> fmap f (case x of
    Nothing -> Nothing
    Just a  -> Just (f a) )
= x -> case x of
    Nothing -> fmap f  Nothing
    Just a  -> fmap f (Just (g a))
= x -> case x of
    Nothing -> Nothing
    Just a  -> Just (f (g a))
= x -> case x of
    Nothing -> Nothing
    Just a  -> Just ((f . g) a)
= x -> case x of
    Nothing -> fmap (f . g) Nothing
    Just a  -> fmap (f . g) (Just a)
= x -> fmap (f . g) (case x of
    Nothing -> Nothing
    Just a  -> Just a )
= x -> fmap (f . g) (case x of
    Nothing -> x
    Just a  -> x )
= x -> fmap (f . g) (case x of
    _ -> x )
= x -> fmap (f . g) x
= fmap (f . g)

显然,我本可以跳过很多步骤,但我只是想详细说明完整的证明。 在你掌握它们之前,证明这些类型的法律一开始是很困难的,所以最好从缓慢和迂腐开始,然后一旦你变得更好,你就可以开始组合步骤,甚至在一段时间后在你的脑海中做一些更简单的步骤。

最新更新