È possibile utilizzare i Inl
e Inr
costruttori nel match modello:
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
}
Questo approccio non è l'ideale perché si deve gestire il caso CNil
se si desidera che il compilatore di essere in grado di dire che la partita è esaustivo, sappiamo che non è possibile per quel caso per abbinare, ma il compilatore non lo fa, quindi dobbiamo fare qualcosa di simile:
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")
}
ho anche personalmente appena trovato la navigazione verso l'appro posizioni corte nel coprodotto con Inr
e Inl
un po 'controintuitivo.
In generale è meglio ripiegare il coprodotto con un valore della funzione polimorfica:
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)
Ora il compilatore verificherà esaustività senza dover per gestire i casi impossibili.
fonte
2015-12-05 19:05:22
faccio fatica a capire che cosa 'caso Inl (0 :: :: secondo Nil) => secondo' in realtà è. Se questo è un coprodotto, sicuramente non può essere sia "0" che "secondo", quindi quando si fa questo match? – fommil
@fommil La parte all'interno di 'Inl' corrisponde a una semplice vecchia lista, quindi corrisponderà ogni volta che abbiamo un' Coproduct [ListOrString] (xs) 'dove' xs' ha esattamente due elementi e '0' è il primo. –
oh capisco, grazie – fommil