“int->”整数->整数”这在 F# 中意味着什么?

发布于 2024-08-20 00:26:44 字数 229 浏览 7 评论 0 原文

我想知道这在 F# 中意味着什么。
“一个接受整数的函数,
它返回一个接受整数并返回整数的函数。”

但我不太明白这一点。
有谁能解释得这么清楚吗?

[更新]:

> let f1 x y = x+y ;;

 val f1 : int -> int -> int

这是什么意思?

I wonder what this means in F#.
“a function taking an integer,
which returns a function which takes an integer and returns an integer.”

But I don't understand this well.
Can anyone explain this so clear ?

[Update]:

> let f1 x y = x+y ;;

 val f1 : int -> int -> int

What this mean ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

枫林﹌晚霞¤ 2024-08-27 00:26:44

F# 类型

让我们从头开始。

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

let myNumber = 5

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

myNumber : int

读作

myNumber 的类型为 int

F# 函数类型

到目前为止一切顺利。让我们介绍一些其他东西,函数类型。函数类型就是函数的类型。 F# 使用 -> 来表示函数类型。这个箭头象征着左侧所写的内容被转换为右侧所写的内容。

让我们考虑一个简单的函数,它接受一个参数并将其转换为一个输出。此类函数的示例如下:

isEven : int -> bool

这引入了函数的名称(位于 : 的左侧)及其类型。这行英文可以读作:

isEven 是将 int 转换为 bool 的函数类型。

请注意,为了正确解释所说的内容,您应该在“属于类型”部分之后短暂停顿,然后立即阅读句子的其余部分,不要停顿。

在 F# 中,函数是值

在 F# 中,函数(几乎)并不比普通类型更特殊。它们是可以传递给函数、从函数返回的东西,就像布尔值、整数或字符串一样。

因此,如果您有:

myNumber : int
isEven : int -> bool

您应该考虑 intint ->; bool 作为同一种类的两个实体:类型。这里,myNumber是一个int类型的值,isEven是一个int -> type的值。 bool (这就是我在谈论上面的短暂停顿时想要表达的意思)。

函数应用

包含 -> 的类型的值也称为函数,并且具有特殊的能力:您可以将函数应用于价值。例如,这

isEven myNumber

意味着您正在将名为 isEven 的函数应用于值 myNumber。正如您通过检查 isEven 的类型所期望的,它将返回一个布尔值。如果您正确实现了 isEven,它显然会返回 false

返回函数类型值的函数

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

isMultipleOf : int -> (int -> bool)

正如您可以猜到的,这被读作:

isMultipleOf 是 (PAUSE) 类型函数,可将 int 转换为 (PAUSE) 函数,将 int 转换为 布尔

(这里的(PAUSE)表示大声朗读时的暂停)。

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

let isEven = isMultipleOf 2

F# 交互式会回答:

isEven : int -> bool

读作

isEven 的类型为 int ->布尔

这里,isEven 的类型为 int ->; bool,因为我们刚刚将值 2 (int) 赋予 isMultipleOf,正如我们已经看到的,它转换了 int code> 转换为 int ->布尔

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

isMultipleOf 的定义

现在让我们定义这个神秘的函数创建函数。

let isMultipleOf n x =
    (x % n) = 0

容易吧?

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

isMultipleOf : int -> int -> bool

括号在哪里?

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

a -> b -> c

您应该将其解释为

a -> (b -> c)

“右关联”中的“右”意味着您应该将其解释为最右边的运算符周围有括号。因此:

a -> b -> c -> d

应该解释为

a -> (b -> (c -> d))

isMultipleOf 的用法

因此,正如您所看到的,我们可以使用 isMultipleOf 创建新函数:

let isEven = isMultipleOf 2
let isOdd = not << isEven
let isMultipleOfThree = isMultipleOf 3
let endsWithZero = isMultipleOf 10

F# Interactive 会响应:

isEven : int -> bool
isOdd : int -> bool
isMultipleOfThree : int -> bool
endsWithZero : int -> bool

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

isMultipleOf 10 150

这将返回 true,因为 150 是 10 的倍数。这与 create 完全相同函数 endsWithZero ,然后将其应用到值 150。

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

(isMultipleOf 10) 150

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

现在,如果您能理解这一切,那么您的示例(即规范的 CreateAdder)应该很简单!

不久前有人问这个问题它处理完全相同的概念,但在 Javascript 中。在我的回答中,我给出了两个 inf Javascript 规范示例(CreateAdder、CreateMultiplier),它们对于返回函数更加明确。

我希望这有帮助。

F# types

Let's begin from the beginning.

F# uses the colon (:) notation to indicate types of things. Let's say you define a value of type int:

let myNumber = 5

F# Interactive will understand that myNumber is an integer, and will tell you this by:

myNumber : int

which is read as

myNumber is of type int

F# functional types

So far so good. Let's introduce something else, functional types. A functional type is simply the type of a function. F# uses -> to denote a functional type. This arrow symbolizes that what is written on its left-hand side is transformed into what is written into its right-hand side.

Let's consider a simple function, that takes one argument and transforms it into one output. An example of such a function would be:

isEven : int -> bool

This introduces the name of the function (on the left of the :), and its type. This line can be read in English as:

isEven is of type function that transforms an int into a bool.

Note that to correctly interpret what is being said, you should make a short pause just after the part "is of type", and then read the rest of the sentence at once, without pausing.

In F# functions are values

In F#, functions are (almost) no more special than ordinary types. They are things that you can pass around to functions, return from functions, just like bools, ints or strings.

So if you have:

myNumber : int
isEven : int -> bool

You should consider int and int -> bool as two entities of the same kind: types. Here, myNumber is a value of type int, and isEven is a value of type int -> bool (this is what I'm trying to symbolize when I talk about the short pause above).

Function application

Values of types that contain -> happens to be also called functions, and have special powers: you can apply a function to a value. So, for example,

isEven myNumber

means that you are applying the function called isEven to the value myNumber. As you can expect by inspecting the type of isEven, it will return a boolean value. If you have correctly implemented isEven, it would obviously return false.

A function that returns a value of a functional type

Let's define a generic function to determine is an integer is multiple of some other integer. We can imagine that our function's type will be (the parenthesis are here to help you understand, they might or might not be present, they have a special meaning):

isMultipleOf : int -> (int -> bool)

As you can guess, this is read as:

isMultipleOf is of type (PAUSE) function that transforms an int into (PAUSE) function that transforms an int into a bool.

(here the (PAUSE) denote the pauses when reading out loud).

We will define this function later. Before that, let's see how we can use it:

let isEven = isMultipleOf 2

F# interactive would answer:

isEven : int -> bool

which is read as

isEven is of type int -> bool

Here, isEven has type int -> bool, since we have just given the value 2 (int) to isMultipleOf, which, as we have already seen, transforms an int into an int -> bool.

We can view this function isMultipleOf as a sort of function creator.

Definition of isMultipleOf

So now let's define this mystical function-creating function.

let isMultipleOf n x =
    (x % n) = 0

Easy, huh?

If you type this into F# Interactive, it will answer:

isMultipleOf : int -> int -> bool

Where are the parenthesis?

Note that there are no parenthesis. This is not particularly important for you now. Just remember that the arrows are right associative. That is, if you have

a -> b -> c

you should interpret it as

a -> (b -> c)

The right in right associative means that you should interpret as if there were parenthesis around the rightmost operator. So:

a -> b -> c -> d

should be interpreted as

a -> (b -> (c -> d))

Usages of isMultipleOf

So, as you have seen, we can use isMultipleOf to create new functions:

let isEven = isMultipleOf 2
let isOdd = not << isEven
let isMultipleOfThree = isMultipleOf 3
let endsWithZero = isMultipleOf 10

F# Interactive would respond:

isEven : int -> bool
isOdd : int -> bool
isMultipleOfThree : int -> bool
endsWithZero : int -> bool

But you can use it differently. If you don't want to (or need to) create a new function, you can use it as follows:

isMultipleOf 10 150

This would return true, as 150 is multiple of 10. This is exactly the same as create the function endsWithZero and then applying it to the value 150.

Actually, function application is left associative, which means that the line above should be interpreted as:

(isMultipleOf 10) 150

That is, you put the parenthesis around the leftmost function application.

Now, if you can understand all this, your example (which is the canonical CreateAdder) should be trivial!

Sometime ago someone asked this question which deals with exactly the same concept, but in Javascript. In my answer I give two canonical examples (CreateAdder, CreateMultiplier) inf Javascript, that are somewhat more explicit about returning functions.

I hope this helps.

左耳近心 2024-08-27 00:26:44

典型的例子可能是“加法器创建者”——一个函数,给定一个数字(例如 3),返回另一个函数,该函数接受一个整数并将第一个数字添加到其中。

因此,例如,在伪代码中,

x = CreateAdder(3)
x(5) // returns 8
x(10) // returns 13
CreateAdder(20)(30) // returns 50

我对 F# 不太熟悉,无法在不检查的情况下尝试编写它,但 C# 会是这样的:

public static Func<int, int> CreateAdder(int amountToAdd)
{
    return x => x + amountToAdd;
}

这有帮助吗?

编辑:正如布鲁诺指出的,您在问题中给出的示例正是我给出的 C# 代码示例,因此上面的伪代码将变为:

let x = f1 3
x 5 // Result: 8
x 10 // Result: 13
f1 20 30 // Result: 50

The canonical example of this is probably an "adder creator" - a function which, given a number (e.g. 3) returns another function which takes an integer and adds the first number to it.

So, for example, in pseudo-code

x = CreateAdder(3)
x(5) // returns 8
x(10) // returns 13
CreateAdder(20)(30) // returns 50

I'm not quite comfortable enough in F# to try to write it without checking it, but the C# would be something like:

public static Func<int, int> CreateAdder(int amountToAdd)
{
    return x => x + amountToAdd;
}

Does that help?

EDIT: As Bruno noted, the example you've given in your question is exactly the example I've given C# code for, so the above pseudocode would become:

let x = f1 3
x 5 // Result: 8
x 10 // Result: 13
f1 20 30 // Result: 50
不必你懂 2024-08-27 00:26:44

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

这在功能上相当于一个接受两个整数并返回一个整数的函数。这种处理采用多个参数的函数的方式在函数式语言中很常见,并且可以轻松地在值上部分应用函数。

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

let add x y = x + y

您有一个列表,并且想要将 10 添加到每个项目。您可以将 add 函数部分应用于值 10。它将其中一个参数绑定到 10 并保留另一个参数未绑定。

let list = [1;2;3;4]
let listPlusTen = List.map (add 10)

这个技巧使编写函数变得非常容易,并且使它们非常可重用。正如您所看到的,您不需要编写另一个将 10 添加到列表项的函数来将其传递给 map。您刚刚重用了 add 函数。

It's a function that takes an integer and returns a function that takes an integer and returns an integer.

This is functionally equivalent to a function that takes two integers and returns an integer. This way of treating functions that take multiple parameters is common in functional languages and makes it easy to partially apply a function on a value.

For example, assume there's an add function that takes two integers and adds them together:

let add x y = x + y

You have a list and you want to add 10 to each item. You'd partially apply add function to the value 10. It would bind one of the parameters to 10 and leaves the other argument unbound.

let list = [1;2;3;4]
let listPlusTen = List.map (add 10)

This trick makes composing functions very easy and makes them very reusable. As you can see, you don't need to write another function that adds 10 to the list items to pass it to map. You have just reused the add function.

甜是你 2024-08-27 00:26:44

您通常将其解释为一个接受两个整数并返回一个整数的函数。
您应该阅读柯里化

You usually interpret this as a function that takes two integers and returns an integer.
You should read about currying.

尤怨 2024-08-27 00:26:44

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

最后一部分:

一个接受整数并返回整数的函数

应该相当简单,C# 示例:

public int Test(int takesAnInteger) { return 0; }

所以我们剩下

一个接受整数的函数,它返回(类似于上面的函数)

再次 C#:

public int Test(int takesAnInteger) { return 0; }
public int Test2(int takesAnInteger) { return 1; }

public Func<int,int> Test(int takesAnInteger) {
    if(takesAnInteger == 0) {
        return Test;
    } else {
        return Test2;
    }
}

a function taking an integer, which returns a function which takes an integer and returns an integer

The last part of that:

a function which takes an integer and returns an integer

should be rather simple, C# example:

public int Test(int takesAnInteger) { return 0; }

So we're left with

a function taking an integer, which returns (a function like the one above)

C# again:

public int Test(int takesAnInteger) { return 0; }
public int Test2(int takesAnInteger) { return 1; }

public Func<int,int> Test(int takesAnInteger) {
    if(takesAnInteger == 0) {
        return Test;
    } else {
        return Test2;
    }
}
星光不落少年眉 2024-08-27 00:26:44

在 F#(以及许多其他函数式语言)中,有一个称为柯里化函数的概念。这就是你所看到的。本质上,每个函数都接受一个参数并返回一个值。

乍一看这似乎有点令人困惑,因为您可以编写 let add xy = x + y 并且它似乎添加了两个参数。但实际上,原始的 add 函数只接受参数 x。当您应用它时,它会返回一个函数,该函数接受一个参数 (y) 并已填充 x 值。当您随后应用该函数时,它会返回所需的值整数。

这显示在类型签名中。将类型签名中的箭头视为“获取左侧的内容并返回右侧的内容”。在类型 int -> 中整数-> int,这意味着它接受一个 int 类型的参数(一个整数),并返回一个 int -> 类型的函数。 int — 一个接受整数并返回整数的函数。您会注意到,这与上面对柯里化函数如何工作的描述完全匹配。

In F# (and many other functional languages), there's a concept called curried functions. This is what you're seeing. Essentially, every function takes one argument and returns one value.

This seems a bit confusing at first, because you can write let add x y = x + y and it appears to add two arguments. But actually, the original add function only takes the argument x. When you apply it, it returns a function that takes one argument (y) and has the x value already filled in. When you then apply that function, it returns the desired integer.

This is shown in the type signature. Think of the arrow in a type signature as meaning "takes the thing on my left side and returns the thing on my right side". In the type int -> int -> int, this means that it takes an argument of type int — an integer — and returns a function of type int -> int — a function that takes an integer and returns an integer. You'll notice that this precisely matches the description of how curried functions work above.

趁年轻赶紧闹 2024-08-27 00:26:44

示例:

let fba = pown ab //fab = a^b

是一个函数,它接受 int(指数)并返回一个将其参数提升为该指数的函数,例如

let sqr = f 2

let tothepowerofthird = f 3

所以

sqr 5 = 25

tothepowerof Three 3 = 27

Example:

let f b a = pown a b //f a b = a^b

is a function that takes an int (the exponent) and returns a function that raises its argument to that exponent, like

let sqr = f 2

or

let tothepowerofthree = f 3

so

sqr 5 = 25

tothepowerofthree 3 = 27

凉月流沐 2024-08-27 00:26:44

这个概念称为高阶函数,在函数式编程中非常常见。

函数本身只是另一种类型的数据。因此,您可以编写返回其他函数的函数。当然,您仍然可以拥有一个接受 int 作为参数并返回其他内容的函数。将两者结合起来并考虑以下示例(在 python 中):(

def mult_by(a):
    def _mult_by(x):
        return x*a
    return mult_by

mult_by_3 = mult_by(3)

print mylt_by_3(3)
9

很抱歉使用 python,但我不知道 f#)

The concept is called Higher Order Function and quite common to functional programming.

Functions themselves are just another type of data. Hence you can write functions that return other functions. Of course you can still have a function that takes an int as parameter and returns something else. Combine the two and consider the following example (in python):

def mult_by(a):
    def _mult_by(x):
        return x*a
    return mult_by

mult_by_3 = mult_by(3)

print mylt_by_3(3)
9

(sorry for using python, but i don't know f#)

凉栀 2024-08-27 00:26:44

这里已经有很多答案,但我想提供另一种看法。有时,用多种不同的方式解释同一件事可以帮助你“理解”它。

我喜欢将函数视为“你给我一些东西,我会给你一些其他东西”

所以一个 Func 表示“你给我一个 int,我给你一个 string”。

我还发现从“以后”的角度思考更容易:“当你给我一个整数时,我会给你一个字符串”。当您看到诸如 myfunc = x =>; 之类的内容时,这一点尤其重要。 y => x + y(“你给出一个 x 时,你会得到一些东西,你给出 ay 时会返回 x + y”)。

(顺便说一句,我假设您熟悉 C#)

所以我们可以表达您的 int ->整数-> int 示例为 Func>

我看待 int -> 的另一种方式整数-> int 是通过提供适当类型的参数来剥离左侧的每个元素。当你不再有 -> 时,你就不再“稍后”了,你就得到了一个值。


(只是为了好玩),您可以将一个一次性接受所有参数的函数转换为“渐进式”接受它们的函数(渐进式应用它们的官方术语是“部分应用”),这称为“柯里化”:

static void Main()
{
    //define a simple add function
    Func<int, int, int> add = (a, b) => a + b;

    //curry so we can apply one parameter at a time
    var curried = Curry(add);    

    //'build' an incrementer out of our add function
    var inc = curried(1);         // (var inc = Curry(add)(1) works here too)
    Console.WriteLine(inc(5));    // returns 6
    Console.ReadKey();
}
static Func<T, Func<T, T>> Curry<T>(Func<T, T, T> f)
{
    return a => b => f(a, b);
}

There are already lots of answers here, but I'd like to offer another take. Sometimes explaining the same thing in lots of different ways helps you to 'grok' it.

I like to think of functions as "you give me something, and I'll give you something else back"

So a Func<int, string> says "you give me an int, and I'll give you a string".

I also find it easier to think in terms of 'later' : "When you give me an int, I'll give you a string". This is especially important when you see things like myfunc = x => y => x + y ("When you give curried an x, you get back something which when you give it a y will return x + y").

(By the way, I'm assuming you're familiar with C# here)

So we could express your int -> int -> int example as Func<int, Func<int, int>>.

Another way that I look at int -> int -> int is that you peel away each element from the left by providing an argument of the appropriate type. And when you have no more ->'s, you're out of 'laters' and you get a value.


(Just for fun), you can transform a function which takes all it's arguments in one go into one which takes them 'progressively' (the official term for applying them progressively is 'partial application'), this is called 'currying':

static void Main()
{
    //define a simple add function
    Func<int, int, int> add = (a, b) => a + b;

    //curry so we can apply one parameter at a time
    var curried = Curry(add);    

    //'build' an incrementer out of our add function
    var inc = curried(1);         // (var inc = Curry(add)(1) works here too)
    Console.WriteLine(inc(5));    // returns 6
    Console.ReadKey();
}
static Func<T, Func<T, T>> Curry<T>(Func<T, T, T> f)
{
    return a => b => f(a, b);
}
第七度阳光i 2024-08-27 00:26:44

这是我的 2c。默认情况下,F# 函数启用部分应用或柯里化。这意味着当您定义它时:

let adder a b = a + b;;

您正在定义一个函数,该函数接受整数并返回一个接受整数并返回整数的函数int ->;整数-> int。然后,柯里化允许您部分地应用一个函数来创建另一个函数:

let twoadder = adder 2;;
//val it: int -> int

上面的代码将 a 预定义为 2,这样每当您调用 twoadder 3 时,它都会简单地将 2 添加到参数中。

函数参数用空格分隔的语法相当于以下 lambda 语法:

let adder = fun a -> fun b -> a + b;;

这是一种更易读的方式来确定两个函数实际上是链接的。

Here is my 2 c. By default F# functions enable partial application or currying. This means when you define this:

let adder a b = a + b;;

You are defining a function that takes and integer and returns a function that takes an integer and returns an integer or int -> int -> int. Currying then allows you partiallly apply a function to create another function:

let twoadder = adder 2;;
//val it: int -> int

The above code predifined a to 2, so that whenever you call twoadder 3 it will simply add two to the argument.

The syntax where the function parameters are separated by space is equivalent to this lambda syntax:

let adder = fun a -> fun b -> a + b;;

Which is a more readable way to figure out that the two functions are actually chained.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文