gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 13:49:54 25 4
gpt4 key购买 nike

我正在尝试使用 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, 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
}

问题是我不知道是什么 foldLeft在这个例子中确实返回。

我希望它返回 (String, String, 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 ,因为编译器静态地知道 Afoo参数是 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.AString .

    这是一个更复杂的例子:
    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
    }
    }

    现在我们知道不可能创建 Baz不同类型的 AB ,但编译器没有,所以它不会接受以下内容:
    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, 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

    (您也可以在 LeftFolder 的类型中使用类型成员语法与普通的旧 l 一起使用,但这会使此签名更加困惑。)
    columns.foldLeft(...)(...)部分仍然返回 l.Out ,但现在编译器静态地知道这是一个字符串元组。

    关于scala - HList#foldLeft() 返回什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26608766/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com