Haskell 理解MonadFix的滑动定律

Haskell 理解MonadFix的滑动定律,haskell,monads,monadfix,Haskell,Monads,Monadfix,我直观地理解了这些元素的纯度、紧密性和嵌套规律。然而,我很难理解滑动定律 mfix(fmap h.f)=fmap h(mfix(f.h))--用于严格h 我的第一个问题是,如果h必须严格,那么mfix(f.h)不会是底部值,即⊥?毕竟,f。h必须在其返回后才能检查其输入,以免引起矛盾。但是,如果h是严格的,则必须检查其输入。也许我对严格函数的理解是错误的 第二,为什么这项法律很重要?我能理解纯度、紧度和筑巢法则的重要性。然而,我不明白为什么mfix遵守滑动定律很重要。你能提供一个代码示例来说明

我直观地理解了这些元素的纯度、紧密性和嵌套规律。然而,我很难理解滑动定律

mfix(fmap h.f)=fmap h(mfix(f.h))--用于严格h
我的第一个问题是,如果
h
必须严格,那么
mfix(f.h)
不会是底部值,即
?毕竟,
f。h
必须在其返回后才能检查其输入,以免引起矛盾。但是,如果
h
是严格的,则必须检查其输入。也许我对严格函数的理解是错误的


第二,为什么这项法律很重要?我能理解纯度、紧度和筑巢法则的重要性。然而,我不明白为什么
mfix
遵守滑动定律很重要。你能提供一个代码示例来说明为什么滑动定律对MonadFix很重要吗?

我对MonadFix定律一无所知,但我想谈谈你问题的第一部分
h
严格并不意味着
f。h
也很严格。例如,以

h = (+ 1) :: Int -> Int
f x = Nothing :: Maybe Int
对于所有输入
x
(f.h)x
返回
Nothing
,因此从不调用
h
。如果您担心我的
h
没有看上去那么严格,请注意

fmap undefined (mfix (f . undefined)) :: Maybe Int

还返回
Nothing
。我对
h
的选择无关紧要,因为根本不调用
h

我不能完全解释这条定律,但我想我可以提供一些见解

让我们忘掉方程的一元部分,假设
f,h::A->A
是普通的非一元函数。然后,法律(非正式地说)简化为:

fix (h . f) = h (fix (f . h))
这是不动点理论中的一个著名性质

不过,非正式的直觉是,
g::A->A
的最小固定点可以写成

fix g = g (g (g (g ....))))
其中,
g
被应用“无限多次”。当
g
是类似
h的组合时。f
在这种情况下,我们得到

fix (h . f) = h (f (h (f (h (f ...)))))
同样地

fix (f . h) = f (h (f (h (f (h ...)))))
现在,由于两个应用程序都是无限的,如果我们在第二个应用程序的基础上应用
h
,我们将期望得到第一个。在周期数中,我们发现
4.5(78)
4.57(87)
相同,因此同样的直觉适用。在公式中

h (fix (f . h)) = fix (h . f)
这正是我们想要的法律

有了单子,如果
f::A->mb
h::B->A
,我们就无法轻松地组合东西,因为我们需要到处使用
fmap
,当然也需要
mfix
而不是fix。我们有

fmap h . f :: A -> M A
f . h      :: B -> M B
因此,两者都是
mfix
的候选对象。要在
mfix
之后应用“顶层”
h
,我们还需要
fmap
它,因为
mfix
返回
ma
。然后我们获得

mfix (fmap h . f) = fmap h (mfix (f . h))
现在,上述推理并不完全严格,但我相信它可以在领域理论中得到适当的形式化,因此即使从数学/理论的角度来看也是有意义的。

MonadFix滑动定律 不幸的是,您提供的链接对滑动定律的描述不正确。它说:

mfix (fmap h . f) = fmap h (mfix (f . h)) -- for strict h
实际的滑动规律略有不同:

mfix (fmap h . f) = fmap h (mfix (f . h)), when f (h _|_) = f _|_
也就是说,前提条件比要求
h
严格要弱。它只要求
f(h | |))=f | |
。请注意,如果
h
是严格的,则自动满足此前提条件。(具体情况见下文。)这种区别在一元情况下很重要,即使
fix
的相应法律没有这种区别:

fix (f . g) = f (fix (g . f)) -- holds without any conditions!
这是因为底层monad的绑定在其左参数中通常是严格的,因此可以观察到事物的“移动”。有关详细信息,请参见第2.4节

严格的
h
案例 当
h
是严格的,那么该定律实际上直接遵循
(A->ma)->ma类型的参数定理。这一点在同一文本的第2.6.12条中得到了证实,尤其是推论。从某种意义上说,这是一个“无聊”的例子:也就是说,所有带有
mfix
的单子都满足它。(因此,将该特定案例列为“法律”并没有真正的意义。)

由于
f(h | | |)=f | |
的要求较弱,我们得到了一个更有用的方程,该方程允许我们处理涉及
mfix
的项,因为它适用于由正则一元函数(即上面的
f
和纯函数(即上面的
h
组成的函数)

我们为什么关心? 你仍然可以问,“为什么我们关心滑动定律?”chi的回答提供了直觉。如果你用一元绑定来写法律,它会变得更清晰。下面是该符号的结果:

mfix (\x -> f x >>= return . h) = mfix (f . h) >>= return .h
如果你看左边,我们会看到
返回。h
是一个中心箭头(即,仅影响值而不影响“一元”部分),因此我们希望能够将其从
=
的右侧“提起”。事实证明,对于任意的
h
,这一要求太高了:可以看出,许多实际感兴趣的单子都没有这样的
mfix
定义。(细节:参见。)但是我们只需要
f(h | | uu)=h |
的弱化形式通过许多实际例子得到了满足

在图片中,滑动法则允许我们进行以下转换:


这给了我们一种直觉:我们希望将一元结应用到“最小”的可能范围,允许根据需要重新安排/洗牌其他计算。滑动属性准确地告诉我们什么时候可以这样做。

哦,对了。Haskell中的评估是从外到内的。因此,
f
可以选择是否对其参数求值。谢谢你澄清这一点。