Begtostudy(白途思)'s Professional Technology Blog

欢迎访问begtostudy的专业知识博客!主要是专业技术和算法为主。
  首页  :: 联系 :: 订阅 订阅  :: 管理

F# 基础语法—关键字和结构[z]

Posted on 2010-08-16 19:38  白途思  阅读(548)  评论(0编辑  收藏  举报

原文出处: http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!887.entry

Translated by Mike

我已经写过很多关于F#的博文,但至今为止还没有描述过F#语言的基本语法.所以今天我将尽力弥补这个缺憾,描述一些在F# 代码中常见的一些关键字和语法结构.这篇博文不会覆盖所有的F# 语法,但是差不多能覆盖75%左右的常见语法.为了使本文尽可能的简单,我可能故意在整体的准确性上犯一点儿小错.

#light

大部分的F#文件以”#light”开头

(译者注:在当前的Dev10版本中已经把”#light”设置为默认打开,所以当前的F#文件不需要再显示的调用”#light”)

#light

这个是用来打开”轻量级语法(lightweight syntax)”选项的.我在这里不会讨论和” 轻量级语法”对应的选项是什么,因为人们总是使用”轻量级语法”这个选项.而且在下一个F#版本中”” 轻量级语法”将成为默认选项(译者注:当前的F#版本已经这样做了). 现在还是要确保”#light”总是出现在F#代码文件的开头.

Comments

共有两种类型的注释,看下面的代码

// a one-line comment

(* a multi-line
   comment (* these can nest *) *)

“open” --打开一个命名空间

“open”关键字是用来打开一个命名空间或者模块.

// must fully qualify the name System.Console
System.Console.WriteLine("Hello, world!")

// after opening the namespace, don't need to
open System

Console.WriteLine("Hello, world!")

“let” – 定义函数和值

“let” 关键字用来定义函数和值.这里是使用”let”定义值的一些例子:

let x = 42 // immutable, x is always 42
let mutable y = 0 // mutable, can re-assign y's value with <- operator
let z : string = null // ": string" is type annotation to declare type

你很少会用到类型说明(F#是一种类型推断语言),但是在最后一个例子当中,类型推断还是很有必要的(如果不使用类型说明,’z’将被推断为”obj”(System.Object)类型;这里的类型说明会告诉编译器我们需要’z’是一个”string”类型).

下面是一些使用’let’定义函数的一些例子:

let F x = x + 1
let G x y = x + y
let G2 (x:float) (y:float) : float = x + y
let H(x,y) = x + y
let rec Kaboom x = Kaboom (x+1)

“F”是带一个参数的函数.”G”和”G2”有两个柯里化的参数(后来”G2”中为参数指定的类型说明和为函数返回值指定的类型说明,展示了这种语法),但是”H”使用的是元组(tuple)参数;想知道更多关于元组和柯里化的信息,你一定得读一读这篇博文. 另外,‘let rec’关键字可以定义一个递归函数.

轻量级语法(lightweight syntax)使空格符/缩进显得更有意义,而且缩进是界定函数(和其他结构体)范围最常用的方法.另外,函数可以定义在任何地方.下面这段代码可以说明以上观点:

let Area diameter = // define a function
// everything indented under here is the body of "Area"
let pi = 3.14 // define a value inside the function
let Radius d =  // define another function inside here
// this is the body of the "Radius" function
        d / 2.0
let r = Radius diameter
    pi * r * r

// use the function
let answer = Area 5.0

“fun” -- lambda 表达式在这里是”fun”

“fun”关键字是用来定义lambda(匿名函数)的.语法是”fun 参数 -> 函数体”,而且优先规则往往会强制你把所有的定义放在一对小括号内,请看下面这个例子:

let nums = [1; 2; 3; 4; 5]
let odds = List.filter (fun x -> x%2 = 1) nums
printfn "odds = %A" odds // odds = [1; 3; 5]

在这个例子中,请注意’%’是一个求模操作符,用在这里是为了确定数字’x’是不是奇数, List.filter是对一个列表应用了断言的函数(返回值为布尔型的函数),它返回的是一个通过断言函数返回值为真的元素的 一个列表.

“|>” 管道操作符

一个使用非常频繁的内置操作符就是:pipe. “x |> f” 就是”f x”.因此,上面的例子更习惯于写成下面这个样子:

let nums = [1; 2; 3; 4; 5]
let odds = nums |> List.filter (fun x -> x%2 = 1)
printfn "odds = %A" odds // odds = [1; 3; 5]

其实在这个小例子中使用管道操作符并没有什么实质性的好处, 但是这个操作符经常用来在一系列具有转化性功能函数中”传递”数据.更详细的说明请看这里.

“match” 模式匹配

模式匹配是一个非常强大的语言特征,在很多环境下都可以使用它,但是他最常使用的地方是在’match’表达式中.

match expr with
| pat_1 -> body_1
...
| pat_n -> body_n

这个表达式会测试每一个模式,第一个被匹配上的模式后面的方法体会得到执行.最常见的模式包括简单的代数数据类型,比如可识别联合(Discriminate Union), 特别是针对一个”列表”或者一个”可选值”的匹配;关于可识别联合的描述和怎样针对可识别联合的匹配请看这篇文章的前半部分.(我最后大概会写至少两篇完整的关于模式匹配的文章,不过上面的一段和链接文章中的描述对你来说已经足够了,因为在这你只需要对语言有一个快速的了解.).

条件和循环

虽然在F#中使用的比在其他语言中用的少(一般会用模式匹配和递归替代),F#中还是有if-then-else, while循环,for循环. 由于F#是一门函数式语言,所以这些都属于带返回值的表达式.

下面是if-then-else语法的通式

if cond1 then

expr1
elif cond2 then

expr2
else

expr3

‘elif’和’else’部分是可选的,而且你想使用多少个’elif’(else if)都可以.所有的exprn都必须是同一个类型,这也是整个表达式返回值的类型.如果’else’部分被省略了,exprn必须是’unit’类型(它是”void”的近亲).

While的语法是:

while cond do
expr

整个while表达式总是返回”unit”.在F#语言中并没有像”break”或者”continue”这样的东西.

for pat in expr do
bodyexpr

在这里,expr是一个你可以遍历的东西(比如: Ienumerable<T>, F#中的seq<’a>),pat是任何一个模式(但是最常见的是一个新的标识符名称),bodyexpr在遍历的过程中针对每一个元素执行一遍.举个例子:

for x in someArray do
    printfn "%d" x

打印出”someArray”中的所有整数. 和’while’一样,整个’for’表达式返回’unit’类型.

“new” – 用”new”来创建对象

你可以像在C#中一样使用”new”来创建一个对象.

let x = new System.Uri("http://hello.world/")

然而,在F#中’new’关键字通常是一个可选项.

Literals(该词在翻译上存在争议,具体可参阅这里,本文中为避免误解,不翻译该词)

在F#语言中有很多种Literal,其中最常见的是下面这些:

let b : bool = true // or false
let i : int = 42
let s : string = "hi"
let x : float = 3.14 // "3." same as "3.0"
let ai : int array = [| 1; 2; 3 |] // "int array"=="array<int>"
let lf : float list = [ 1.1; 2.2; 3.3 ] // "float list"=="list<float>"

(这里所有的类型说明都不是必要的,不过他们对我的讲解很有帮助.)布尔,整数,字符串Literal会像你期待的那样正常工作.”浮点型”相当于 System.Double, 它是一种包含小数点的数字常量.数组常量用[|括号|]来书写,而列表常量用[括号]来书写;他们都使用分号(或者另起一行)来区分集合中的元素.这里只展示了最常用的一些类型.我将在新的博文中详细的讨论更多F#内置类型.

Exception constructs

F#有一种”try-catch-finally”结构,并且使用C#中的IDisposable.它的基础语法是:

try
expr
with
| pat_i -> body_i
try
expr
finally
cleanup
use ident = expr

更多描述请看这里.

还有什么没有描述到的?

除了 类型(定义新的类型,类,成员等;包括描述不常见的内置类型)和pervasives(内置操作符和函数),这篇简介几乎囊括了95%的F#常用语法结构. 类型和pervasives我打算在我将来的博文中讲解.

原帖:http://blog.joycode.com/fscti/archive/2009/10/21/115741.joy

前往Begtostudy的编程知识博客(CSDN)