类型和类型推断
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,返回的是一个元组。
上面的代码看似什么也没做,但是它的类型是'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) = ["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
分享标题:F#初学笔记04
URL链接:
http://cqcxhl.com/article/gidecp.html