定义索引 monad a la Atkey 的常用方法是:
class IxMonad m where
ireturn :: a -> m i i a
ibind :: m i j a -> (a -> m j k b) -> m i k b
在 McBride 的工作中发现了另一种方法(也被他 here 讨论过):
type f :-> g = forall i. f i -> g i
class MonadIx (m :: (state -> *) -> (state -> *)) where
returnIx :: f :-> m f
flipBindIx :: (f :-> m g) -> (m f :-> m g)
flipBindIx
的类型与 bindIx :: forall i. m f i -> (forall j. f j -> m g j) -> m g i
同构。正常的 Haskell monad 表征 m :: * -> *
(而“正常”索引的 monad 表征 m :: state -> state -> * -> *
),而 MonadIx
表征 monad m :: (state -> *) -> state -> *
。这就是为什么我称后者为“高阶”(但如果有更好的名字,请告诉我)。
虽然这在一定程度上有意义,并且我可以看到两种编码之间的某些结构相似性,但我在一些事情上遇到了困难。以下是一些看似相关的问题:
基本上,我只是不明白如何使用 MonadIx
编写一个简单的索引状态 monad——IxMonad
中的那个看起来就像常规状态 monad,带有更一般的类型。
相关地,在之前链接的 SO 问题中,Kmett discusses 是一种从 IxMonad
中“恢复”MonadIx
的力量的方法。然而,该技术并未完全展示(而且我无法再编译相关代码)。
MonadIx
比 IxMonad
强。这表明应该存在从任何 IxMonad m => m i o a
到某个 MonadIx m => m f
(或者是 m f i
?)的映射,但不是相反,对吗?那是什么映射?
最后,MonadIx
的定义中充满了参数化。但是 IxMonad
动作可以自由地对传入状态的形状提出要求,如 m :: IxMonad m (a, i) i a
。 MonadIx
中的此类操作如何?
答案 0 :(得分:2)
我只是不明白如何使用 MonadIx 编写一个简单的索引状态 monad——在 IxMonad 中的那个看起来就像常规状态 monad,具有更通用的类型。
McBride 风格的索引 monad 是关于量化运行时不确定性。如果普通 monad m a
对返回 a
的计算进行建模,则索引 monad m a i
对从 state* i
开始并返回 a j
的计算进行建模对于某些未知输出状态 j
。关于 j
,您唯一可以说的是它满足谓词 a
。
*我在这里使用了“状态”、“输入”和“输出”这三个词。
这就是 McBride 的 bind
具有更高等级类型的原因:
mcBind :: m a i -> (forall j. a j -> m b j) -> m b i
延续 forall j. a j -> m b j
必须与 j
无关,超出了它在运行时检查 a j
所能学到的。 (对于返回多个 a
的非确定性 monad,它们中的每一个的 j
可能不同。)
McBride 来自 the Outrageous Fortune paper 的运行示例是关于文件 API,它可能成功返回打开的文件或可能失败(如果文件不存在)。 the Hasochism paper 中还有另一个关于平铺窗口管理器的示例 — 您有一个 2D 框,它可能由彼此相邻放置的较小框组成。您可以深入查看单个框并用其他框替换它们。您不知道每个单独的盒子在静态上有多大,但是当用另一个盒子替换一个盒子时,它们必须具有相同的大小。
因此索引状态 monad (State i j a
) 采用已知的输入状态 i
并产生已知的输出状态 j
,只是不适合 strong> 用于 McBride 风格的索引 monad。 mcBind
的类型是错误的,因为它丢弃了有关输出状态的信息。
[T] 这里应该是从任何 IxMonad
[到] MonadIx
的映射,但不是相反,对吗?那是什么映射?
相反。 McBride 的索引 monad 比 Atkey 的更强大——如果你有一个 m :: (i -> *) -> i -> *
的实例为 MonadIx
,你总是可以想出一个对应的 n :: i -> i -> * -> *
的实例为 IxMonad
. (Surprisingly the reverse is also true。)这在 McBride 的论文(“天使、恶魔和鲍勃”)的第 5 节中有详细说明。简而言之:
-- McBride wittily pronounces this type "at key"
data (a := i) j where
V :: a -> (a := i) i
newtype Atkey m i j a = Atkey { getAtkey :: m (a := j) i }
instance MonadIx m => IxMonad (Atkey m) where
ireturn a = Atkey (returnIx (V a))
ibind (Atkey m) f = Atkey $ m `bindIx` (\(V a) -> getAtkey (f a))