这里有几个问题。首先是你的 hlist 的静态类型有Some
在其中而不是Option
, 所以Mapper
你需要证明的证据uuu
可以映射到options
不会被发现。解决这个问题最好的方法是定义一个智能的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
, both F
and 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
—即,它是为您提供未包装类型的标识类型构造函数。
这个版本既编译又给你返回一个有用的类型结果,但它仍然不是真正安全,因为如果你映射一个hlist
的元素是None
(在运行时),你会得到一个NoSuchElementException
。除了改变之外,没有什么办法可以解决这个问题Option ~> Id
to Some ~> Id
,以某种方式提供默认值等,所有这些都极大地改变了操作的性质。