【问题标题】:Understanding function in scala理解scala中的函数
【发布时间】:2016-11-06 20:54:30
【问题描述】:

这个问题严格来说是关于 Scala 语法的,尽管它包含一些来自 akka 的代码(例如)。

我对 Scala 还是很陌生。深入研究 akka 的源代码,我想出了以下非常奇怪的方法:

def transform[C]
 (f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] =
Unmarshaller.withMaterializer { implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) }

其中Unmarshaller.withMaterializer定义为

  def withMaterializer[A, B](f: ExecutionContext ⇒ Materializer => A ⇒ Future[B]): Unmarshaller[A, B]

这里发生了什么?什么是可怕的功能f: ExecutionContext => Materializer => Future[B] => Future[C]。而我觉得更奇怪的是implicits:implicit ec => implicit mat => a => f(ec)(mat)(this(a))的序列虽然withMaterializer根本没有隐式参数。

这些序列中的隐含是什么意思?

【问题讨论】:

    标签: scala function


    【解决方案1】:

    f: ExecutionContext => Materializer => Future[B] => Future[C] 只不过是一个 curried 函数,所以你可以像 f(ec)(mat)(this(a)) 那样使用多个参数列表来调用它(好吧,从技术上讲,参数列表与 def f(...)(...) 不属于同一个函数,但这些都是细节) .也就是说f可以写成:

    f: ExecutionContext => { Materializer => { Future[B] => Future[C] } }`
    

    (返回一个函数的函数,它返回另一个函数)

    现在,如果您查看f(ec)(mat)(this(a)),就会看到一个调用this(a),它在transform 上方定义:

    def apply(value: A)(implicit ec: ExecutionContext, materializer: Materializer): Future[B]
    

    this(a) 只是对this.apply(a) 的调用)。现在apply 有两个隐式参数,即ec: ExecutionContextmaterializer:Materializer,所以像this(a) 这样调用它需要两个隐式值。这正是定义implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) 的含义。它将ecmat 声明为所有嵌套函数体的隐含,因此this(a) 可以选择它们。另一种可能是这样写:

    ec ⇒ mat ⇒ a ⇒ f(ec)(mat)(this(a)(ec, mat))
    

    【讨论】:

      【解决方案2】:

      这是一个带有柯里化和隐式参数的 lambda(它们应该在声明的范围内)。

      “可怕”的函数类型语法是currying:一个参数的函数,它接受ExecutionContext 并返回一个参数的另一个函数,该参数接受Materializer 并返回另一个函数,等等。另一件事是implicit arguments

      这是一个类似构造的更简单示例:

      implicit val implicitInt: Int = 5
      implicit val implicitString: String = "0"
      
      val f: Int => String => String = {
        implicit a => {
          implicit b => {
            a.toString + b
          }
        }
      }
      

      这里的f 是一个柯里化函数,它接受Int 并返回一个接受String 并返回String 的函数。函数值声明的一般语法是val f = { argument => ... },因此如果您将此参数设为隐式,则意味着在作用域中必须有一个此类型的实例,它将作为 default 值工作。您仍然可以将f 应用于某些参数:f(1)(""),因为它仍然是一个函数。

      您可以通过为每个步骤定义嵌套函数来更详细地重写您询问的代码:

      def transform[C](f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = {
      
        def getExecutionContext(implicit ec: ExecutionContext): Materializer => (A => Future[B]) = {
      
          def getMaterializer(implicit mat: Materializer): A => Future[B] = {
      
            def applyF(a: A): Future[B] = f(ec)(mat)(this(a))
            applyF // : A => Future[B]
          }
      
          getMaterializer // : Materializer => (A => Future[B])
        }
      
        Unmarshaller.withMaterializer(
          getExecutionContext // : ExecutionContext => (Materializer => (A => Future[B]))
        )
      }
      

      【讨论】:

      • 我认为你不能在没有参数的情况下调用你的f 来利用隐式值。它仅适用于方法。函数字面量中的implicit 表示参数隐含在函数体内。
      • 你是对的。 f 不能用作具有默认参数的方法。我只是试图用一个更简单的例子来说明这个结构,但把它断章取义了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 2017-03-28
      相关资源
      最近更新 更多