26

一段时间以来,我一直在尝试打开和关闭 F#,但我一直被推迟。为什么?

因为无论我尝试查看哪个“初学者”资源,我都会看到非常简单的示例,这些示例开始使用 operator ->

但是,到目前为止,我还没有找到任何地方可以清楚简单地解释此运算符的含义。就好像它必须如此明显,以至于即使完成新手也不需要解释。

因此,我必须非常密集,或者可能是近 3 年的经验使我退缩了。

有人可以请解释一下或指出一个真正可访问的资源来解释它吗?

4

9 回答 9

50

'->' 不是运算符。它在许多地方出现在 F# 语法中,其含义取决于它如何用作更大构造的一部分。

在类型内部,'->' 描述了人们上面描述的函数类型。例如

let f : int -> int = ...

表示“f”是一个接受 int 并返回 int 的函数。

在 lambda(“以 'fun' 关键字开头的东西”)中,'->' 是将参数与正文分开的语法。例如

fun x y -> x + y + 1

是一个表达式,它定义了具有给定实现的两个参数函数。

在“匹配”结构中,'->' 是将模式与模式匹配时应该运行的代码分开的语法。例如,在

match someList with
| [] -> 0
| h::t -> 1

每个'->'左边的东西是模式,右边的东西是如果左边的模式匹配会发生什么。

理解的困难可能源于错误的假设,即“->”是具有单一含义的“运算符”。一个类比可能是“。” 在 C# 中,如果您以前从未见过任何代码,请尝试分析“.”。基于查看“obj.Method”和“3.14”和“System.Collections”的运算符,您可能会感到非常困惑,因为符号在不同的上下文中具有不同的含义。但是,一旦您对语言有足够的了解以识别这些上下文,事情就会变得清晰。

于 2008-09-19T20:56:26.237 回答
13

它基本上意味着“映射到”。以这种方式阅读它,或者“转化为”或类似的东西。

因此,从F# in 20 分钟教程中,

> List.map (fun x -> x % 2 = 0) [1 .. 10];;
val it : bool list
= [false; true; false; true; false; true; false; true; false; true]

代码 (fun i -> i % 2 = 0) 定义了一个匿名函数,称为 lambda 表达式,它有一个参数 x,该函数返回“x % 2 = 0”的结果,即 x 是否为甚至。

于 2008-09-19T19:21:05.173 回答
9

第一个问题 - 你熟悉 C# 中的 lambda 表达式吗?如果是这样,F# 中的 -> 与 C# 中的 => 相同(我认为你读到它'goes to')。

-> 运算符也可以在模式匹配的上下文中找到

match x with
| 1 -> dosomething
| _ -> dosomethingelse

我不确定这是否也是一个 lambda 表达式或其他东西,但我想“去”仍然成立。

也许您真正指的是 F# 解析器的“神秘”响应:

> let add a b = a + b
val add: int -> int -> int

这意味着(正如大多数示例所解释的)add 是一个“val”,它接受两个整数并返回一个整数。对我来说,这从一开始就完全不透明。我的意思是,我怎么知道 add 不是一个接受一个 int 并返回两个 int 的 val?

嗯,事情是,在某种意义上,它确实如此。如果我只添加一个 int,我会得到一个 (int -> int):

> let inc = add 1
val inc: int -> int

这(currying)是让 F# 如此性感的原因之一,对我来说。

有关 F# 的有用信息,我发现博客比任何官方“文档”都更有用:这里有一些名称可供查看

于 2008-09-19T20:29:10.110 回答
4

(a -> b) 表示“从 a 到 b 的函数”。在类型注解中,它表示一个函数类型。例如, f : (int -> String) 表示 f 指的是一个接受整数并返回字符串的函数。它也被用作此类值的构造函数,例如

val f : (int -> int) = fun n -> n * 2

它创建了一个值,该值是从某个数字 n 到相同数字乘以 2 的函数。

于 2008-09-19T19:24:39.297 回答
1

来自微软

函数类型是赋予一等函数值的类型,写成 int -> int。它们类似于 .NET 委托类型,只是它们没有给定名称。所有 F# 函数标识符都可以用作一等函数值,并且可以使用 (fun ... -> ...) 表达式形式创建匿名函数值。

于 2008-09-19T19:22:50.177 回答
1

这里已经有很多很好的答案,我只是想在对话中添加另一种思考方式。

' -> ' 表示功能。

'a -> 'b 是一个接受 'a 并返回 'b 的函数

('a * 'b) -> ('c * 'd) 是一个函数,它接受一个 ('a, 'b) 类型的元组并返回一个 ('c, 'd) 元组。比如int/string返回float/char。

有趣的地方在于 'a -> 'b -> 'c 的级联情况。这是一个接受 'a 并返回一个函数 ('b -> 'c) 的函数,或者一个接受 'b -> 'c 的函数。

所以如果你写: let fxyz = ()

类型将是 f : 'a -> 'b -> 'c -> unit,所以如果你只应用第一个参数,结果将是一个柯里化函数 'b -> 'c -> 'unit。

于 2008-09-19T19:58:04.443 回答
1

在定义函数的上下文中,它类似于=>C# 3.0 中的 lambda 表达式。

F#: let f = fun x -> x*x
C#: Func<int, int> f = x => x * x;

F# 中的->也用于模式匹配,它的意思是:如果表达式匹配 and 之间的部分|->那么后面->的内容应该作为结果返回:

let isOne x = match x with
 | 1 -> true
 | _ -> false
于 2008-09-19T20:15:18.927 回答
1

这个问题有很多很好的答案,谢谢大家。我想在这里放一个可编辑的答案,将事情结合在一起。

对于那些熟悉 C# 理解的人来说 -> 与 => lamba 表达式相同是一个很好的第一步。这种用法是:-

fun x y -> x + y + 1

可以理解为等价于:-

(x, y) => x + y + 1;

然而,很明显 -> 具有更基本的含义,它源于一个概念,即采用上述两个参数的函数可以简化(这是正确的术语吗?)为一系列仅采用一个参数的函数。

因此,当上面这样描述时:-

Int -> Int -> Int

知道 -> 是正确的关联真的很有帮助,因此可以考虑以上内容:-

Int -> (Int -> Int)

啊哈!我们有一个接受 Int 并返回 (Int -> Int) 的函数(一个柯里化函数?)。

-> 也可以作为类型定义的一部分出现的解释也有帮助。(Int -> Int) 是任何接受 Int 并返回 Int 的函数的类型。

-> 出现在其他语法(例如匹配)中也很有帮助,但它的含义不同?那是对的吗?我不确定是不是。我怀疑它具有相同的含义,但我还没有表达的词汇。

请注意,此答案的目的不是产生进一步的答案,而是由你们协作编辑以创建更明确的答案。最终,最好删除所有不确定性和绒毛(例如本段)并添加更好的示例。让我们尽量让没有经验的人可以访问这个答案。

于 2008-09-20T21:15:45.137 回答
0

诸如 Haskell 之类的语言的好处(它在 F# 中非常相似,但我不知道确切的语法 - 这应该有助于您理解 ->,不过)是您可以仅应用部分参数来创建curried职能:

adder n x y = n + x + y

换句话说:“给我三样东西,我会把它们加在一起”。当你向它抛出数字时,编译器会推断出 nx 和 y 的类型。说你写

adder 1 2 3

1、2 和 3 的类型是 Int。所以:

adder :: Int -> Int -> Int -> Int

也就是说,给我三个整数,我最终会变成一个整数,或者说的一样:

five :: Int
five = 5

但是,这是很好的部分!试试这个:

add5 = adder 5

你还记得,adder 接受一个 int、一个 int、一个 int,然后返回一个 int。然而,这并不是全部真相,您很快就会看到。事实上,add5 会有这种类型:

add5 :: Int -> Int -> Int

就好像你已经“剥离”了整数(最左边的),并将它直接粘到函数上。仔细观察函数签名,我们注意到 -> 是右关联的,即:

addder :: Int -> (Int -> (Int -> Int))

这应该很清楚:当你给加法器第一个整数时,它会评估第一个箭头右边的任何东西,或者:

add5andtwomore :: Int -> (Int -> Int)
add5andtwomore = adder 5

现在您可以使用 add5andtwomore 而不是“adder 5”。这样,您可以应用另一个整数来获得(比如说)“add5and7andonemore”:

add5and7andonemore :: Int -> Int
add5and7andonemore = adder 5 7

如你所见,add5and7andonemore 正好需要另一个参数,当你给它一个参数时,它会突然变成一个整数!

  > add5and7andonemore 9
 => ((add5andtwomore) 7) 9
 => ((adder 5) 7) 9)
<=> adder 5 7 9

将参数代入加法器 (nxy) 中 (5 7 9),我们得到:

  > adder 5 7 9 = 5 + 7 + 9
 => 5 + 7 + 9
 => 21

实际上, plus 也只是一个接受一个 int 并返回另一个 int 的函数,所以上面的内容真的更像:

  > 5 + 7 + 9
 => (+ 5 (+ 7 9))
 => (+ 5 16)
 => 21

给你!

于 2008-09-19T19:45:11.090 回答