F#运行原理之程序构造
一切从Modules说起:
创建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#的启动顺序是从你新添加的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#是如何运行的了,不用在添加一个新文件后忽然发现执行不了了,原因就在于此。
补充:
然而对多文件的工程来说,代码需要被分成一个个叫做modules或者namespaces的模块单元里去。
作者: 水知道答案