f、g、h的Kleisli((->)e)a b <=> f >>>(g &&&h)=(f >>> g)&&&(f >>> h)?

5

编辑:如果存在这样的函数 f,使得箭头 p 纯净,则我们将称箭头 p 为纯箭头:p = arr f

我试图更好地掌握 Haskell 中的 Arrow,并想要找出何时成立:

f >>> (g &&& h) = (f >>> g) &&& (f >>> h),其中 fgh 都是箭头。

显然,这并不普遍成立。在这个特定的例子中,右侧的副作用被复制了:

GHCi> c = Kleisli $ \x -> ("AB", x + 1)
GHCi> fst . runKleisli (c >>> c &&& c) $ 1
"ABABAB"
GHCi> fst . runKleisli ((c >>> c) &&& (c >>> c)) $ 1
"ABABABAB"

显然,如果f是纯函数,则 f >>> (g &&& h) = (f >>> g) &&& (f >>> h)
我在 GHCi 中尝试了此语句对于f, g, h :: Kleisli ((->) e) a b的实现,但未能找到这样的fgh的值,使得f >>> (g &&& h) ≠ (f >>> g) &&& (f >>> h)。对于f, g, h :: Kleisli ((->) e) a b,此语句是否确实正确,如果是,这是否可以作为一个有效的证明: Monad ((->) e)的效果是从环境中读取。因此,应用f的结果是帮助gh从环境中读取的函数。无论此函数在何处创建 - 它都是相同的,因为它每次都应用于相同的参数,因此从环境中读取的结果也是相同的,因此整体结果也是相同的。

2
有趣的后续问题是:哪些单子具有这种属性?它们是否都同构于ReaderWriteridempotent单子的组合? - leftaroundabout
@leftaroundabout,我非常确定我们可以将“Either”和“Maybe”单子加入列表中,因为它们的效果取决于应用程序的顺序,并且根据“(&&&)”的定义,这些应用程序在左手和右手上是相同且顺序相同的。但我可能错了。你怎么看? - Zhiltsoff Igor
1个回答

5

直观理解

是的,(->) e这个单子是一个reader(读者)单子,无论我们进行两次读取还是只有一次都没有关系。运行f一次或两次并不重要,因为它总是会产生相同的结果,并具有相同的效果(读取)。

你的推理在我的看来是直观正确的。

正式表述

f, g, h :: Kleisli ((->) e) a b实际上意味着f, g, h :: a -> (e -> b),去掉了包装。

同样地,忽略这层包装,我们得到

for all (f :: a -> e -> b) and (g :: b -> e -> c)
f >>> g = (\xa xe -> g (f xa xe) xe)

for all (f :: a -> e -> b) and (g :: a -> e -> c)
f &&& g = (\xa xe -> (f xa xe, g xa xe))

因此:
f >>> (g &&& h)
= { def &&& }
f >>> (\xa xe -> (g xa xe, h xa xe))
= { def  >>> }
(\xa' xe' -> (\xa xe -> (g xa xe, h xa xe)) (f xa' xe') xe')
= { beta }
(\xa' xe' -> (g (f xa' xe') xe', h (f xa' xe') xe'))


(f >>> g) &&& (f >>> h)
= { def >>> }
(\xa xe -> g (f xa xe) xe) &&& (\xa xe -> h (f xa xe) xe)
= { def &&& }
(\xa' xe' -> ((\xa xe -> g (f xa xe) xe) xa' xe', (\xa xe -> h (f xa xe) xe) xa' xe'))
= { beta }
(\xa' xe' -> (g (f xa' xe') xe', h (f xa' xe') xe'))

“Either”和“Maybe”单子是否也具有这种属性? 我相信它们具有这种属性,因为它们的效果取决于应用程序的顺序,并且根据“(&&&)”的定义,左手和右手的应用程序是相同的并且顺序相同。 - Zhiltsoff Igor
1
@ZhiltsoffIgor,我猜他们应该有这个。 - chi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接