看起来像StackOveflow这里有一群F#爱好者.
我想更好地了解这种语言,因此,除了函数式编程理论之外,您能否指出我开始使用F#语言的更好起点?我的意思是,教程,怎么样,但首先是工作样本有机会开始做某事并享受语言.
非常感谢
安德里亚
不要惹恼自己,但我在这里和这里写了几篇F#概述帖子.Chris Smith(MS的F#团队成员)在20分钟内发表了一篇名为"F#"的文章 - 第1 部分和第2部分.
请注意,您必须要小心,因为F#(版本1.9.6.0)的最新CTP与以前的版本相比有一些严重的变化,所以一些示例/教程可能无法修改.
这里有一些很酷的东西,也许我可以在这里给你一些提示,这些提示显然非常简短,可能不是很好,但希望能给你一些东西!: -
首先要注意的是 - 互联网上的大多数示例都假设"轻量级语法"已打开.为实现此目的,请使用以下代码: -
#light
这可以防止您必须插入某些为OCaml兼容性而存在的关键字,并且还必须以分号终止每一行.请注意,使用此语法意味着缩进定义范围.这将在后面的示例中变得清晰,所有这些示例都依赖于打开轻量级语法.
如果您正在使用交互模式,则必须使用双分号终止所有语句,例如: -
> #light;; > let f x y = x + y;; val f : int -> int -> int > f 1 2;; val it : int = 3
请注意,交互模式在每行后返回"val"结果.这提供了有关我们正在进行的定义的重要信息,例如'val f:int - > int - > int'表示带有两个int的函数返回一个int.
请注意,只有在交互式中我们才需要终止带有分号的行,当实际定义F#代码时我们没有那个:-)
您可以使用'let'关键字定义函数.这可能是所有F#中最重要的关键字,你会经常使用它.例如:-
let sumStuff x y = x + y let sumStuffTuple (x, y) = x + y
我们可以这样称呼这些功能: -
sumStuff 1 2 3 sumStuffTuple (1, 2) 3
注意这里定义函数有两种不同的方法 - 你可以用空格分隔参数,也可以在'元组'中指定参数(即用逗号分隔的括号中的值).不同之处在于我们可以使用"部分功能应用程序"来获取使用第一种方法所需的参数少于所需参数的函数,而不是使用第二种方法.例如:-
let sumStuff1 = sumStuff 1 sumStuff 2 3
注意我们从表达式'sumStuff 1'获得一个函数.当我们可以像被称为具有"第一类函数"的语言一样容易地传递函数时,这是任何函数语言(如F#)的基本部分.
模式匹配非常酷,它基本上就像一个关于类固醇的开关语句(是的,我从另一个F#-ist :-)中删除了那个短语.你可以做的事情: -
let someThing x = match x with | 0 -> "zero" | 1 -> "one" | 2 -> "two" | x when x < 0 -> "negative = " + x.ToString() | _ when x%2 = 0 -> "greater than two but even" | _ -> "greater than two but odd"
注意我们在想要匹配某些东西时使用'_'符号,但我们返回的表达式不依赖于输入.
我们可以根据需要使用if,elif和else语句缩写模式匹配: -
let negEvenOdd x = if x < 0 then "neg" elif x % 2 = 0 then "even" else "odd"
F#列表(在下面实现为链接列表)可以这样操作: -
let l1 = [1;2;3] l1.[0] 1 let l2 = [1 .. 10] List.length l2 10 let squares = [for i in 1..10 -> i * i] squares [1; 4; 9; 16; 25; 36; 49; 64; 81; 100] let square x = x * x;; let squares2 = List.map square [1..10] squares2 [1; 4; 9; 16; 25; 36; 49; 64; 81; 100] let evenSquares = List.filter (fun x -> x % 2 = 0) squares evenSqares [4; 16; 36; 64; 100]
请注意,List.map函数将方形函数"映射"到列表中的1到10,即将函数应用于每个元素.List.filter'过滤'列表只返回列表中传递提供的谓词函数的值.还要注意'fun x - > f'语法 - 这是F#lambda.
请注意,在整个过程中我们没有定义任何类型--F#编译器/解释器'推断'类型,即从您的使用中找出您想要的东西.例如:-
let f x = "hi " + x
这里编译器/解释器将确定x是一个字符串,因为您正在执行一个需要x为字符串的操作.它还确定返回类型也是字符串.
当存在歧义时,编译器会做出假设,例如: -
let f x y = x + y
这里x和y可以是多种类型,但编译器默认为int.如果要定义类型,可以使用类型注释: -
let f (x:string) y = x + y
另请注意,我们必须在括号中包含x:string,我们通常必须这样做以分隔函数定义的各个部分.
F#中两个非常有用且使用频繁的运算符分别是管道转发和函数组合运算符|>和>>.
我们定义|>因此: -
let (|>) x f = f x
请注意,您可以在F#中定义运算符,这非常酷:-).
这允许您以更清晰的方式编写内容,例如: -
[1..10] |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
将允许您获得前10个偶数正方形.这比以下更清楚: -
List.filter (fun x -> x % 2 = 0) (List.map (fun x -> x * x) [1..10])
好吧,至少我是这么认为的:-)
>>运算符定义的函数组成定义如下: -
let (>>) f g x = g(f(x))
即前向管道操作只有第一个函数的参数仍未指定.这很有用,因为您可以执行以下操作: -
let mapFilter = List.map (fun x -> x * x) >> List.filter (fun x -> x % 2 = 0)
这里mapFilter将接受一个输入列表并返回像以前一样过滤的列表.它是以下的缩写版本: -
let mapFilter = l |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
如果我们想编写递归函数,我们必须通过在let之后放置'rec'来将函数定义为递归函数.以下示例.
一些很酷的东西: -
阶乘
let rec fact x = if x <= 1 then 1 else x * fact (x-1)
第n个斐波纳契数
let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2)
FizzBuzz
let (/%) x y = x % y = 0 let fb = function | x when x /% 15 -> "FizzBuzz" | x when x /% 3 -> "Fizz" | x when x /% 5 -> "Buzz" | x -> x.ToString() [1..100] |> List.map (fb >> printfn "%s")
无论如何,这是一个非常简短的概述,希望它有点帮助!!
毫无疑问,你应该购买Don Syme的优秀书籍"Expert F#".这本书写得很好,适合初学者和专家.在其中,您将找到介绍性材料和更具挑战性的材料.近600页,物有所值.
我发现它教会了我很多有用的技术来编写更多功能的C#,并提供了开始编写Windows托管的F#应用程序所需的所有参考资料.
该书由Apress出版,并附有一个网站:http: //www.expert-fsharp.com/default.aspx
@kronoz - 非常感谢你的长篇答案,这是一个非常好的起点.我会按照你的意见,找一下@vecstasy所提到的那本书.
现在,让我去编码:-)
let thanksalot = "thanks a lot" printfn "%s" (thanksalot);;