类型和类型推断
F#是强类型语言,意味着你不能用整型参数传给只接受string类型参数函数中。你必须显式的转换。F#的类型系统和常规的编程语言不同。F#中,所有的值都有类型,包括哪些是函数的值。

 
通常,不需要显式的声明类型,编译器根据值能推断出类型。如果一切OK,编译器会保持这样的类型推断。如果类型类型有错误,编译器会报错。VS开发中,可以把鼠标指针悬浮在标识符上查看类型。
let  aString   =   "Spring time in Paris"
let  anInt   =   42
这两个标识符的类型很直白简单
val makeMessage : int -> string
val half : int -> int

 
如果是标识符的值是函数,如
let  makeMessage x   =   ( Printf. sprintf   "%i"  x )   +   " days to spring time"
let  half x   =  x   /   2
类型则如下,注意前面还是val,表示函数仍然也是值:
val makeMessage : int -> string
val half : int -> int
第一个类型表示输入整型返回string
第二个类型表示输入整型返回整型

 
如下的定义
let  div1 x y   =  x   /  y
let  div2   (x, y )   =  x   /  y
let  divRemainder x y   =  x   /  y, x   %  y
类型如下
val div1 : int -> int -> int
val div2 : int * int -> int
val divRemainder : int -> int -> int * int

 
第一个表示参数可以各自输入
第二个用了*号,表示参数是一个二元的元素,包含2个整型的元素作为单独的输入参数。
第三个的类型是int -> int -> int * int,输入的是两个int,返回的是一个元组。
let  doNothing x   =  x
val doNothing : 'a -> 'a
上面的代码看似什么也没做,但是它的类型是'a -> 'a。表示接受一个类型,返回的是同样的类型。任何由单引号(')前缀的类型,都是变量类型(variable type)。
F#有一种类型是obj,对应的是System.Object,表示任何类型的值,概念和CLR中的System.Object差不多。但是变量类型(variable type)不是这样的,注意,->两端都是'a,意思是编译器目前还不知道到底是什么类型。只知道返回的类型和输入的类型是一致的。这个特征也称作类型参数化,使得编译器在编译期间发现更多类型错误,避免转型。

 
变量类型(variable type),或者称做类型参数化,它的概念和CLR2.0中泛型概念相近。F#的创立者Don Syme,在创立F#之前,就设计和实现了.NET CLR中的泛型。有人猜测可能正是由于他县创建了泛型,才能创建F#。
let  doNothingToAnInt   (x:   int )   =  x
let  intList   =   [ 1 ;   2 ;   3 ]
let   (stringList: list < string > )   =   [ "one" ;   "two" ;   "three" ]
val doNothingToAnInt _int : int -> int
val intList : int list
val stringList : string list

 
doNothingToAnInt函数,演示了被约束的值,类型约束。参数x限制为int类型。我们不仅仅只在函数参数中,也可以限制任何标识符为一种类型。
stringList演示了如何限制一个不是函数参数的标识符。

 
限制值类型的语法很简单,加个括号,后面跟冒号(:),冒号后是参数名,这也称做类型标记。
intList的值是一个整型的list,标识符的类型是 int list。表示编译器已经识别出这个list只包含整型,把其他类型加入这个list都会导致编译错误。
stringList有一个类型标记,因为编译器可以从value中解析出类型,所以这不是必须的。这样的写法使得F#看起来类似于.NET库中的泛型类型。也可以用这种写法 stringList : string list