创建彼此递归包含的抽象数据类型的实例

发布于 2024-11-04 05:03:04 字数 367 浏览 0 评论 0原文

给定两个日期类型定义如下:

data Foo = Foo Bar String
data Bar = Bar Foo String

如何使 foobar 使得 fooFoo bar "foo" 和 barBar foo "bar"

当我们将类型更改为:

data Foo = Foo Bar (MVar String)
data Bar = Bar Foo (MVar String)

Given two date types defined as follows:

data Foo = Foo Bar String
data Bar = Bar Foo String

How can I make foo and bar such that foo is Foo bar "foo" and bar is Bar foo "bar"?

What about when we change the types to:

data Foo = Foo Bar (MVar String)
data Bar = Bar Foo (MVar String)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

折戟 2024-11-11 05:03:04

只需使用 let 就足够了(Haskell 中的 letletrec,并且支持相互递归定义)。相互递归定义在堆中设置循环,如下所示:

foo bar let rec

MVar< /code> 初始化并没有真正以任何有意义的方式改变事情。

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 ()

Just using a let is enough (let in Haskell is letrec, and supports mutually recursive definitions). The mutually recursive definitions set up cycles in the heap, that look like this:

foo bar let rec

The MVar initialization doesn't really change things in any meaningful way.

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 ()
笑叹一世浮沉 2024-11-11 05:03:04

Don 按要求回答了问题,但一个稍微有趣的问题是如何处理

data Foo = Foo (MVar Bar) String
data Bar = Bar (MVar Foo) String

现在这两个 MVar 不仅仅是递归的旁观者,他们是共犯。

这可以通过两种方式完成:

1.) 要么执行在命令式语言(如 C: 2.)中执行的操作

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)

,要么使用 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)

Don answered the question as asked, but a slightly more interesting question is how to deal with

data Foo = Foo (MVar Bar) String
data Bar = Bar (MVar Foo) String

Now the two MVars aren't mere bystanders to the recursion, they are accomplices.

This can be done two ways:

1.) Either by doing what you would do in an imperative language like 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.) or by using DoRec (formerly RecursiveDo) and mfix and behind the scenes tie the knot:

{-# LANGUAGE DoRec #-} 

mutual = do
   rec foo <- newMVar (Foo bar "foo")
       bar <- newMVar (Bar foo "foo")
   return (foo, bar)

This translates to something analogous to:

mutual = do
   (foo, bar) <- mfix $ \(foo, bar) -> do
       foo <- newMVar (Foo bar "foo")
       bar <- newMVar (Bar foo "foo")
       return (foo, bar)
  return (foo, bar)
北方的韩爷 2024-11-11 05:03:04

由于 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

The following works fine thanks to Haskells lazyness.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文