一段时间以来,我一直在尝试打开和关闭 F#,但我一直被推迟。为什么?
因为无论我尝试查看哪个“初学者”资源,我都会看到非常简单的示例,这些示例开始使用 operator ->
。
但是,到目前为止,我还没有找到任何地方可以清楚简单地解释此运算符的含义。就好像它必须如此明显,以至于即使完成新手也不需要解释。
因此,我必须非常密集,或者可能是近 3 年的经验使我退缩了。
有人可以请解释一下或指出一个真正可访问的资源来解释它吗?
一段时间以来,我一直在尝试打开和关闭 F#,但我一直被推迟。为什么?
因为无论我尝试查看哪个“初学者”资源,我都会看到非常简单的示例,这些示例开始使用 operator ->
。
但是,到目前为止,我还没有找到任何地方可以清楚简单地解释此运算符的含义。就好像它必须如此明显,以至于即使完成新手也不需要解释。
因此,我必须非常密集,或者可能是近 3 年的经验使我退缩了。
有人可以请解释一下或指出一个真正可访问的资源来解释它吗?
'->' 不是运算符。它在许多地方出现在 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”的运算符,您可能会感到非常困惑,因为符号在不同的上下文中具有不同的含义。但是,一旦您对语言有足够的了解以识别这些上下文,事情就会变得清晰。
它基本上意味着“映射到”。以这种方式阅读它,或者“转化为”或类似的东西。
因此,从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 是否为甚至。
第一个问题 - 你熟悉 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# 的有用信息,我发现博客比任何官方“文档”都更有用:这里有一些名称可供查看
(a -> b) 表示“从 a 到 b 的函数”。在类型注解中,它表示一个函数类型。例如, f : (int -> String) 表示 f 指的是一个接受整数并返回字符串的函数。它也被用作此类值的构造函数,例如
val f : (int -> int) = fun n -> n * 2
它创建了一个值,该值是从某个数字 n 到相同数字乘以 2 的函数。
来自微软:
函数类型是赋予一等函数值的类型,写成 int -> int。它们类似于 .NET 委托类型,只是它们没有给定名称。所有 F# 函数标识符都可以用作一等函数值,并且可以使用 (fun ... -> ...) 表达式形式创建匿名函数值。
这里已经有很多很好的答案,我只是想在对话中添加另一种思考方式。
' -> ' 表示功能。
'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。
在定义函数的上下文中,它类似于=>
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
这个问题有很多很好的答案,谢谢大家。我想在这里放一个可编辑的答案,将事情结合在一起。
对于那些熟悉 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 的函数的类型。
-> 出现在其他语法(例如匹配)中也很有帮助,但它的含义不同?那是对的吗?我不确定是不是。我怀疑它具有相同的含义,但我还没有表达的词汇。
请注意,此答案的目的不是产生进一步的答案,而是由你们协作编辑以创建更明确的答案。最终,最好删除所有不确定性和绒毛(例如本段)并添加更好的示例。让我们尽量让没有经验的人可以访问这个答案。
诸如 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
给你!