F#简明教程二:F#类型系统和类型推断机制

简介:
在上一篇教程《 F#与函数式编程概述 》中我们了解到F#和函数式编程的一些特点,更多关于F#语言和函数式编程的介绍可以参考51CTO之前对微软MVP赵颉老师的专访《 TechED 09视频专访:F#与函数式编程语言 》。本节教程我们将学习到F#的一些基础原理,在开始之前,让我们先温习一下我们的Hello World代码:
 
 
  1. #light  
  2. System.Console.WriteLine(“This is one hello”)  
  3. printfn “This is another hello” 
F#是函数式和面向对象的混合体。它有时候会看起来与C#或Visual Basic惊人的相似,但却又完全陌生。F#程序以一系列的表达式形式组成,每个表达式可以通过“let”标识符被指定,比如:
 
 
  1. let fles = System.IO.DirectoryInfo(@”C:\Users\Chance”).  
  2. GetFiles() 
在上面的代码中,“fles”被指定了一个值,在这个例子中,是一个文件路径。有意思的是,程序运行中,直到语句在得到右侧的返回值前,“fles”的实际类型都没有被详细定义。你可能觉得有些别扭,在Java或其他编程语言中,变量fles应该被定义成一种数据类型,string或是其他什么类型以在内存中可以明确的被编译器区别对待,但这些规则在F#中有些不同。这也导致我们的F#简明教程稍有不同,我们不会像通常的教程那样介绍F#的基本数据类型,从某种意义上说,F#可以是任意类型或只有一个类型。
F#小提示:F#是一种类型推断语言,它们在编译过程中被推断和确定。如果你在Visual Studio中编写F#,将鼠标指向某个值就会得到它的类型,编译器可以通过函数体或其他方式的定义推断出类型;Visual Studio是开发F#的主要工具,51CTO推荐您阅读Visual Studio 2010中关于F#的资源一文。
类型推断(Type Inference)
我们说数据的类型是被推断出的,因为F#的编译期进程会试图根据变量自身的特点来判断出它的类型并确保这种类型是安全的。尽管F#是强类型语言,但变量的类型声明在类型的判断推理过程中并不是必须的。
类型推断有自身的优点。在使用F#开发一些大型应用时,比如.NET和Java开发者都很熟悉的泛型特性(Generics)便是由类型推断来完成。注意,F#编译器会视任何没有类型标注的表达式为泛型。例如,下面的函数中,各变量的类型被定义(推断为)泛型,即使程序编写者没有定义任何类型。
 
 
  1. let f x =   
  2.     let y = g x  
  3.     h y 
 
 
  1. let f (x:’a) : ’b =  
  2.     let y:’c = (g:’a->’c) x   
  3.     (h:’c->’b) y 
F#小提示:在F#中,泛型类型参数是一个以撇号为前缀的字符。比如上面例子中的’b和’c就是最常用的泛型参数。像在.NET中一样,泛型类型也可使用尖括号语法,比如“Dictionary<’Key,’Value>”。只有一个泛型参数的时候,你有时候会看到它使用‘前缀’语法而不是尖括号——最常见的是和F#泛型类‘list’和‘option’一起使用。比如“int list”和“list<int>”表达同一种功能,只是书写方式不同。
F#类型推断机制
F#语言中的大多数类型推断可以遵循以下两条规则。首先,如果一个函数用于产生一个值,编译器将假定该值的类型是函数需求的。第二,如果一个值是一个表达式的必然结果,这个值的类型是这个表达式所决定的。
有些情况下这些简单的规则不够完全,编译器必须需要类型声明。比如,当一个算数运算符被使用,F#会处理的非常谨慎,如果没有程序员的明确代码,不会将一个数值型赋予另一个。这样做是为了确保F#在进行大规模数值计算时,类型推断不会加重编译器的负担。
针对第二条规则的例子在方法过载的情况下发生。比如Write方法在System.Console(.NET中System.Console封装了基于控制台应用程序的输入、输出和错误流操作)中有18个负载。类型推断可以确定传送给它的类型,但是无法确定另一个方向传送的值的类型。
类型推断不只是简单的符号,它还可以用于程序功能的检测。当你写了一段代码,类型推断功能为这些代码智能的获得了指定的类型,这意味着错误不会被引入程序。这种机制使F#获得动态语言的代码简洁性的同时保证了完全静态的类型系统。
更多关于F#的类型和语法基础请参考:
F#的类型系统和类型推断机制是学习和理解F#语言的基础,掌握了这些有利于我们之后的学习。下周我们将继续F#的学习,一起探究F#的基础语法。









本文转自 red7 51CTO博客,原文链接:http://blog.51cto.com/hong7/267531,如需转载请自行联系原作者
目录
相关文章
|
10月前
|
编译器 C++
【C++ 泛型编程 基础扫盲】 详解为什么C++ 虚拟成员函数模板不被允许
【C++ 泛型编程 基础扫盲】 详解为什么C++ 虚拟成员函数模板不被允许
73 0
|
7月前
|
JavaScript 前端开发 安全
TypeScript中的枚举类型有哪些优点和缺点
【8月更文挑战第4天】 TypeScript中的枚举类型有哪些优点和缺点
80 3
|
7月前
|
SQL Java
访问者模式问题之动态语言在实现访问者模式时有啥优势
访问者模式问题之动态语言在实现访问者模式时有啥优势
|
5月前
|
JavaScript 前端开发 程序员
动态语言、静态语言、强类型语言、弱类型语言的区别
动态语言、静态语言、强类型语言、弱类型语言的区别
|
8月前
|
自然语言处理 算法 安全
编程语言中的静态和动态类型语言
【7月更文挑战第14天】本文介绍静态与动态类型语言对比。类型检查效率是关键,一些系统可能在极端情况下慢。自动化与高效算法的研究持续进行.
99 5
编程语言中的静态和动态类型语言
|
9月前
|
前端开发 JavaScript 安全
TypeScript作为一种静态类型的JavaScript超集,其强大的类型系统和面向对象编程特性为微前端架构的实现提供了有力的支持
【6月更文挑战第11天】微前端架构借助TypeScript提升开发效率和代码可靠性。 TypeScript提供类型安全,防止微前端间通信出错;智能提示和自动补全加速跨代码库开发;重构支持简化代码更新。通过定义公共接口确保一致性,用TypeScript编写微前端以保证质量。集成到构建流程确保顺利构建打包。在微前端场景中,TypeScript是强有力的语言选择。
65 2
|
8月前
|
JavaScript 安全 Java
TypeScript(十四)变体(协变与逆变) 最新推荐文章于 2023-06-27 10:01:47 发布
TypeScript(十四)变体(协变与逆变) 最新推荐文章于 2023-06-27 10:01:47 发布
46 0
|
9月前
|
安全 Java 编译器
JAVA泛型,编译时类型安全的“秘密武器”
【6月更文挑战第28天】Java泛型是JDK 5引入的特性,用于在编译时增强类型安全和代码复用。它允许类、接口和方法使用类型参数,确保运行时类型匹配,减少了类型转换错误。例如,泛型方法`&lt;T&gt; void printArray(T[] array)`能接受任何类型数组,编译器会检查类型一致性。此外,泛型提升了代码的可读性、可维护性和与容器类的配合效率,优化整体软件质量。
67 0
|
10月前
|
C语言 iOS开发 MacOS
Objective-C是一种面向对象的编程语言,它扩展了C语言,添加了面向对象编程的特性
【5月更文挑战第9天】Objective-C是苹果公司的面向对象编程语言,用于iOS和macOS应用开发。它扩展了C语言,包含类定义(接口和实现)、对象创建、消息传递、属性、协议、块和类别等语法特性。例如,类通过`@interface`和`@implementation`定义,对象用`alloc`和`init`创建,方法通过消息传递调用。属性简化变量声明,协议定义可选方法集合,块支持代码块作为参数,类别用于扩展已有类。错误处理常使用NSError对象。要深入了解,建议查阅相关教程和文档。
83 0
|
10月前
|
JavaScript 安全 前端开发
【亮剑】TypeScript 由于其强类型的特性,直接为对象动态添加属性可能会遇到一些问题
【4月更文挑战第30天】本文探讨了在 TypeScript 中安全地为对象动态添加属性的方法。基础方法是使用索引签名,允许接受任何属性名但牺牲了部分类型检查。进阶方法是接口扩展,通过声明合并动态添加属性,保持类型安全但可能导致代码重复。高级方法利用 OOP 模式的类继承,确保类型安全但增加代码复杂性。选择哪种方法取决于应用场景、代码复杂性和类型安全性需求。
89 0