我一直在尝试mfix
使用Control.Arrow.loop
. 我想出了不同的定义,并mfix
想看看哪一个是实际工作相似的。
因此,我认为正确的解决方案如下:
mfix' :: MonadFix m => (a -> m a) -> m a
mfix' k = let f ~(_, d) = sequenceA (d, k d)
in (flip runKleisli () . loop . Kleisli) f
可以看到,loop . Kleisli
' 的论点适用于Applicative
实例。我发现这是一个好兆头,因为在正确的论点中,我们的打结大多被(>>=)
' 严格性破坏了。
这是另一个功能。我可以说这不是mfix
完全一样的,但我发现的唯一情况不是很自然。看一看:
mfix'' k = let f ~(_, d) = fmap ((,) d) (return d >>= k)
in (flip runKleisli () . loop . Kleisli) f
据我了解,并非所有严格的右手绑定都完全强制其论点。例如,在以下情况下IO
:
GHCi> mfix'' ((return :: a -> IO a) . (1:))
[1,1,1,1,1,Interrupted.
所以,我决定解决这个问题。我只是接受Maybe
并强行x
加入Just x >>= k
:
data Maybe' a = Just' a | Nothing' deriving Show
instance Functor Maybe' where
fmap = liftM
instance Applicative Maybe' where
pure = return
(<*>) = ap
instance Monad Maybe' where
return = Just'
Nothing' >>= k = Nothing'
Just' x >>= k = x `seq` k x
instance MonadFix Maybe' where
mfix f = let a = f (unJust' a) in a
where unJust' (Just' x) = x
unJust' Nothing' = errorWithoutStackTrace "mfix Maybe': Nothing'."
我们手上有这个:
GHCi> mfix ((return :: a -> Maybe' a) . (1:))
[1,1,1,1,1,Interrupted.
GHCi> mfix' ((return :: a -> Maybe' a) . (1:))
[1,1,1,1,1,Interrupted.
GHCi> mfix'' ((return :: a -> Maybe' a) . (1:))
Interrupted.
所以,这是我的问题:
- 有没有其他例子可以证明这
mfix''
不是完全的mfix
? - 具有如此严格绑定的 monad
Maybe'
在实践中是否有趣? - 是否有任何例子表明我没有找到
mfix'
不完全是?mfix
关于IO
:
mfix3 k' =
let
k = return . k'
f ~(_, d) = fmap ((,) d) (d >>= k)
in (join . flip runKleisli () . loop . Kleisli) f
不要担心所有的return
s 和join
s - 它们在这里只是为了让mfix3
's 和mfix
' 类型匹配。这个想法是我们传递d
自己而不是传递return d
到(>>=)
右手边。它为我们提供了以下信息:
GHCi> mfix3 ((return :: a -> IO a) . (1:))
Interrupted.
然而,例如(感谢Li-yao Xia的评论):
GHCi> mfix3 ((return :: a -> e -> a) . (1:)) ()
[1,1,1,1,1,Interrupted.
编辑:感谢HTNW 在评论中对模式匹配的重要说明:最好使用\ ~(_, d) -> ...
,而不是\ (_, d) -> ...
.