假设我有以下类层次结构:
sealed trait Animal
case class Cat(isFriendly: Boolean) extends Animal
case class Dog(color: String) extends Animal
case class Fish(isFreshWater: Boolean) extends Animal
现在我有一个类型的实例
Option[Cat] :: Option[Dog] :: Option[Fish] :: HNil
但是对实例有限制。它只能是以下形式之一
Some(Cat(???)) :: None :: None :: HNil
或者
None :: Some(Dog(???)) :: None :: HNil
或者
None :: None :: Some(Fish(???)) :: HNil
首先,请原谅任何不一致的地方——这是我试图解决的一个更大问题的一部分,但还没有很好地表达出来
二、
???
只是我为真实实例设计的占位符,例如:None :: Some(Dog(brown)) :: None :: HNil
事情是,我宁愿 新 到无形,我不完全知道
???
的值是否有所作为。继续问题
有没有办法“迭代” HList 并提取
Some
?我了解,一般来说,不可能如以下两个问题所示。但我想知道添加我上面设置的限制是否会有所作为
https://stackoverflow.com/a/28598157/101715
https://stackoverflow.com/a/29572541/101715
最佳答案
正如您提供的链接中所解释的,这样的操作只能在 HList
上进行。如果您的值静态类型为 Some
和 None
, 以便编译器可以做任何事情。
如果您有关于类型给出的附加信息(这里,一个选项可以是 Some
的事实),这意味着您使用了错误的类型,因为类型是您对值的信息编译时间。在这种情况下,您应该使用的类型是 Coproduct
:
type AnimalCoproduct = Cat :+: Dog :+: Fish :+: CNil
val dog = Coproduct[AnimalCoproduct](Dog("brown"))
现在,回到你的问题,假设你知道哪些是
None
哪些是 Some
在编译时。首先,您需要检查哪个
HList
具有它们是 None
列表的属性.trait IsNoneList[L <: HList]
object IsNoneList {
//all values in an HNil are None, since there aren't any
implicit val hnil: IsNoneList[HNil] = new IsNoneList[HNil] {}
//if all the values in the tail are None, and the head is None, then all the values are None
implicit def hcons[T <: HList: IsNoneList]: IsNoneList[None.type :: T] = new IsNoneList[None.type :: T] {}
}
所以现在,如果有
implicit IsNoneList[L]
在范围内,这意味着 L
是 HList
的 None.type
.让我们对我们正在寻找的属性做同样的事情:trait IsOneSomeHList[L <: HList] {
type OneSome
def get(l: L): OneSome
}
object IsOneSomeHList {
type Aux[L <: HList, O] = IsOneSomeHList[L] { type OneSome = O }
def apply[L <: HList](implicit L: IsOneSomeHList[L]) = L
// if the tail is full of None, and the head is a Some, then the property is true
implicit def someHead[A, T <: HList: IsNoneList]: Aux[Some[A] :: T, A] = new IsOneSomeHList[Some[A] :: T] {
type OneSome = A
def get(l: Some[A] :: T) = l.head.get
}
//if the head is None, and the tail has the property, then the HCons also has the property, with the same extraction function
implicit def noneHead[T <: HList](implicit T: IsOneSomeHList[T]): Aux[None.type :: T, T.OneSome] = new IsOneSomeHList[None.type :: T] {
type OneSome = T.OneSome
override def get(l: ::[None.type, T]): T.OneSome = T.get(l.tail)
}
}
请注意,如果我们有
implicit IsOneSomeHList[L]
在范围内,我们知道 L
有我们想要的属性,但是我们也可以使用这个隐式来获取唯一的Some
的类型和值在列表中。编辑
我们举个例子:
val cat = Some(Cat(isFriendly = true)) :: None :: None :: HNil
IsOneSomeHList[Some[Cat] :: None.type :: None.type :: HNil].get(cat) == Cat(true)
关于scala - 在 Hlist of Options 中无形查找 Some between Nones 的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44382672/