fmap
对于Monads
通常默认为liftM
:
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }
然而,正如人们所看到的,它使用绑定(如右手去糖成m1 >>= \ x1 -> return (f x1)
)。我想知道这样的 a 是否fmap
可以用于为mfix
具有严格>>=
运算符的单子写下来。更准确地说,我想知道Control.Arrow.loop
(再次)的以下实现。
我使用的 monad 是Identity
,但它会在绑定发生时强制其中的任何内容seq
。
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
我的直觉是可以的,可以用。我认为我们只会在两种情况下遇到问题:
k
我们申请mfix
/myMfix
是严格的。- 我们申请
mfix
/myMfix
。return
这两种情况都相当简单,我们一开始并不期望任何收敛的结果。我相信其他案例可以在不强制反馈的情况下强制进行WHNF。
我的直觉正确吗?如果没有,可以举一个失败的例子吗?