加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – HList#foldLeft()返回什么?

发布时间:2020-12-16 18:58:16 所属栏目:安全 来源:网络整理
导读:我正在尝试使用来自Shapeless的HList. 这是我的第一次尝试: trait Column[T] { val name: String}case class CV[T](col: Column[T],value: T)object CV { object columnCombinator extends Poly2 { implicit def algo[A] = at[(String,String,String),CV[A]
我正在尝试使用来自Shapeless的HList.

这是我的第一次尝试:

trait Column[T] {
     val name: String
}

case class CV[T](col: Column[T],value: T)

object CV {
    object columnCombinator extends Poly2 {
        implicit def algo[A] = at[(String,String,String),CV[A]] { case ((suffix,separator,sql),cv) ?
            (suffix,if (sql == "") cv.col.name+suffix else sql+separator+cv.col.name+suffix)
        }
    }

    def combine[A <: HList](columns: A,suffix: String,separator: String = " and ")
                           (implicit l: LeftFolder[A,(String,columnCombinator.type]): String =
        columns.foldLeft((suffix,""))(columnCombinator)._3
}

问题是我不知道foldLeft在这个例子中返回了什么.

我希望它返回(String,但编译器告诉我返回l.Out.什么是l.Out?

猜测源代码有点复杂.

网上没有太多关于此的信息.

我咨询过的一些信息:

> Shapeless Tests
> Shapeless documentation

解决方法

您的combine方法返回所谓的 “dependent method type”,这意味着它的返回类型取决于它的一个参数 – 在这种情况下是一个路径依赖类型,在其路径中包含l.

在许多情况下,编译器将静态地知道有关依赖返回类型的内容,但在您的示例中却没有.我将尝试在一秒钟内解释原因,但首先考虑以下更简单的例子:

scala> trait Foo { type A; def a: A }
defined trait Foo

scala> def fooA(foo: Foo): foo.A = foo.a
fooA: (foo: Foo)foo.A

scala> fooA(new Foo { type A = String; def a = "I'm a StringFoo" })
res0: String = I'm a StringFoo

这里res0的推断类型是String,因为编译器静态地知道foo参数的A是String.但是,我们不能写下列任何一种:

scala> def fooA(foo: Foo): String = foo.a
<console>:12: error: type mismatch;
 found   : foo.A
 required: String
       def fooA(foo: Foo): String = foo.a
                                        ^

scala> def fooA(foo: Foo) = foo.a.substring
<console>:12: error: value substring is not a member of foo.A
       def fooA(foo: Foo) = foo.a.substring
                                  ^

因为这里编译器不静态地知道foo.A是String.

这是一个更复杂的例子:

sealed trait Baz {
  type A
  type B

  def b: B
}

object Baz {
  def makeBaz[T](t: T): Baz { type A = T; type B = T } = new Baz {
    type A = T
    type B = T

    def b = t
  }
}

现在我们知道不可能为A和B创建一个具有不同类型的Baz,但是编译器没有,所以它不会接受以下内容:

scala> def bazB(baz: Baz { type A = String }): String = baz.b
<console>:13: error: type mismatch;
 found   : baz.B
 required: String
       def bazB(baz: Baz { type A = String }): String = baz.b
                                                            ^

这正是你所看到的.如果我们查看shapeless.ops.hlist中的代码,我们可以说服自己,我们在这里创建的LeftFolder将具有相同的In和Out类型,但编译器不能(或者更确切地说不是 – 它是一个设计决定)在这个推理中跟随我们,这意味着它不会让我们对待l.Out作为没有更多证据的元组.

幸运的是,由于LeftFolder.Aux,它只是LeftFolder的别名,Out类型成员作为第四个类型参数,因此很容易提供证据:

def combine[A <: HList](columns: A,separator: String = " and ")(
  implicit l: LeftFolder.Aux[
    A,columnCombinator.type,String)
  ]
): String =
    columns.foldLeft((suffix,""))(columnCombinator)._3

(您也可以在l类型中使用类型成员语法和普通的旧LeftFolder,但这会使这个签名更加混乱.)

columns.foldLeft(…)(…)部分仍然返回l.Out,但现在编译器静态地知道这是一个字符串元组.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读