这应该是正确身份单子法则的反例。
下面,我们利用 中的函子乘积Maybe :*: Maybe
,GHC.Generics
但如果愿意,它可以被内联。这也是一个 applicative、alternative、foldable 和 monad。我相信这些情况下的图书馆是守法的。
然后,我们将提议instance Monad
的(问题中的那个)与标准库之一进行比较。我们发现建议的实例不满足正确的恒等律,而它似乎在库实例中成立(至少在我非常有限的测试中)。
{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, TypeOperators #-}
{-# OPTIONS -Wall #-}
module NotAMonad where
import Control.Applicative
import GHC.Generics ((:*:)(..))
-- A basic wrapper to avoid overlapping instances, and to be able to
-- define a custom monad instance.
newtype Wrap m a = Wrap { unWrap :: m a }
deriving (Functor, Applicative, Alternative, Foldable, Show)
-- The proposed instance
instance (Applicative f, Alternative f, Foldable f) => Monad (Wrap f) where
(>>=) = flip $ \f -> foldr (<|>) empty . fmap f
-- This is Applicative, Alternative, and Foldable
type T = Maybe :*: Maybe
-- A basic test
test :: Wrap T Int
test = Wrap (Just 3 :*: Just 4) >>= return
-- result:
-- Wrap {unWrap = Just 3 :*: Just 3}
现在4
替换为3
。不过,我并没有试图解释原因。估计是由Just 3 <|> Just 4 = Just 3
.
相反,使用库 monad 实例,一切看起来都很好:
> (Just 3 :*: Just 4) >>= return
Just 3 :*: Just 4