模式匹配与无形的副产品 [英] Pattern matching with shapeless coproduct
问题描述
我可以对无形的副产品使用模式匹配吗?
Can I use pattern matching with shapeless coproducts?
import shapeless.{CNil, :+:}
type ListOrString = List[Int] :+: String :+: CNil
def f(a: ListOrString): Int = a match {
case 0 :: second :: Nil => second
case first :: Nil => first
case Nil => -1
case string: String => string.toInt
}
这当然行不通,因为 a
被装箱为 Coproduct
.
That of course doesn't work, since a
is boxed as a Coproduct
.
是否有其他方法可以使用副产品并保持模式匹配的能力?
Is there an alternative way to use coproducts and maintain the ability to pattern match?
推荐答案
您可以在模式匹配中使用 Inl
和 Inr
构造函数:
You can use the Inl
and Inr
constructors in the pattern match:
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
}
这种方法并不理想,因为如果您希望编译器能够判断匹配是详尽无遗的,则必须处理 CNil
情况——我们知道这种情况不可能匹配,但编译器不匹配,所以我们必须做这样的事情:
This approach isn't ideal because you have to handle the CNil
case if you want the compiler to be able to tell that the match is exhaustive—we know that it's not possible for that case to match, but the compiler doesn't, so we have to do something like this:
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")
}
我个人也发现使用 Inr
和 Inl
导航到联产品中的适当位置有点违反直觉.
I also personally just find navigating to the appropriate positions in the coproduct with Inr
and Inl
a little counterintuitive.
一般来说,最好用多态函数值折叠联积:
In general it's better to fold over the coproduct with a polymorphic function value:
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)
现在编译器将验证穷举性,而无需您处理不可能的情况.
Now the compiler will verify exhaustivity without you having to handle impossible cases.
这篇关于模式匹配与无形的副产品的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!