Można użyć Inl
i Inr
konstruktorów w meczu Wzór:
import shapeless.{ CNil, Inl, Inr, :+: }
type ListOrString = List[Int] :+: String :+: CNil
def f(a: ListOrString): Int = a match {
case Inl(0 :: second :: Nil) => second
case Inl(first :: Nil) => first
case Inl(Nil) => -1
case Inr(Inl(string)) => string.toInt
}
Podejście to nie jest idealne, bo trzeba sobie sprawę CNil
jeśli chcesz kompilator, aby móc powiedzieć, że mecz jest wyczerpująca, wiemy, że to nie jest możliwe, że sprawa się zgadzają, ale kompilator nie robi, więc musimy zrobić coś takiego:
def f(a: ListOrString): Int = a match {
case Inl(0 :: second :: Nil) => second
case Inl(first :: Nil) => first
case Inl(Nil) => -1
case Inl(other) => other.sum
case Inr(Inl(string)) => string.toInt
case Inr(Inr(_)) => sys.error("Impossible")
}
ja również osobiście po prostu znaleźć, przechodząc do APPro Właściwe pozycje w współprodukcie z Inr
i Inl
są trochę sprzeczne z intuicją.
Generalnie lepiej spasować nad koproduktu z polimorficznych wartości funkcji:
object losToInt extends shapeless.Poly1 {
implicit val atList: Case.Aux[List[Int], Int] = at {
case 0 :: second :: Nil => second
case first :: Nil => first
case Nil => -1
case other => other.sum
}
implicit val atString: Case.Aux[String, Int] = at(_.toInt)
}
def f(a: ListOrString): Int = a.fold(losToInt)
Teraz kompilator będzie weryfikacji kompletności bez konieczności obsługi niemożliwych przypadki.
ja usiłuję zrozumieć co 'przypadek INL (0 :: sekund :: Nil) => second' rzeczywistości. Jeśli jest to współprodukt, na pewno nie może to być zarówno "0", jak i "sekunda", więc kiedy to się zgadza? – fommil
@fommil Część wewnątrz 'Inl' pasuje do zwykłej starej listy, więc będzie pasować za każdym razem, gdy mamy' Coproduct [ListOrString] (xs) 'gdzie' xs' ma dokładnie dwa elementy i '0' jest pierwszy. –
oh Widzę, dzięki – fommil