斯卡拉的letrec? (“打结”的不可改变的方式?)

时间:2012-06-06 00:26:26

标签: scala letrec tying-the-knot

假设我有一个像这样的愚蠢的小案例类:

case class Foo(name: String, other: Foo)

如何定义ab不可变,a.otherbb.othera? scala是否为"tie the knot"提供了一些方法?我想做这样的事情:

val (a, b): (Foo, Foo) = (Foo("a", b), Foo("b", a)) // Doesn't work.

可能性

在Haskell中,我会这样做:

data Foo = Foo { name :: String, other :: Foo }

a = Foo "a" b
b = Foo "b" a

ab的绑定包含在同一个let表达式中,或位于顶层。

或者,不会滥用Haskell的自动化letrec功能:

(a, b) = fix (\ ~(a', b') -> Foo "a" b', Foo "b" a')

请注意惰性模式~(a', b'),这很重要。

1 个答案:

答案 0 :(得分:13)

您希望Foo保持不变,但Scala中的懒惰位于声明网站上。 Foo不可能在不改变它的情况下是非严格的,并且Haskell中指示的模式只能起作用,因为Foo,那里是非严格的(即Foo "a" b没有' t立即评估b

否则解决方案几乎是相同的,允许必要的箍以使所有事情都不严格:

class Foo(name: String, other0: => Foo) { // Cannot be case class, because that mandates strictness
  lazy val other = other0 // otherwise Scala will always reevaluate
}
object Foo {
  def apply(name: String, other: => Foo) = new Foo(name, other)
}

val (a: Foo, b: Foo) = (Foo("a", b), Foo("b", a))