Frage an scala, letrec, tying-the-knot – letrec in Scala? (Unveränderliche Weise, den Knoten zu binden?)

10

Angenommen, ich habe so eine dumme kleine Fallklasse:

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

Wie kann ich definierena undb unveränderlich so, dassa.other istb, undb.other ista? Bietet Scala eine Möglichkeit dazu?"binde den Knoten"? Ich würde gerne so etwas machen:

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

Möglichkeiten

In Haskell würde ich das machen:

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

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

Wo die Bindungen sinda undb sind in demselben enthaltenlet Ausdruck oder auf der obersten Ebene.

Oder, ohne die automagischen Letrec-Funktionen von Haskell zu missbrauchen:

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

Beachten Sie das faule Muster,~(a', b'), das ist wichtig.

@LuigiPlinge Diese Lösung infiziert die Definition der Klasse selbst. Ich würde gerne eine Lösung sehen, woFoo ist unbestritten.toString würde in der Tat für immer wiederkehren. Dan Burton
Ich frage mich, wie viele Suchmaschinen nun anfangen werden, diese Fragen für "Hochzeit" zu finden ... user166390
Diese Frage ist mehr oder weniger ein Duplikat vonstackoverflow.com/questions/7507965/…. Auch wenn es mit Fallklassen möglich wäre dietoString würde für immer wiederkehren Luigi Plinge

Deine Antwort

1   die antwort
13

Sie wollenFoo unverändert zu sein, aber Faulheit in Scala ist auf der Deklarationsseite. Es ist unmöglich fürFoo nicht streng zu sein, ohne es zu ändern, und das in Haskell angegebene Muster funktioniert nur, weilFoodort ist nicht streng (das heißt,Foo "a" b bewertet nichtb sofort).

Ansonsten ist die Lösung so ziemlich die gleiche, so dass die erforderlichen Rahmen vorhanden sind, um alles zu erhalten, was nicht streng ist:

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))
Ah, du hast recht. Definierendata Foo = Foo { name :: !String, other :: !Foo } bewirkt, dass die Haskell-Lösungen nicht funktionieren. Dan Burton
Danke für den Kommentar "Sonst wird Scala immer neu bewerten". Das ist gut zu wissen! Madoc

Verwandte Fragen