2012-06-06 15 views
10

Supongamos que tengo un poco de clase estúpido caso así:letrec en Scala? ("? Atar el nudo" forma inmutable que)

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

¿Cómo puedo definir a y b inmutable tal que a.other es b, y b.other es a? ¿Scala proporciona alguna forma de "tie the knot"? Me gustaría hacer algo como esto:

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

Posibilidades

En Haskell Me gustaría hacer esto:

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

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

Donde los enlaces a a y b están contenidas en el la misma expresión let, o en el nivel superior.

O, sin abusar de las capacidades letrec automágicas de Haskell:

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

Nota el patrón perezoso, ~(a', b'), eso es importante.

+3

Me pregunto cuántos motores de búsqueda ahora se empieza a encontrar esta pregunta para "boda" ... –

+2

Esta pregunta es más o menos un duplicado de http://stackoverflow.com/questions/7507965/instantiating-immutable-paired-objects. Además, si fuera posible con clases de casos, 'toString' recurriría para siempre –

+0

@LuigiPlinge. Esa solución infecta la definición de la clase en sí misma. Me gustaría ver una solución donde 'Foo' no esté dañado. 'toString' de hecho se repetirá para siempre. –

Respuesta

13

Quiere que se modifique Foo, pero la pereza en Scala se encuentra en el sitio de declaración. Es imposible que Foo sea no estricto sin cambiarlo, y el patrón indicado en Haskell solo funciona porque Foo, allí, no es estricto (es decir, Foo "a" b no evalúa b inmediatamente).

lo contrario, la solución es más o menos la misma, teniendo en cuenta los aros necesarios para que todo no estricto:

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)) 
+1

Ah tienes razón. La definición de 'datos Foo = Foo {name ::! String, other ::! Foo}' hace que las soluciones Haskell no funcionen. –

+0

Gracias por el comentario "de lo contrario, Scala siempre reevaluará". ¡Es bueno saberlo! – Madoc

Cuestiones relacionadas