给定两种日期类型定义如下:
data Foo = Foo Bar String
data Bar = Bar Foo String
如何foo
和bar
foo
为Foo bar "foo"
且bar
为Bar foo "bar"
?
当我们将类型更改为:
时data Foo = Foo Bar (MVar String)
data Bar = Bar Foo (MVar String)
答案 0 :(得分:7)
只需使用let
即可(Haskell中的let
为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 ()
答案 1 :(得分:5)
Don回答了问题,但一个更有趣的问题是如何处理
data Foo = Foo (MVar Bar) String
data Bar = Bar (MVar Foo) String
现在两个MVar不仅仅是递归的旁观者,而是他们的共犯。
这可以通过两种方式完成:
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)
2。)或者使用DoRec(以前称为RecursiveDo)和mfix
并在幕后打结:
{-# LANGUAGE DoRec #-}
mutual = do
rec foo <- newMVar (Foo bar "foo")
bar <- newMVar (Bar foo "foo")
return (foo, bar)
这意味着类似于:
mutual = do
(foo, bar) <- mfix $ \(foo, bar) -> do
foo <- newMVar (Foo bar "foo")
bar <- newMVar (Bar foo "foo")
return (foo, bar)
return (foo, bar)
答案 2 :(得分:0)
由于Haskell的懒惰,以下工作正常。
data Foo = Foo Bar String deriving Show
data Bar = Bar Foo String deriving Show
test = let
foo = Foo bar "foo"
bar = Bar foo "bar"
in foo