使用多态函数从选项中提取对象 [英] Using a polymorphic function to extract an object from Options

查看:38
本文介绍了使用多态函数从选项中提取对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

the shapeless 文档解释了如何使用多态函数来创建一个函数,将一种容器中的对象映射到另一种容器,但是当您想从容器中解包东西时怎么办?

The shapeless documentation explains how to use polymorphic functions to make a function that maps objects in one kind of container to another, but what about when you want to unpack things from their container?

我有一个 HList 选项

I have a HList of Options

val options = Some(1) :: Some("A") :: Some(3.5) :: HNil

我想要一个可以提取每个选项内容的多态函数.

I want a polymorphic function that can extract the contents of each of the Options.

// This is incorrect:
object uuu extends (Option ~> Any) {
  def apply[T](l:Option[T]):T = {
    l.get
  }
}

如果这个函数是正确的,我想要以下行为:

If this function was correct, I'd want the following behavior:

options.map(uuu) // I want: 1 :: "A" :: 3.5 :: HNil

我该如何纠正这个问题,以便我的多态函数真正起作用?

How can I correct this so that my polymorphic function actually works?

推荐答案

这里有几个问题.首先是你的 hlist 的静态类型有 Some 而不是 Option,所以 Mapper 证明你需要证明 uuu 可以映射到 options 不会被发现.解决这个问题的最好方法是定义一个智能的 Some 构造函数,它返回一个 Option:

There are a couple of problems here. The first is that the static type of your hlist has Some in it instead of Option, so the Mapper evidence that you need to prove that uuu can be mapped over options won't be found. The nicest way to fix this is to define a smart Some constructor that returns an Option:

def some[A](a: A): Option[A] = Some(a)

val options = some(1) :: some("A") :: some(3.5) :: HNil

您还可以在原始 options 中添加类型注释,或更改 uuu 以使用 Some 而不是 Option(这会更安全,但对于您的目标可能不太有用).

You could also add type annotations to your original options, or change uuu to work with Some instead of Option (which would be safer, but presumably less useful for whatever it is you're aiming to do).

现在您的代码可以编译并执行某些事情,但这仅仅是因为 Any 在 Scala 中是种类多态的这一有点奇怪的事实.一般来说,当你有 F ~>GFG 都必须是采用单个类型参数的类型构造函数——例如<代码>选项~>列表.Any 不接受类型参数,但它可以工作,因为关于 Scala 语言的这个奇怪的事实(Any,连同 Nothing>, 是种类多态的,适合任何需要类型、带一个参数的类型构造函数、带十几个参数的类型构造函数等的插槽.

Now your code compiles and does something, but only because of the somewhat bizarre fact that Any is kind-polymorphic in Scala. In general when you have F ~> G, both F and G have to be type constructors that take a single type parameter—e.g. Option ~> List. Any doesn't take a type parameter, and yet it works, because of this weird fact about the Scala language (that Any, together with Nothing, is kind-polymorphic and will fit any slot where you need a type, a type constructor with one parameter, a type constructor with a dozen parameters, etc.).

所以它编译了,但它很没用,因为它返回一个Any :: Any :: Any :: HNil.您可以通过将自然变换中的 Any 替换为 shapeless.Id 来解决此问题:

So it compiles, but it's pretty useless, since it returns an Any :: Any :: Any :: HNil. You can fix this by replacing the Any in the natural transformation with 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——也就是说,它是为您提供解包类型的标识类型构造函数.

Id is defined as type Id[+T] = T—i.e., it's the identity type constructor that gives you the unwrapped type.

这个版本既编译又返回一个有用的类型结果,但它仍然不是真正安全的,因为如果你用 None 的元素映射 hlist(在运行时),你会得到一个 NoSuchElementException.除了改变 Option ~>IdSome ~>Id,以某种方式提供默认值等,所有这些都非常显着地改变了操作的性质.

This version both compiles and gives you back a usefully-typed result, but it's still not really safe, since if you map over an hlist with elements that are None (at runtime), you'll get a NoSuchElementException. There's not really any way around this apart from changing Option ~> Id to Some ~> Id, somehow providing default values, etc., all of which change the nature of the operation pretty dramatically.

这篇关于使用多态函数从选项中提取对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆