You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中Monad函数dist与join的关系及Annotated类型等式问题

问题原因

问题出在你joinAnnotated实现里的Semigroup运算顺序和distAnnotated里的顺序不匹配,因为Semigroup的<>默认不满足交换律,两边计算出来的注释拼接顺序相反,我们可以直接展开等式右侧的表达式验证:

我们取两个具体的Annotated值做测试:

p = 1 :# ["p的注释"]
q = 2 :# ["q的注释"]

按你给出的三个函数实现,逐步计算等式右侧:

  1. 先计算最内层的mapAnnotated (\b -> (a, b)) q:按mapAnnotated的实现,保留q的注释,得到结果 (a, 2) :# ["q的注释"]
  2. 再计算外层的mapAnnotated (\a -> 上述结果) p:保留p的注释,得到结果 ((1, 2) :# ["q的注释"]) :# ["p的注释"]
  3. 最后用joinAnnotated处理上述结果:按你的实现,注释拼接为内层注释加外层注释,得到最终结果 (1, 2) :# ["q的注释", "p的注释"]

而你实现的distAnnotated计算distAnnotated (p, q)得到的结果是 (1, 2) :# ["p的注释", "q的注释"],两边注释顺序相反,自然不满足等式。


解决方法

你可以任选一种修改方式对齐顺序,通常Writer类带注释的Monad会遵循「先产生的注释在前」的规则,也就是外层计算的注释在前,内层计算的在后,更推荐修改joinAnnotated的拼接顺序:

joinAnnotated :: Semigroup e => Annotated e (Annotated e a) -> Annotated e a
joinAnnotated ((b :# m) :# n) = b :# n <> m

修改后join得到的注释顺序会变成外层的p注释在前,内层的q注释在后,和你现有的distAnnotated结果完全一致。

如果你不想修改joinAnnotated的实现,也可以调整distAnnotated的拼接顺序:

distAnnotated :: Semigroup e => (Annotated e a, Annotated e b) -> Annotated e (a, b)
distAnnotated (x :# m, y :# n) = (x, y) :# n <> m

内容的提问来源于stack exchange,提问作者Dmitry Ivanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 22:24:10