scala - 在 Hlist of Options 中无形查找 Some between Nones 的实例

标签 scala shapeless hlist

假设我有以下类层次结构:

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 上进行。如果您的值静态类型为 SomeNone , 以便编译器可以做任何事情。

如果您有关于类型给出的附加信息(这里,一个选项可以是 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]在范围内,这意味着 LHListNone.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/

相关文章:

json - 使用Argonaut创建通用JSON转换器

scala - 在 EMR 上烫伤 : Hadoop job fails with NoSuchMethodError: scala. Predef$.ArrowAssoc(Ljava/lang/Object;)Ljava/lang/Object;

scala - 类型同义词中的类型大小写

scala - Shapeless:检查多态函数的类型约束

haskell - Haskell 中的无限(最终周期性)HList

java - 在 Maven 中指定源和测试文件夹的 IntelliJ 包前缀

scala - 无法在scala中的构造函数之前调用实例方法

Scala 无形 : derive type from Mapper

scala - 带参数的无形 HList 多态映射

scala - 查找 Shapeless HList 的类型类实例