Scala:我如何理解咖喱机制

时间:2018-08-12 22:04:04

标签: scala functional-programming

我了解咖喱函数在实际中是如何工作的。

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import ode

vx = lambda x,y: -1 - x**2 + y
vy = lambda x,y: 1 + x - y**2

y0, x0 = 0.5, 0.6

def f(x, y):
    return vy(x,y)/vx(x,y)

r = ode(f).set_integrator('vode', method='adams')
r.set_initial_value(y0, x0)

xf = 0.32
dx =-0.01

x, y = [x0,], [y0,]
while r.successful() and r.t < xf:
    x.append(r.t+dx)
    y.append(r.y[0])

#plot it
plt.figure()
plt.plot(x, y)
plt.axis('equal')
plt.show()

其中def plainSum(a: Int)(b: Int) = a + b val plusOne = plainSum(1) _ 是类型plusOne的咖喱函数,可以应用于(Int) => Int

Int

独立地,当由Chiusano和Bjarnason读本书(第2章)《 Scala中的函数式编程》 时,它证明了将两个自变量的函数plusOne(10) res0: Int = 11 引入函数的实现一个参数的形式可以通过以下方式编写:

f

参考:https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/gettingstarted/GettingStarted.scala#L157-L158

我可以理解上面的实现,但是很难将签名与def curry[A, B, C](f: (A, B) => C): A => (B => C) = a: A => b: B => f(a, b) plainSum示例相关联。

plusOne中的1似乎对应于类型参数plainSum(1) _,而函数值A似乎对应于函数签名plusOne

Scala编译器在看到语句B => C时如何应用上面的curry签名?

1 个答案:

答案 0 :(得分:2)

您正在将部分应用函数与currying混为一谈。在Scala中,它们存在一些差异:

  • 部分应用的函数传递的参数少于应用程序中提供的参数,其余参数(由占位符(_)表示)将部分应用到下一次调用。
  • 固化是指高阶函数使用N个参数的函数并将其转换为函数的单参数链。

plusOne示例自然可以通过多参数列表来立即使用,该列表多接一个参数,并返回最后一个参数。

Your mistake is that you are trying to use currying twice when this notation()() already gives you currying.  同时,您可以通过向plainSum函数添加curry签名来达到相同的效果,

def curry[A, B, C](f: (A, B) => C): A => (B => C) =
  (a: A) => (b: B) => f(a, b)

def plainSum(a: Int, b: Int) = a + b

val curriedSum = curry(plainSum)
val add2 = curriedSum(2)
add2(3)

不应将(部分应用程序和currying)两者与另一个称为部分函数的概念相混淆。

注意:红皮书fpinscala试图像在Scala库中那样在没有语法糖的情况下创建这些抽象。