为什么这个 F# 函数需要括号?
Why are parentheses needed on this F# function?
为什么下面的 read_rest_of_csv
需要括号?
let read_rest_of_csv() =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
while read_rest_of_csv() do ignore None
没有括号,循环将不会终止。
open System
open System.Threading
open System.Collections.Generic
open System.Linq
open System.Text
open System.Threading.Tasks
open System.IO
open Microsoft.VisualBasic.FileIO
[<EntryPoint>]
let main argv =
let csv_fileH = new TextFieldParser("test1.csv")
csv_fileH.TextFieldType = FieldType.Delimited |> ignore
let x = csv_fileH.SetDelimiters(",")
let csv_data = new List<string[]>()
let eod = csv_fileH.EndOfData
if not eod then
let column_headings = csv_fileH.ReadFields()
csv_data.Add(column_headings) |> ignore
let read_rest_of_csv =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
while read_rest_of_csv do ignore None
0
很抱歉,我不记得我是在哪里看到的。我认为这是在 SO 中。这是一个很好的例子。
这会不会是我在处理某种函数对象时没有括号?
我确实不仅有 C、C++ 和 C# 背景,还有中级 Clojure 背景。在我使用 F# 语法的情况下,更详细地阅读我的 Haskell 手册可能会有所帮助,因为语法看起来很相似。
没有括号,内容只执行一次,不再执行。 read_rest_of_csv
有一个类型 bool
:你基本上是在说 while true do ignore None
。
括号表示 read_rest_of_csv
的类型为 unit -> bool
,因此每次调用它时,它都会读取一行并移动光标。否则,它只会执行一次。
你的问题的答案是:
let read_rest_of_csv =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
根本不是函数。这与以下内容没有区别:
> let i = 1;;
val i : int = 1
这声明了一个具有整数值的绑定。如果你想用一个不带参数的函数值声明一个绑定,看起来像这样:
> let i () = 1;;
val i : unit -> int
完全相同的推理适用于 read_rest_of_csv
。如果没有括号,您将声明类型为 bool
的绑定。使用括号,您正在声明类型为 unit->bool
的绑定,即具有函数值的绑定,其中函数不接受输入并且 returns 一个布尔值。
似乎来自 C 系列语言(C#、Java、C、C++、JavaScript)的人在理解 F# 中括号的使用时遇到问题。我当然有,而且我花了几年时间才知道事情是如何运作的。
简而言之,F# 中最基本的构建块是 值。值可以是 let
-bound:
let foo = bar
这意味着foo
是一个值,恰好等于bar
。
函数也是值:
// 'a -> 'a * 'a
let f = fun x -> x, x
这里,f
是一个函数,它接受一些值 (x
) 和 returns 一个以 x
作为第一个和第二个元素的元组。
写起来有点麻烦,所以有一个shorthand:
// 'a -> 'a * 'a
let f x = x, x
请注意,这些表达式中没有括号。
有时您需要调整运算符的优先级。就像在数学中一样,1 + 2 * 3
(相当于 1 + (2 * 3)
)与 (1 + 2) * 3
不同。在 F# 中,您还可以使用方括号来覆盖优先级。于是
// 'a -> string * 'a
let f x = someOtherFunction x, x
与
不同
// x:'a -> string
let f x = someOtherFunction (x, x)
(在这种情况下,someOtherFunction
是 returns 一个 string
的函数。)
注意方括号不表示函数调用;他们只是在那里控制评估顺序。
有时,您想定义一个不接受任何输入的函数。但是,您不能这样定义它:
let f = whatever
因为这会使它成为一个 值,并立即 let
绑定到 whatever
。相反,您可以让函数采用内置类型 unit
的值。这个类型只有一个值,写成()
:
let f () = whatever
这意味着 f
是一个函数,pattern 将其输入与 unit
的唯一已知值相匹配。
每当您使用 ()
调用 f
时,都会计算并返回表达式 whatever
。
为什么下面的 read_rest_of_csv
需要括号?
let read_rest_of_csv() =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
while read_rest_of_csv() do ignore None
没有括号,循环将不会终止。
open System
open System.Threading
open System.Collections.Generic
open System.Linq
open System.Text
open System.Threading.Tasks
open System.IO
open Microsoft.VisualBasic.FileIO
[<EntryPoint>]
let main argv =
let csv_fileH = new TextFieldParser("test1.csv")
csv_fileH.TextFieldType = FieldType.Delimited |> ignore
let x = csv_fileH.SetDelimiters(",")
let csv_data = new List<string[]>()
let eod = csv_fileH.EndOfData
if not eod then
let column_headings = csv_fileH.ReadFields()
csv_data.Add(column_headings) |> ignore
let read_rest_of_csv =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
while read_rest_of_csv do ignore None
0
很抱歉,我不记得我是在哪里看到的。我认为这是在 SO 中。这是一个很好的例子。
这会不会是我在处理某种函数对象时没有括号?
我确实不仅有 C、C++ 和 C# 背景,还有中级 Clojure 背景。在我使用 F# 语法的情况下,更详细地阅读我的 Haskell 手册可能会有所帮助,因为语法看起来很相似。
没有括号,内容只执行一次,不再执行。 read_rest_of_csv
有一个类型 bool
:你基本上是在说 while true do ignore None
。
括号表示 read_rest_of_csv
的类型为 unit -> bool
,因此每次调用它时,它都会读取一行并移动光标。否则,它只会执行一次。
你的问题的答案是:
let read_rest_of_csv =
csv_data.Add(csv_fileH.ReadFields()) |> ignore
not csv_fileH.EndOfData
根本不是函数。这与以下内容没有区别:
> let i = 1;;
val i : int = 1
这声明了一个具有整数值的绑定。如果你想用一个不带参数的函数值声明一个绑定,看起来像这样:
> let i () = 1;;
val i : unit -> int
完全相同的推理适用于 read_rest_of_csv
。如果没有括号,您将声明类型为 bool
的绑定。使用括号,您正在声明类型为 unit->bool
的绑定,即具有函数值的绑定,其中函数不接受输入并且 returns 一个布尔值。
似乎来自 C 系列语言(C#、Java、C、C++、JavaScript)的人在理解 F# 中括号的使用时遇到问题。我当然有,而且我花了几年时间才知道事情是如何运作的。
简而言之,F# 中最基本的构建块是 值。值可以是 let
-bound:
let foo = bar
这意味着foo
是一个值,恰好等于bar
。
函数也是值:
// 'a -> 'a * 'a
let f = fun x -> x, x
这里,f
是一个函数,它接受一些值 (x
) 和 returns 一个以 x
作为第一个和第二个元素的元组。
写起来有点麻烦,所以有一个shorthand:
// 'a -> 'a * 'a
let f x = x, x
请注意,这些表达式中没有括号。
有时您需要调整运算符的优先级。就像在数学中一样,1 + 2 * 3
(相当于 1 + (2 * 3)
)与 (1 + 2) * 3
不同。在 F# 中,您还可以使用方括号来覆盖优先级。于是
// 'a -> string * 'a
let f x = someOtherFunction x, x
与
不同// x:'a -> string
let f x = someOtherFunction (x, x)
(在这种情况下,someOtherFunction
是 returns 一个 string
的函数。)
注意方括号不表示函数调用;他们只是在那里控制评估顺序。
有时,您想定义一个不接受任何输入的函数。但是,您不能这样定义它:
let f = whatever
因为这会使它成为一个 值,并立即 let
绑定到 whatever
。相反,您可以让函数采用内置类型 unit
的值。这个类型只有一个值,写成()
:
let f () = whatever
这意味着 f
是一个函数,pattern 将其输入与 unit
的唯一已知值相匹配。
每当您使用 ()
调用 f
时,都会计算并返回表达式 whatever
。