HList#foldLeft() 返回什么? [英] What does HList#foldLeft() return?

查看:31
本文介绍了HList#foldLeft() 返回什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Shapeless 中的 HList.

这是我第一次尝试:

特质列[T] {val 名称:字符串}case class CV[T](col: Column[T], value: T)对象简历{对象 columnCombinator 扩展 Poly2 {隐式 def 算法[A] = at[(String, String, String), CV[A]] { case ((suffix, separator, sql), cv) ⇒(后缀, 分隔符, if (sql == "") cv.col.name+suffix else sql+separator+cv.col.name+suffix)}}def combine[A <: HList](columns: A, suffix: String, separator: String = " and ")(隐式 l: LeftFolder[A, (String, String, String), columnCombinator.type]): String =columns.foldLeft((suffix, separator, ""))(columnCombinator)._3}

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

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

源代码有点难猜.

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

我查阅过的一些信息:

解决方案

您的 combine 方法返回所谓的 依赖方法类型",这只是意味着它的返回类型依赖于它的一个参数——在这种情况下作为路径依赖类型,在其路径中包含 l.

在许多情况下,编译器会静态地了解依赖返回类型,但在您的示例中它不知道.稍后我将尝试解释原因,但首先考虑以下更简单的示例:

scala>特质 Foo { 类型 A;定义一个:A }定义特征 Foo标度>def fooA(foo: Foo): foo.A = foo.afooA: (foo: Foo)foo.A标度>fooA(new Foo { type A = String; def a = "I'm a StringFoo" })res0: String = 我是一个 StringFoo

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

scala>def fooA(foo: Foo): String = foo.a<console>:12: 错误:类型不匹配;发现:foo.A要求:字符串def fooA(foo: Foo): String = foo.a^标度>def fooA(foo: Foo) = foo.a.substring<console>:12: 错误:值子串不是 foo.A 的成员def fooA(foo: Foo) = foo.a.substring^

因为这里编译器不会静态地知道 foo.AString.

这是一个更复杂的例子:

密封特性 Baz {A型B型定义 b: B}对象巴兹{def makeBaz[T](t: T): Baz { type A = T;类型 B = T } = 新巴兹 {类型 A = T类型 B = T定义 b = t}}

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

scala>def bazB(baz: Baz { type A = String }): String = baz.b<console>:13: 错误:类型不匹配;发现:baz.B要求:字符串def bazB(baz: Baz { type A = String }): String = baz.b^

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

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

def combine[A <: HList](columns: A, suffix: String, separator: String = " and ")(隐式 l:LeftFolder.Aux[一种,(字符串,字符串,字符串),columnCombinator.type,(字符串,字符串,字符串)]): 字符串 =columns.foldLeft((suffix, separator, ""))(columnCombinator)._3

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

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

I'm trying to play with HList's from Shapeless.

This is my first try:

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, separator, 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, String, String), columnCombinator.type]): String =
        columns.foldLeft((suffix, separator, ""))(columnCombinator)._3
}

The problem is I don't know what foldLeft does return in this example.

I expect it to return (String, String, String), but the compiler tells me that returns l.Out. What is l.Out?

The source code is a little complicated to guess it.

There isn't much information in the web about this.

Some information I've consulted:

解决方案

Your combine method returns what's called a "dependent method type", which just means that its return type depends on one of its arguments—in this case as a path-dependent type that includes l in its path.

In many cases the compiler will statically know something about the dependent return type, but in your example it doesn't. I'll try to explain why in a second, but first consider the following simpler example:

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

Here the inferred type of res0 is String, since the compiler statically knows that the A of the foo argument is String. We can't write either of the following, though:

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
                                  ^

Because here the compiler doesn't statically know that foo.A is String.

Here's a more complex example:

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
  }
}

Now we know that it's not possible to create a Baz with different types for A and B, but the compiler doesn't, so it won't accept the following:

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
                                                            ^

This is exactly what you're seeing. If we look at the code in shapeless.ops.hlist, we can convince ourselves that the LeftFolder we're creating here will have the same type for In and Out, but the compiler can't (or rather won't—it's a design decision) follow us in this reasoning, which means it won't let us treat l.Out as a tuple without more evidence.

Fortunately that evidence is pretty easy to provide thanks to LeftFolder.Aux, which is just an alias for LeftFolder with the Out type member as a fourth type parameter:

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

(You could also use the type member syntax with plain old LeftFolder in l's type, but that would make this signature even messier.)

The columns.foldLeft(...)(...) part still returns l.Out, but now the compiler statically knows that that's a tuple of strings.

这篇关于HList#foldLeft() 返回什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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