【问题标题】:What does -> mean in F#?-> 在 F# 中是什么意思?
【发布时间】:2008-09-19 19:07:50
【问题描述】:

一段时间以来,我一直在尝试使用 F#,但一直被推迟。为什么?

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

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

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

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

【问题讨论】:

  • 对我来说,这一切都像是希腊语。
  • 实际上玛土撒拉活了 969 岁,所以我仍然是他的三分之一。但是,已编辑谢谢;)
  • 如果使用的年龄单位实际上是农历月份,我们会让玛土撒拉在 75 岁高龄时死去——这完全可信,在沙漠游牧民族中当然值得注意。

标签: f# functional-programming


【解决方案1】:

'->' 不是运算符。它在许多地方出现在 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”的运算符,您可能会感到非常困惑,因为符号在不同的上下文中具有不同的含义。但是,一旦您对语言有足够的了解以识别这些上下文,事情就会变得清晰。

【讨论】:

  • 我接受了这个作为答案,因为它是我正在寻找的那种完整答案的壁橱,但其他答案中还有许多其他细节有帮助。但是,我不相信 -> 不是运算符。其他人可以证实这一点吗?
  • 你可以说它是一个类型级别的操作符。而是一个数据类型构造函数。 ( a -> b ) 与 (a, b) 同构。前者中的箭头与后者中的逗号是同一种东西。
  • Apocalisp,我读了几遍(你假设我知道同构意味着阻止了我)但我现在明白了。
  • 现在在for 循环中它代表do yield ([for i in 0..n -> i])。
【解决方案2】:

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

所以,来自F# in 20 minutes 教程,

> 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 是否为 甚至。

【讨论】:

【解决方案3】:

第一个问题 - 你熟悉 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”,它接受两个 int 并返回一个 int。对我来说,这从一开始就完全不透明。我的意思是,我怎么知道 add 不是一个接受一个 int 并返回两个 int 的 val?

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

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

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

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

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

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

      ' -> ' 表示函数。

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

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

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

      所以如果你写: 设 f x y z = ()

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

      【讨论】:

        【解决方案6】:

        来自Microsoft

        函数类型是赋予给 一流的函数值和是 写成 int -> int。它们很相似 到 .NET 委托类型,但它们除外 没有名字。所有 F# 函数 标识符可以用作第一类 函数值和匿名 可以使用创建函数值 (fun ... -> ...) 表达形式。

        【讨论】:

          【解决方案7】:

          这个问题有很多很好的答案,谢谢大家。我想在这里提供一个可编辑的答案,将所有内容整合在一起。

          对于那些熟悉 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 的函数的类型。

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

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

          【讨论】:

          • 名声够大我会回来的:)
          • 所以在类型定义中 - Int -> Int -> Int = 一个接受一个 int 并返回一个接受一个 int 并返回一个 int 的 func - 对吗?
          【解决方案8】:

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

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

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

          let isOne x = match x with
           | 1 -> true
           | _ -> false
          

          【讨论】:

            【解决方案9】:

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

            adder n x y = n + x + y
            

            换句话说:“给我三样东西,我会把它们加在一起”。当你向它抛出数字时,编译器将推断 n x 和 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
            

            将参数加法器 (n x y) 代入 (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
            

            给你!

            【讨论】:

              最近更新 更多