F#程序构造

大多语言比如c#,需要一个明确的入口点,这就是最常见的main函数。但是我们的F#程序目前为止还没有一个特别明确的标记来说明程序要从这儿开始。在F#里,对一个个单一的文件程序来说(.fs),代码文件里的内容自上而下已经可以执行(不需要定义一个明确的main方法)
然而对多文件的工程来说,代码需要被分成一个个叫做modules或者namespaces的模块单元里去。
下面先介绍Modules
目前为止我们所有的代码都写在module里,默认情况下,F#将我们的代码放置在一个和代码文件名字相同并将首字母大写的匿名Module里。所以,如果我们有一个叫做value1的值,我们的代码文件是file1.fs,那么就可以用合法的全路径来指向它:File1.value1。
创建一个modules
我们可以在代码文件的第一行使用关键字module明确的指定代码的module。
然后,每一个变量,函数,或者是类型定义将都属于这个Module。
例子:

1 module Alpha    //定义一个模块Alpha
2 let x=1 //使用Alpha.x

嵌套的modules
modules是可以嵌套的。定义一个嵌套的module,也是使用module关键字。
在定义嵌套的module时一定要注意缩进,这将直接影响到module的嵌套级别。下面演示了有缩进和无缩进的module

 1 module Utilities
2 //将使用Utilities.ConversionUtils.intToString
3 module ConversionUtils =
4 let intToString (x : int)= x.ToString()
5
6 module ConvertBase=
7 //将使用Utilities.ConversionUtils.ConvertBase.convertToHex
8 let convertToHex x = sprintf "%x" x
9 //将使用Utilities.ConversionUtils.ConvertBase.convertToOct
10 let convertToOct x = sprintf "%o" x
11
12 module DataTypes =
13 //将使用Utilities.DataTypes.Point
14 type Point = Point of float * float * float


命名空间

modules的替代品那么就是namespaces了。。命名空间也是像Module一样组织代码,仅仅的不同之处是无法包含值,而只能有类型定义。并且命名空间不能像Modules那样嵌套。那么替代的做法就是可以在同一个文件里定义多个命名空间。
例子:

 1 namespace PlayingCards
2 //PlayingCards.Suit
3 type Suit =
4 | Spade
5 | Club
6 | Heart
7
8 //PlayingCards.PlayingCard
9 type PlayingCard =
10 | Ace of Suit
11 | King of Suit
12 | Queen of Suit
13 | Jack of Suit
14
15 namespace PlayingCards.Poker
16
17 //PlayingCards.Poker.PokerPlayer
18 type PokerPlayer = { Name : string; Money : int; Position : int}

可能在F#里namespaces和modules看上去都不太习惯。这里想说的是modules
是最佳化的解决方案,至少目前是这样。从另一方面说命名空间可能将用于以后大规模的项目。

下面还有F#程序是如何启动的还没写。晚上补上。

 

下面讨论F#程序的启动

F#的启动顺序是从你新添加的fs文件开始。比如说最开始的F#项目中有一个program.fs,如果你这里面写了代码,F5后可以运行,你将会看到输出结果,此时你再重新添加一个空白fs文件,直接F5后将看不到任何输出,因为他执行的是你新添加的文件。而你的新文件里面还没有代码。

先看一下下面一个简单的程序。

1 // Program.fs
2 let numbers = [1 .. 10]
3 let square x = x * x
4 let squaredNumbers = List.map square numbers
5 printfn "SquaredNumbers = %A" squaredNumbers
6 open System
7 printfn "(press any key to continue)"
8 ignore(Console.ReadKey(true))

  这段代码第二行定义了一个Numbers函数,他将产生一个[1;2;3;4;5;6;7;8;9;10]这样一个数组

第三行定义了一个square函数,这个函数会返回一个参数的乘积运算

第四行的代码调用了List.map函数,这个函数的意思是产生一个新的集合,其中的元素是将给定的函数应用于集合的每一个元素的结果。

那么在具体到这行代码里面就是将返回由函数numbers产生的1到10的元素分别做平方运算的结果。也就是[1;4;9;...100]

这种执行方式如果看不习惯会觉得很混乱很别扭,为什么要从最后一个文件开始执行,这很让人受不了。下面我们看看如何使用Module执行一个真正的程序。

当然在F#里我们也可以使用[<EntryPoint>]特性来写类似main函数的方法来定义程序的入口点。

为了运行通过,必须确保以下几点:

1,必须确保是在编译序列中的最后一个文件的最后一个声明,并且只能在编译为.exe时才可以使用。

2,要定义单一的一个string[]类型的参数。

3,返回一个int类型的值,以表示程序退出代码

重写上面的代码就是:

 1 open System
2 [<EntryPoint>]
3 let main (args : string[]) =
4 let numbers = [1 .. 10]
5 let square x = x * x
6 let squaredNumbers = List.map square numbers
7 printfn "SquaredNumbers = %A" squaredNumbers
8 printfn "(press any key to continue)")
9 Console.ReadKey(True) |> ignore
10 // Return 0
11 0

现在我们已经知道了F#是如何运行的了,不用在添加一个新文件后忽然发现执行不了了,原因就在于此。

以后的章节让我们用F#写出更强大的功能!

有问题请在下面提问。我会把所知道的告诉大家。

 

posted @ 2011-08-31 18:33  carsick_cars  阅读(1611)  评论(11编辑  收藏