Haskell 如果我们用它来写mfix,liftM对函子实例是否太严格了?
Haskell 如果我们用它来写mfix,liftM对函子实例是否太严格了?,haskell,monads,functor,strictness,Haskell,Monads,Functor,Strictness,fmap对于monad通常默认为: 我的直觉是是的,它可以被使用。我估计我们只在两种情况下遇到问题: k我们将mfix/myMfix应用于一个严格的系统 我们将mfix/myMfix应用于return 这两种情况都相当简单,我们一开始并不期望有任何收敛的结果。我相信其他案例可以在不强制反馈的情况下被强制WHNF 我的直觉正确吗?如果没有,你能举一个失败的例子吗?你对Id'的定义不是有效的单子,因为它违反了左单位定律: 返回未定义>=const(返回3) =Id'未定义>>=const(返回3)
fmap
对于monad
通常默认为:
我的直觉是是的,它可以被使用。我估计我们只在两种情况下遇到问题:
k
我们将mfix
/myMfix
应用于一个严格的系统mfix
/myMfix
应用于return
我的直觉正确吗?如果没有,你能举一个失败的例子吗?你对
Id'
的定义不是有效的单子,因为它违反了左单位定律:
返回未定义>=const(返回3)
=Id'未定义>>=const(返回3)
=未定义的`seq`const(返回3)未定义
=未定义
这不等于
const(返回3)未定义
=返回3
=Id'3
因此,关于Id'
的MonadFix
定义是否有效的讨论相当没有意义,更不用说通过Kleisli构造的定义是否可信了
话虽如此,如果你想知道一个定义是否是mfix的忠实实现,你需要写下并证明严格、纯洁和收缩三条定律。如果你从一个实际的单子开始(而不是你的Id'
,它没有通过测试),那么你需要建立这三个定律,将其视为一个有效的单子反馈算子。如果不做这项工作,就不可能说这个定义是如何概括的
我的直觉是,通过Kleisli构造的定义直觉可能非常适用于行为良好的箭头,即那些循环
操作符确实满足正确的拧紧法则的箭头。然而,众所周知,具有左严格绑定运算符的monad的Kleisli类上的箭头没有满足右紧的循环
运算符。(见第6.4.1节中的说明和讨论。)
因此,任何具有左严格绑定运算符的monad(例如
[]
,可能
,IO
,严格状态等)都将无法通过测试。但是由monad(如环境、惰性状态)和由monoid(也称为writer monad)生成的箭头可能会起作用。我猜你的意思是Id'
,而不是代码中的Maybe'
。@Krantz是的。谢谢-我编辑了这篇文章。mfix
总是需要特别小心才能实现。不知道你能说多少,这将普遍适用。谢谢你的回答。然而,你在最后一篇摘录中提到的“克莱斯利·蒙纳德”是什么?此外,当你说我的直觉不适用于某些单子时,这是否意味着我们可能无法从mfix
循环中为一个符合Kleisli m
的单子提取信息?我不明白你在第一条评论中询问的是哪一个单子。关于你的第二个评论:我的意思是考虑任何具有左严格绑定操作符的Haskell monad。(可能是IO、List、Strict state…)为其构造Kleisli箭头。该箭头将不具有合适的循环运算符。也就是说,您不能为满足箭头循环法则的对象定义循环,因为正确的拧紧将失败。因此,实际上没有相应的mfix
可提取。关于第一个:您正在写:“但是,众所周知,从具有左严格绑定运算符的Kleisli单子产生的箭头没有”。什么是克莱斯里单子?关于第二个:即使某些实例不满足定律,但这并不意味着我们不想对这些单子使用定点(-like)组合符。问题是,如果我们尝试将我们的组合符应用于(1:)
,我们就可以马上得到WHNF。问题是当我们没有这样的案例时,这可能会如何影响反馈。我看到了混乱。我应该说“左严格绑定操作符的单子的Kleisli类上的箭头…”希望现在已经清楚了。相应地编辑了文本。关于mfix
/loop
等的非守法定义:您肯定可以定义任何您认为有用的函数。我可以看到一系列的研究削弱了mfix
/loop
法则,以允许更多的定义。如果你能想出一个更为宽容的抽象,它仍然是有用的,那将是值得探索的。但就我所知,这方面的研究基本上还没有涉足。(老实说,我不确定它是否非常有趣。)
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }
newtype Id' a = Id' { runId' :: a } deriving ...
instance Functor Id' where
fmap = liftM -- instead of `f <$> (Id' x) = Id' (f x)`.
instance Applicative Id' where
pure = return
(<*>) = ap
instance Monad Id' where
return = Id'
(Id' x) >>= k = x `seq` k x
instance MonadFix Id' where
mfix f = let a = f (runId' a) in a
myMfix :: MonadFix m => (a -> m a) -> m a
myMfix k = let f ~(_, d) = ((,) d) <$> k d
in (flip runKleisli () . loop . Kleisli) f