隐含提升的正确性

时间:2013-02-18 01:45:39

标签: haskell types

想象一下,我有一个比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

...其中MT 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 mm的有效替代,假设两种类型检查。短语问题有点困难,因为它需要m类型检查作为替换之前和之后的两个单独的monad。据我所知,这种替换进行类型检查的唯一方法是m是否对于monad是通用的。

我模糊的直觉是替换应该总是正确的,但我不确定我的直觉是否正确,或者如果它是正确的,如何证明它。

2 个答案:

答案 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技巧,除非你传递一个参数。使用了一些技巧,例如herehere。)

鉴于m,我们通过monad变换器法则(m ~ Identity)知道m = return x

当然,这只适用于这种特殊类型。如果您有lift . return = return,那么lift m = m可能很容易与m :: MonadState S m => m A不同 - 例如,类型为mlift m和{ {1}}会有所不同。

(当然所有这些都忽略了⊥。然后,如果你不这样做,大多数monad都不遵守法律。)

答案 1 :(得分:2)

我认为这是一个草率inductive proofm相当于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