通过Scala中的currying了解名称调用

时间:2013-11-24 22:09:59

标签: scala playframework currying

我正在尝试使用play框架中的默认Anorm库来理解Scala中的数据库连接。 Play有一个示例示例“计算机数据库”,其中一个函数尝试从数据库中检索计算机:

DB.withConnection { implicit connection =>
  SQL("select * from computer where id = {id}").on('id -> id).as(Computer.simple.singleOpt)
}

如果我查看 withConnection 的函数签名,那就是:

def withConnection [A] (block: (Connection) ⇒ A)(implicit app: Application): A
Execute a block of code, providing a JDBC connection. The connection and all created statements are automatically released.
**block** Code block to execute.

我的问题是如何将函数调用的每个值映射到函数定义?例如什么是A(它是整个SQL查询,但返回类型的含义是什么?)。在这种情况下,隐式应用是什么?在哪里定义?

1 个答案:

答案 0 :(得分:3)

不可否认,这个例子令人困惑,因为它结合了多种语言功能

  1. 类型参数(泛型)
  2. currying(=两个参数列表)
  3. 匿名内联函数(功能块)
  4. 隐式参数(从上下文中获取)
  5. 与往常一样,当事情开始变得复杂时,让我们一个接一个地排序

    (1)A是类型参数。在每次调用函数时,它都会被合适的类型替换。由于在参数列表和返回类型中的两个位置提到A,这意味着无论使用何种类型,传入函数块的结果类型都将与整体返回类型相同。您可以在使用该函数时明确定义A,但通常您可以将其保留,因为编译器可以推断出实际使用的类型。

    (2)currying很容易理解。这个函数只有两个参数列表。这意味着您可以分几步应用此功能。首先应用左参数列表:

    def myBlock(connection:Connection):SQL =
            SQL("select ......" .....
    
    val pf = DB.withConnection(myBlock)
    

    问题:pf是什么类型的对象? ists类型是什么? 答:它是一个函数,带一个参数,一个Application对象

    因此pf的类型将是Application => SQL,因为在函数的第一个部分应用中,我们只传递了另一个返回类型为SQL的函数,因此类型参数A被推断为{ {1}}

    (3)但是在上面的代码中,我们以传统的方式定义了函数SQL,我们明确地给它命名为“myBlock”。这不是必需的。我们可以使用块语法直接定义相同的函数。

    (4)现在是令人困惑的“神奇”部分,暗示。这是Scala的一个非常特殊的功能,编译器允许您省略某些值或参数(在我们的例子中)。您不能省略任意参数,只能省略标记为myBlock的参数。执行此操作时,编译器不会立即生成错误;而是在当前范围内查找,如果他能找到一些合适的其他具有相同名称的对象。

    实际上,这意味着,在您的示例中,必须以某种方式成为类型implicit的值“连接”,并且必须存在类型为Connection的值“应用程序”。这两个值必须在当前作用域中以某种方式显示 - 即,作为参数,作为封闭作用域中的值,或作为伴随对象中的值,或者您可能已使用import语句将它们显式地带入作用域。这种语言功能的目的只是为了节省您输入那些明显的参数(应用程序和连接9一次又一次