"int - > int - > int"这在F#中意味着什么?

ali*_*62b 14 f# functional-programming currying

我想知道这对F#意味着什么.
"一个取整数的函数,
它返回一个取整数并返回一个整数的函数."

但我对此并不了解.
有人能解释清楚这个吗?

[更新]:

> let f1 x y = x+y ;;

 val f1 : int -> int -> int
Run Code Online (Sandbox Code Playgroud)

这是什么意思 ?

Bru*_*eis 57

F#类型

让我们从头开始.

F#使用冒号(:)表示法来指示事物的类型.假设你定义了一个类型的值int:

let myNumber = 5
Run Code Online (Sandbox Code Playgroud)

F#Interactive会理解这myNumber是一个整数,并会通过以下方式告诉你:

myNumber : int
Run Code Online (Sandbox Code Playgroud)

读作的是

myNumber 是类型的 int

F#功能类型

到现在为止还挺好.让我们介绍一些其他功能类型.功能性类型仅仅是一个函数的类型.F#用于->表示功能类型.这个箭头象征着在左手边写的东西被转换成写在右手边的东西.

让我们考虑一个简单的函数,它接受一个参数并将其转换为一个输出.这种功能的一个例子是:

isEven : int -> bool
Run Code Online (Sandbox Code Playgroud)

这将介绍函数的名称(在左侧:)及其类型.这行可以用英文阅读:

isEven是一个int将函数转换为a 的类型函数bool.

请注意,要正确解释所说的内容,您应该在"类型"部分之后进行短暂停顿,然后立即读取句子的其余部分,而不会暂停.

在F#中,函数是值

在F#中,函数(几乎)不比普通类型更特殊.它们是你可以传递给函数的东西,从函数返回,就像bool,int或字符串一样.

所以如果你有:

myNumber : int
isEven : int -> bool
Run Code Online (Sandbox Code Playgroud)

您应该考虑int和int -> bool作为同一类型的两个实体:类型.这里,myNumber是类型的值int,并且isEven是类型的值int -> bool(这是我想,当我谈论的象征短暂停顿以上).

功能应用

包含的类型的值->恰好也称为函数,并具有特殊功能:您可以将函数应用于值.所以,例如,

isEven myNumber
Run Code Online (Sandbox Code Playgroud)

意味着您正在将所调用的函数isEven应用于该值myNumber.正如您所期望的那样,通过检查类型isEven,它将返回一个布尔值.如果你已经正确实施isEven,它显然会返回false.

返回函数类型值的函数

让我们定义一个泛型函数来确定一个整数是其他整数的倍数.我们可以想象我们的函数的类型将是(括号在这里是为了帮助你理解,它们可能存在也可能不存在,它们具有特殊含义):

isMultipleOf : int -> (int -> bool)
Run Code Online (Sandbox Code Playgroud)

你可以猜到,这被解读为:

isMultipleOf是一种类型(PAUSE)函数,它将转换int为(PAUSE)函数转换int为a bool.

(此处(PAUSE)表示大声朗读时的暂停).

我们稍后会定义这个函数.在此之前,让我们看看我们如何使用它:

let isEven = isMultipleOf 2
Run Code Online (Sandbox Code Playgroud)

F#interactive会回答:

isEven : int -> bool
Run Code Online (Sandbox Code Playgroud)

读作的是

isEven 是类型的 int -> bool

这里isEven有类型int -> bool,因为我们刚刚给出了值2(int)isMultipleOf,正如我们已经看到的那样,它转换int成了一个int -> bool.

我们可以将此函数isMultipleOf视为一种函数创建者.

的定义 isMultipleOf

所以现在我们来定义这个神秘的函数创建函数.

let isMultipleOf n x =
    (x % n) = 0
Run Code Online (Sandbox Code Playgroud)

好吗,对吧?

如果您在F#Interactive中输入此内容,它将回答:

isMultipleOf : int -> int -> bool
Run Code Online (Sandbox Code Playgroud)

括号在哪里?

请注意,没有括号.这对你来说并不是特别重要.请记住,箭头是正确的关联.也就是说,如果你有

a -> b -> c
Run Code Online (Sandbox Code Playgroud)

你应该把它解释为

a -> (b -> c)
Run Code Online (Sandbox Code Playgroud)

在右侧的右结合意味着你应该解释为,如果有各地最右边括号操作.所以:

a -> b -> c -> d
Run Code Online (Sandbox Code Playgroud)

应该被解释为

a -> (b -> (c -> d))
Run Code Online (Sandbox Code Playgroud)

用法 isMultipleOf

所以,正如您所见,我们可以isMultipleOf用来创建新功能:

let isEven = isMultipleOf 2
let isOdd = not << isEven
let isMultipleOfThree = isMultipleOf 3
let endsWithZero = isMultipleOf 10
Run Code Online (Sandbox Code Playgroud)

F#Interactive会回复:

isEven : int -> bool
isOdd : int -> bool
isMultipleOfThree : int -> bool
endsWithZero : int -> bool
Run Code Online (Sandbox Code Playgroud)

但你可以用不同的方式.如果您不想(或需要)创建新函数,可以按如下方式使用它:

isMultipleOf 10 150
Run Code Online (Sandbox Code Playgroud)

这将返回true,因为150是10的倍数.这与创建函数endsWithZero然后将其应用于值150 完全相同.

实际上,函数应用程序是左关联的,这意味着上面的行应解释为:

(isMultipleOf 10) 150
Run Code Online (Sandbox Code Playgroud)

也就是说,将括号括在最左边的函数应用程序周围.

现在,如果你能理解这一切,你的例子(这是规范的CreateAdder)应该是微不足道的!

前段时间有人问这个问题涉及完全相同的概念,但是在Javascript中.在我的回答中,我给出了两个规范的例子(CreateAdder,CreateMultiplier)inf Javascript,它们对返回函数更加明确.

我希望这有帮助.

  • 这是一个非常有用,深入的答案! (5认同)
  • 你在这里写章的人当完整的书出来时;) (4认同)

Jon*_*eet 9

这个典型的例子可能是"加法器创建者" - 一个函数,给定一个数字(例如3)返回另一个函数,该函数取一个整数并将第一个数字加到它上面.

因此,例如,在伪代码中

x = CreateAdder(3)
x(5) // returns 8
x(10) // returns 13
CreateAdder(20)(30) // returns 50
Run Code Online (Sandbox Code Playgroud)

我不太习惯在F#中试着写它而不检查它,但C#会是这样的:

public static Func<int, int> CreateAdder(int amountToAdd)
{
    return x => x + amountToAdd;
}
Run Code Online (Sandbox Code Playgroud)

这有帮助吗?

编辑:正如布鲁诺所说,你在问题中给出的例子就是我给出C#代码的例子,所以上面的伪代码将成为:

let x = f1 3
x 5 // Result: 8
x 10 // Result: 13
f1 20 30 // Result: 50
Run Code Online (Sandbox Code Playgroud)

  • @ ali62b:基本上是的.如果您将函数视为值(函数式语言中的基本元素),这是有道理的.假设带有一个参数的`f1`函数的返回值只是另一个函数(C#服务方式中的委托). (2认同)
  • 当然,在像F#这样的语言中,我们可以简单地将`create_adder`定义为`create_adder =(+)`. (2认同)

Meh*_*ari 7

它是一个函数,它接受一个整数并返回一个取整数并返回一个整数的函数.

这在功能上等效于一个带有两个整数并返回整数的函数.这种处理带有多个参数的函数的方法在函数式语言中很常见,并且可以很容易地在函数上部分应用函数.

例如,假设有一个add函数,它接受两个整数并将它们加在一起:

let add x y = x + y
Run Code Online (Sandbox Code Playgroud)

您有一个列表,并且您想要为每个项目添加10.您将add函数部分应用于该值10.它会将其中一个参数绑定到10并使另一个参数保持未绑定状态.

let list = [1;2;3;4]
let listPlusTen = List.map (add 10)
Run Code Online (Sandbox Code Playgroud)

这个技巧使编写功能非常容易,并使它们非常可重用.如您所见,您不需要编写另一个向列表项添加10以将其传递给的函数map.你刚刚重用了这个add功能.


3le*_*gos 6

您通常将此解释为一个函数,它接受两个整数并返回一个整数.你应该读一下关于currying的事.