Pergunta sobre tying-the-knot, letrec, scala – letrec em Scala? (Maneira imutável de "amarrar o nó?")

10

Suponha que eu tenha uma pequena classe de casos assim:

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

Como posso definira eb imutavelmente tal quea.other ébeb.other éa? Scala fornece alguma maneira de"amarre o nó"? Eu gostaria de fazer algo assim:

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

Possibilidades

Em Haskell eu faria isso:

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

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

Onde as ligações paraa eb estão contidos no mesmolet expressão, ou no nível superior.

Ou, sem abusar dos recursos automagical da letrec de Haskell:

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

Observe o padrão preguiçoso~(a', b'), isso é importante.

@LuigiPlinge essa solução infecta a definição da própria classe. Eu gostaria de ver uma solução ondeFoo está sem restrições.toString iria de fato recorrer para sempre. Dan Burton
Gostaria de saber quantos mecanismos de busca começarão a encontrar essas perguntas para "casamento" ... user166390
Esta questão é mais ou menos uma duplicata destackoverflow.com/questions/7507965/…. Além disso, se fosse possível com as classes de casostoString iria recorrer para sempre Luigi Plinge

Sua resposta

1   a resposta
13

Foo para ser inalterado, mas a preguiça em Scala está no local da declaração. É impossível paraFoo para ser não-estrito, sem alterá-lo, e o padrão indicado em Haskell só funciona porqueFoo, não é estrito (isto é,Foo "a" b não avaliab imediatamente).

Caso contrário, a solução é praticamente a mesma, permitindo que os aros necessários para obter tudo não-estrito:

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))
Obrigado pelo comentário "caso contrário, Scala sempre irá reavaliar". Isso é bom saber! Madoc
Ah você está certo. Definindodata Foo = Foo { name :: !String, other :: !Foo } faz com que as soluções Haskell não funcionem. Dan Burton

Perguntas relacionadas