并不是为了让自己可怕,而是我在博客here和here上写了几篇F#概述文章。克里斯史密斯(MS的F#团队的负责人)发表了一篇名为“20分钟内的F#”的文章-part 1和part 2。
请注意,由于最新的F#CTP(版本1.9.6.0)与以前的版本相比有一些重大突破,因此请务必小心,因此此处的某些示例/教程在未进行修改的情况下可能无法工作。
这是一些很酷的东西的简要介绍,也许我可以在这里给您一些提示,这些提示很简短,可能不太好,但希望能给您一些帮助!-
首先注意-互联网上的大多数示例都假定“轻量语法”已打开。为此,请使用以下代码行:
#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#)的基本组成部分。
模式匹配非常酷,基本上就像类固醇的switch语句一样(是的,我从另一个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")
无论如何,这是一个非常简短的概述,希望对您有所帮助!!