Joh*_*ler 5 recursion haskell abstract-data-type data-structures
给定两种日期类型定义如下:
data Foo = Foo Bar String
data Bar = Bar Foo String
Run Code Online (Sandbox Code Playgroud)
我怎样才能使foo和bar这样foo是Foo bar "foo"和bar是Bar foo "bar"?
当我们将类型更改为:
data Foo = Foo Bar (MVar String)
data Bar = Bar Foo (MVar String)
Run Code Online (Sandbox Code Playgroud)
只使用a let就足够了(let在Haskell中letrec,并支持相互递归的定义).相互递归的定义在堆中设置循环,如下所示:

该MVar初始化并没有真正改变任何有意义的方式事情.
import Control.Concurrent
data Foo = Foo Bar (MVar String)
data Bar = Bar Foo (MVar String)
main = do
a <- newMVar "foo"
b <- newMVar "bar"
let foo = Foo bar a
bar = Bar foo b
return ()
Run Code Online (Sandbox Code Playgroud)
唐回答了问题,但一个更有趣的问题是如何处理
data Foo = Foo (MVar Bar) String
data Bar = Bar (MVar Foo) String
Run Code Online (Sandbox Code Playgroud)
现在这两个MVars不仅仅是递归的旁观者,而是共犯.
这可以通过两种方式完成:
1.)通过像C这样的命令式语言做你想做的事情:
mutation = do
-- setting up an empty mvar
bar <- newEmptyMVar
foo <- newMVar (Foo bar "foo")
-- and then filling it in
putMVar bar (Bar foo "foo")
return (foo, bar)
Run Code Online (Sandbox Code Playgroud)
2.)或者通过使用DoRec(以前称为RecursiveDo)并mfix在幕后打结:
{-# LANGUAGE DoRec #-}
mutual = do
rec foo <- newMVar (Foo bar "foo")
bar <- newMVar (Bar foo "foo")
return (foo, bar)
Run Code Online (Sandbox Code Playgroud)
这转化为类似于:
mutual = do
(foo, bar) <- mfix $ \(foo, bar) -> do
foo <- newMVar (Foo bar "foo")
bar <- newMVar (Bar foo "foo")
return (foo, bar)
return (foo, bar)
Run Code Online (Sandbox Code Playgroud)