假设我有一个愚蠢的小案例类,如下所示:
case class Foo(name: String, other: Foo)
我怎样才能一成不变地定义a
和b
,以便a.other
b
,b.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
其中,a
和b
的绑定包含在同一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))