/ / Kiedy pusta lista HL nie jest listą HL? - Scala, bezkształtna

Kiedy puste HList nie jest HList? - scala, bezkształtny

Podczas uczenia się bezkształtnego zastanawiam się, dlaczego to się nie kompiluje:

def someHList[H <: HList]: H = HNil

skoro obiekt HNil rozszerza cechę HNil, która rozszerza listę HList?

Jaki jest właściwy sposób zdefiniowania metody w cechy, która zwraca pewną listę HList, która jest implementowana tylko przez rozszerzającą klasę?

Chciałbym zrobić coś takiego:

trait Parent {
def someHList[H <: HList]: H
}

object Child1 extends Parent {
def someHList[H <: HList] = HNil
}

object Child2 extends Parent {
def someHList[H <: HList] = 1 :: "two" :: HNil
}

Wszelkie porady są mile widziane. Dzięki!

EDYTOWAĆ

Aby rozwinąć, gdy zdam sobie sprawę z tego, co podkreśliłem w moim pierwotnym pytaniu:

1.) Pożądane jest, aby nie musieć określać H wyraźnie w każdej klasie implementującej, ale pozwólcie, że można to wywnioskować (w witrynie wywoływania?).

2.) Chciałbym użyć HNil jako domyślnej implementacji cechy nadrzędnej, którą można opcjonalnie zastąpić w podklasach. Mój przykład prawdopodobnie powinien być:

trait Parent {
def someHList[H <: HList]: H = HNil
}

object Child extends Parent {
override def someHList[H <: HList] = 1 :: "two" :: HNill
}

Odpowiedzi:

8 dla odpowiedzi № 1

HNil obiekt jest HList. Ale to nie jest konieczne H.

definicja jak

def someHList[H <: HList]: H = HNil

należy czytać jako

dla każdego type H, podtyp HList istnieje sposób na zbudowanie jego członka i tak będzie HNil

co jest oczywiście błędne

To, co próbuję zrobić, jak czuję, to przeformułowana wersja tego

tam jest type H, podtyp HList i sposób na zbudowanie jego członka

Jeśli tak, możesz użyć takiego członka:

import shapeless._

trait Parent {
type H <: HList
def someHList: H
}

object Child1 extends Parent {
type H = HNil
def someHList: H = HNil
}

object Child2 extends Parent {
type H = Int :: String :: HNil
def someHList: H = 1 :: "two" :: HNil
}

Aktualizacja

Możesz także trochę go przeredagować, aby niektóre typy automatycznie wnioskowały

abstract class Parent[H <: HList](val someList: H)
object Child1 extends Parent(HNil: HNil)
object Child2 extends Parent(1 :: "two" :: HNil)

Możesz zauważyć, że ten typ dla HNil jest ustawiany ręcznie, ponieważ typ object HNil jest HNil.typepodtyp HNil, który może czasami prowadzić kompilator w niewłaściwy sposób


4 dla odpowiedzi nr 2

Jeśli po prostu użyj HList jako typ zwrotu wszystko działa dobrze:

trait Parent {
def someHList: HList
}

object Child1 extends Parent {
def someHList = HNil
}

object Child2 extends Parent {
def someHList = 1 :: "two" :: HNil
}

Lub w przypadku zaktualizowanej wersji pytania:

trait Parent {
def someHList: HList = HNil
}

object Child2 extends Parent {
override def someHList = 1 :: "two" :: HNil
}