Suppose I have a stupid little case class like so:
case class Foo(name: String, other: Foo)
How can I define a
and b
immutably such that a.other
is b
, and b.other
is a
? Does scala provide some way to "tie the knot"? I'd like to do something like this:
val (a, b): (Foo, Foo) = (Foo("a", b), Foo("b", a)) // Doesn't work.
Possibilities
In Haskell I would do this:
data Foo = Foo { name :: String, other :: Foo }
a = Foo "a" b
b = Foo "b" a
Where the bindings to a
and b
are contained in the same let
expression, or at the top level.
Or, without abusing Haskell's automagical letrec capabilities:
(a, b) = fix (\ ~(a', b') -> Foo "a" b', Foo "b" a')
Note the lazy pattern, ~(a', b')
, that's important.
You want
Foo
to be unchanged, but laziness in Scala is on the declaration site. It is impossible forFoo
to be non-strict without changing it, and the pattern indicated in Haskell only works becauseFoo
, there, is non-strict (that is,Foo "a" b
doesn't evaluateb
immediately).Otherwise the solution is pretty much the same, allowing for the hoops necessary to get everything non-strict: