想象一下,我有一个比monad更通用的值:
m :: (Monad m) => m A -- 'A' is some concrete type
现在让我们说我将这个值专门化为一个具体的monad变换器堆栈,有两种不同的方式:
m1 :: T M A
m1 = m
m2 :: T M A
m2 = lift m
...其中M
和T M
是monad,T
是monad变换器:
instance Monad M where ...
instance (Monad m) => Monad (T m) where ...
instance MonadTrans T where ...
......这些实例遵守monad法律和monad变压器法则。
我们可以推断出:
m1 = m2
......对m
以外的其他类型一无所知?
这只是一个冗长的方式,询问lift m
是m
的有效替代,假设两种类型检查。短语问题有点困难,因为它需要m
类型检查作为替换之前和之后的两个单独的monad。据我所知,这种替换进行类型检查的唯一方法是m
是否对于monad是通用的。
我模糊的直觉是替换应该总是正确的,但我不确定我的直觉是否正确,或者如果它是正确的,如何证明它。
答案 0 :(得分:9)
如果m :: Monad m => m A
,那么m
必须与某些return x
的{{1}}等效,因为x :: A
获取任何内容的唯一方法是{{} 1}}和:: m x
。但是,为了使用return
,您必须能够生成一些(>>=)
,您可以使用(>>=)
或使用m y
的其他应用程序。无论哪种方式,你最终都必须使用return
,monad法则保证整个表达式等同于(>>=)
。
(如果return
对monad完全是多态的,那么你必须能够在return x
使用它,所以它不能使用任何花哨的monad技巧,除非你传递一个参数。使用了一些技巧,例如here和here。)
鉴于m
,我们通过monad变换器法则(m ~ Identity
)知道m = return x
。
当然,这只适用于这种特殊类型。如果您有lift . return = return
,那么lift m = m
可能很容易与m :: MonadState S m => m A
不同 - 例如,类型为m
,lift m
和{ {1}}会有所不同。
(当然所有这些都忽略了⊥。然后,如果你不这样做,大多数monad都不遵守法律。)
答案 1 :(得分:2)
我认为这是一个草率inductive proof,m
相当于lift m
。
我认为我们必须尝试证明m
(或者更确切地说,关于类型(Monad m) => m A
的所有可能值)。如果我们将Monad
视为仅包含绑定和返回,并忽略底部和fail
,那么您的m
必须位于顶层:
mA = return (x)
mB = (mX >>= f)
对于mA
,两种形式的m
等同于monad变换器定律:
lift (return (x)) = return (x)
这是基本情况。然后我们留下第二个变压器定律来推理mB
:
lift (mX >>= f) = lift mX >>= (lift . f)
我们想要证明我们的mB
等于那个扩展:
mX >>= f = lift mX >>= (lift . f)
我们假设bind的左侧是等价的(mX = lift mX
),因为这是我们的归纳假设(对吧?)。
那么我们就可以通过弄清楚f = lift . f
的样子来证明f
:
f :: a -> m b
f = \a -> (one of our forms mA or mB)
和lift . f
看起来像:
f = \a -> lift (one of our forms mA or mB)
这让我们回到了我们的假设:
m = lift m