让我们在斯卡拉?(不可变的"Tie the knot?"方式)



假设我有一个愚蠢的小案例类,如下所示:

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

我怎样才能一成不变地定义ab,以便a.other bb.other a?Scala 是否提供了某种"喜结连理"的方法?我想做这样的事情:

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

可能性

在哈斯克尔,我会这样做:

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'),这很重要。

您希望Foo保持不变,但 Scala 中的懒惰在声明站点上。如果不改变它,Foo就不可能不严格,而 Haskell 中指示的模式之所以有效,Foo 那里是非严格的(也就是说,Foo "a" b不会立即评估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))

相关内容

最新更新