非形状文档解释了如何使用多态函数来生成将一种容器中的对象映射到另一种容器中的函数,但是当您想从它们的容器中解压东西时呢?
我有一个HList的选项
val options = Some(1) :: Some("A") :: Some(3.5) :: HNil
我想要一个多态函数,可以提取每个选项的内容。
// This is incorrect:
object uuu extends (Option ~> Any) {
def apply[T](l:Option[T]):T = {
l.get
}
}
如果这个函数是正确的,我想要下面的行为:
options.map(uuu) // I want: 1 :: "A" :: 3.5 :: HNil
我如何纠正这一点,使我的多态函数实际工作?
发布于 2016-09-22 10:48:00
这里有几个问题。首先,您的hlist的静态类型中有Some
而不是Option
,因此找不到您需要证明uuu
可以映射到options
之上的Mapper
证据。解决这个问题的最好方法是定义一个返回一个Some
的智能Option
构造函数。
def some[A](a: A): Option[A] = Some(a)
val options = some(1) :: some("A") :: some(3.5) :: HNil
您还可以将类型注释添加到原始options
中,或者将uuu
更改为使用Some
而不是Option
(这将更安全,但可能对您想做的任何事情都不太有用)。
现在,您的代码编译并执行了一些操作,但这仅仅是因为Any
在Scala中是多态的,这一事实有点奇怪。通常,当您有F ~> G
时,F
和G
都必须是接受单个类型参数的类型构造函数,例如Option ~> List
。Any
不接受类型参数,但是它可以工作,因为Scala语言的这个奇怪的事实( Any
和Nothing
都是多态的,并且适合您需要一个类型、一个带一个参数的类型构造函数、一个带十几个参数的类型构造函数等等)。
所以它编译了,但是它非常无用,因为它返回一个Any :: Any :: Any :: HNil
。您可以通过将自然转换中的Any
替换为shapeless.Id
来修复这个问题。
import shapeless._, shapeless.poly.~>
def some[A](a: A): Option[A] = Some(a)
val options = some(1) :: some("A") :: some(3.5) :: HNil
object uuu extends (Option ~> Id) {
def apply[T](l: Option[T]): T = l.get
}
options.map(uuu)
Id
被定义为type Id[+T] = T
-i.e.,它是身份类型构造函数,为您提供了未包装的类型。
这个版本同时编译并返回一个有用的输入结果,但它仍然不太安全,因为如果您在hlist
上映射None
元素(在运行时),您将得到一个NoSuchElementException
。除了将Option ~> Id
更改为Some ~> Id
、以某种方式提供默认值等之外,没有任何方法可以解决这些问题,所有这些都极大地改变了操作的性质。
https://stackoverflow.com/questions/39628022
复制相似问题