取决于目标类型的无形地图 HList [英] Shapeless map HList depending on target types

查看:43
本文介绍了取决于目标类型的无形地图 HList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下问题,我想将一个 HList 的项目映射到另一个 HList,但是如果目标"类型是 URL,源 HList 中的字符串应该只转换为 URL.

I have the following problem, I want to map items of an HList to another HList but Strings in the source HList should only be converted to URL if the "target" type is URL.

val name = "Stackoverflow"
val url = "https://stackoverflow.com/q"
val list = name :: url :: HNil

val mapped: String :: URL :: HNil = list.map(???)

就我的研究而言,所有的 Poly 东西只关心输入类型,而不关心输出类型.那么有没有办法归档我的目标?

As far as my research took me is that all the Poly stuff only cares about the input type but not about the output type. So are there ways to archive my goal ?

推荐答案

我不认为你会得到你想要的东西,因为 Scala 的隐式解析发生在类型推断之前(但谁知道——人们做的事情在 Scala 中一直给我惊喜).

I don't think you're going to get exactly what you want, since Scala's implicit resolution happens before type inference (but who knows—people do things that surprise me in Scala all the time).

(旁注:CanBuildFrom/breakOut 模式支持与您所要求的类似的东西,但我没有看到在这种情况下使其工作的方法,因为源类型确实限制了哪些实例可用.)

(Side note: the CanBuildFrom / breakOut pattern supports something similar to what you're asking for, but I don't see a way to make it work in this situation, since the source type does constrain what instances are available.)

不过,对于这种情况,有一种非常标准的解决方法,包括使用辅助类来近似部分应用类型参数.假设您有一个相当简单的类型类来捕获您的转换逻辑:

There is a pretty standard workaround for this kind of situation, though, involving the use of a helper class to approximate partial application of type parameters. Suppose you've got a fairly straightforward type class that captures your conversion logic:

import java.net.URL
import shapeless._

trait Convert[I <: HList, O <: HList] { def apply(i: I): O }

object Convert extends LowPriorityConvertInstances {
  implicit val convertHNil: Convert[HNil, HNil] = new Convert[HNil, HNil] {
    def apply(i: HNil): HNil = i
  }

  implicit def convertHConsURL[T <: HList, TO <: HList](implicit
    c: Convert[T, TO]
  ): Convert[String :: T, URL :: TO] = new Convert[String :: T, URL :: TO] {
    def apply(i: String :: T): URL :: TO = new URL(i.head) :: c(i.tail)
  }
}

sealed class LowPriorityConvertInstances {
  implicit def convertHCons[H, T <: HList, TO <: HList](implicit
    c: Convert[T, TO]
  ): Convert[H :: T, H :: TO] = new Convert[H :: T, H :: TO] {
    def apply(i: H :: T): H :: TO = i.head :: c(i.tail)
  }
}

现在你可以尝试这样的事情:

Now you might try something like this:

def convert[I <: HList, O <: HList](i: I)(implicit c: Convert[I, O]): O = c(i)

但是这里有两个问题.第一个是如果你让类型参数被推断出来,你总是会得到一个将每个字符串转换为 URL 的转换.您可以通过显式提供这两个类型参数来覆盖此行为,但是.

But there are two problems here. The first is that if you let the type parameters be inferred, you'll always get a conversion that turns every string into a URL. You can override this behavior by explicitly providing both type parameters, but ugh.

我们可以(有点)使用辅助类来改善这种情况:

We can (kind of) improve this situation with a helper class:

class PartiallyAppliedConvert[O <: HList] {
  def apply[I <: HList](i: I)(implicit c: Convert[I, O]): O = c(i)
}

def convert[O <: HList]: PartiallyAppliedConvert[O] =
  new PartiallyAppliedConvert[O]

现在您可以编写以下内容:

Now you can write the following:

scala> val mapped = convert[String :: URL :: HNil](list)
mapped: shapeless.::[String,shapeless.::[java.net.URL,shapeless.HNil]] = Stackoverflow :: https://stackoverflow.com/q :: HNil

这不是您所要求的,但非常接近,因为我们必须明确指定的唯一类型是所需的目标类型.

It's not exactly what you asked for, but it's pretty close, in that the only type we have to specify explicitly is the desired target type.

这篇关于取决于目标类型的无形地图 HList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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