函数式编程之-F#类型系统
在深入到函数式编程思想之前,了解函数式独有的类型是非常有必要的。函数式类型跟OO语言中的数据结构截然不同,这也导致使用函数式编程语言来解决问题的思路跟OO的思路有明显的区别。
什么是类型?类型在编程语言中有什么作用呢?一般来说,类型有两个作用:
- 首先当你对某个数据声明类型后,就拥有了编译时的检查,换句话说,你可以认为类型充当了“编译时的单元测试”;
- 类型系统可以让你建立一种模型,用来表达真实世界中的模型;
Tuple type
元组是函数式编程语言中的常用类型,同时在.NET 4.0中被引入到了C#中。但是在C#中几乎不太会用到这种类型,但是在函数式编程语言中却随处可见。
例如在C#中这样使用元组:
var s = new Tuple<int, int>(1, 2);
var fist = s.Item1;
在F#中
let t = 1,2
let first = fst t //提取第一个元素
let second =snd t //提取第二个元素
let f s = t //通过解构提取元素
Record type
Record type是F#中最常用的类型。经常被用来对领域建模(Domain modeling)。例如定义一个矩形数据结构:
type Rect = {
Left: float32
Top: float32
Width: float32
Height: float32
}
这看起来跟OO语言中对class的定义是很相似的,好比在某个class中声明了一组属性。使用起来也简单:
let rc = {
Left = 10.0f;
Top = 10.0f;
Width = 200.0f;
Height = 200.0f
}
你可以把它当做一个简单的class,但是从定义和使用都能看出来Record type更加简单和直接一些。并且我们并没有在Record type里设计一些方法,这跟class有本质的区别。
Record type还支持“复制一个现有记录并进行一些修改”:
let rc2 ={ rc with Left = rc.Left + 100.0f }
C#中的class是没有这种能力的,你不得不显示复制所有属性。
另外Record type自动实现了equal操作符:
type Name = { First:string ; Last:string}
let jim = { First ="Jim"; Last = "Dan"}
let jim2 = {First = "Jim"; Last = "Dan"}
let isSame = jim = jim2 //true
使用Record type来建立领域模型
考虑下面的Contact领域模型:
type Contact = {
FirstName: string;
MiddleName: string;
LastName: string;
EmailAddress: string;
Address1: string;
Address2: string;
City: string;
State: string;
Zip: string;
}
如果你把它当做一个class也是可行的,实际上在OO语言里我们也经常设计这样的class。这样的模型定义犯了三个错误:
- 没有把相关一组类型组合起来,例如FirstName, MiddleName, LastName。这三个类型共同组成了Name,我们的模型并没有体现出这样的设计。
- EmailAddress真的是一个string吗?他能有效的表达Email这样的Domain吗?Email分有效和无效,他拥有自己的规则,并不是所有的字符串都是Email,string这样的类型无法表达Email的Domain含义。
- 在F#中没有null,如果你认为某个类型可能为空,就应该设计为option类型,例如MiddleName,他应该是string option。
还记得前面的章节我们说函数式编程的核心思想是组合,组合不但体现在函数之间的组合,类型也是可组合的:
type PersonalName = {
FirstName: string;
MiddleName: string option;
LastName: string;
}
type EmailContactInfo = {
EmailAddress: string;
IsEmailVerified: bool;
}
type PostalAddress = {
Address1: string;
Address2: string;
City: string;
State: string;
Zip: string;
}
type PostalContactInfo = {
Address: PostalAddress;
IsAddressValid: bool;
}
type Contact = {
Name: PersonalName;
EmailContactInfo: EmailContactInfo;
PostalContactInfo: PostalContactInfo;
}
Descriminated Unions type
中文翻译过来叫做可区分联合,这种类型试图为不同的选项进行建模,所以你可以把他理解为选项类型。
举个例子:“现在温度是多少?“
如何对现在的温度建模?你问的是摄氏度呢还是华氏度呢?如果是摄氏度即38°,如果单位是华氏度,则为100.4°。
type Temperature =
| F of float
| C of int
let tempNow = C(30)
let tempNow2 = F(100.4)
只有一个选项的类型:
type EmailAddress = EmailAddress of string
let email = "a" |> EmailAddress
let emails = ["a"; "b"; "c"] |> List.map EmailAddress
使用 Descriminated Unions type来建立领域模型
选项类型在F#是非常常用的领域模型建模类型,比如设计一个关于支付的模型,在OO语言中,你可能会这样做:
interface IPaymentMethod { }
class Cash : IPaymentMethod { }
class Cheque: IPaymentMethod { }
class Card : IPaymentMethod { }
...
在函数式语言中利用选项类型可以轻松搞定:
type PaymentMethod =
| Cash
| Cheque of ChequeNumber
| Card of CardType * CardNumber
OO思想中通过抽象接口和定义派生类来实现这个模型。函数式语言则利用选项类型把模型核心内容通过尽可能少的代码展现出来。
此时你也许会有所疑虑,在OO的设计中,每种支付方式都是一个独立的实现,所以每种支付方式的具体行为就可以设计在具体的实现中,例如Payment的过程。不同的支付方式显然需要不同的支付过程,这种设计在OO中的好处是显而易见的。
在选项类型中,似乎把三种不同的支付方式揉在了一块,那么每种支付方式的支付过程这种行为怎么实现呢?答案是模式匹配,我们将在下节介绍。
函数式编程之-F#类型系统的更多相关文章
- 函数式编程的类型系统:typeclass--Functor的解释--构造类型
函数式编程的类型系统:typeclass Typeclass是带有关联构造类型的抽象接口,抽象接口的行为用于约束构造类型. 构造类型实现了抽象接口的行为约束,就称这个实现为这个构造类型的函子. 要素: ...
- 函数式编程之-初窥F#
大量讲解函数式编程语言的书籍最终都会用Fuctor,Monad,Monoids,范畴论等各种词汇吓退命令式语言玩家,所以我试图避开这些问题,揭开这些复杂词汇带来的具有实战意义的成果.另外我会尽量使用C ...
- swift语言的特征:类型系统与函数式编程:swift是面向类型和面向函数编程的语言
swift语言的特征: 类型系统:值类型与引用类型.泛型.协议类型 函数式编程:
- trait Monad:函数式编程类型系统本博客搜索关键字--类型升降
trait Monad:函数式编程类型系统本博客搜索关键字--类型升降
- swift之函数式编程(四)
文章内容来自<Functional Programing in Swift>,具体内容请到书中查阅 Map, Filter, Reduce Functions that take func ...
- Java8函数式编程探秘
引子 将行为作为数据传递 怎样在一行代码里同时计算一个列表的和.最大值.最小值.平均值.元素个数.奇偶分组.指数.排序呢? 答案是思维反转!将行为作为数据传递. 文艺青年的代码如下所示: public ...
- 给 JavaScript 开发者讲讲函数式编程
本文译自:Functional Programming for JavaScript People 和大多数人一样,我在几个月前听到了很多关于函数式编程的东西,不过并没有更深入的了解.于我而言,可能只 ...
- 函数式编程-将Monad(单子)融入Swift
前言 近期又开始折腾起Haskell,掉进这个深坑恐怕很难再爬上来了.在不断深入了解Haskell的各种概念以及使用它们去解决实际问题的时候,我会试想着将这些概念移植到Swift中.函数式编程范式的很 ...
- 【JS】394- 简明 JavaScript 函数式编程-入门篇
转载自公众号"程序员成长指北" 写在开头 本文较长,总共分为三大部分:(对于函数式编程以及其优点有一定理解的童鞋,可以直接从 第二部分 开始阅读) 第一部分:首先会通过实际代码介绍 ...
随机推荐
- canvas画布如何画图案例
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 读《赋能》有感zz
听樊登18年春节后第一本新书<赋能>,学到了几个新的管理词语,深井病.还原论.乌卡时代: 下面谈谈自己的学习收获. 深井病就是随着组织发展的壮大,当然是传统的企业,其部门或个人都会变得越来 ...
- 20155205 郝博雅 Exp9 Web安全基础
20155205 郝博雅 Exp9 Web安全基础 一.实验内容 一共做了13个题目. 1.WebGoat 输入java -jar webgoat-container-7.1-exec.jar 在浏览 ...
- android:动态申请权限(一)
环境: android版本6.0 对应SDK版本23 动态申请权限说明:所有动态申请的权限,必须在AndroidManifest.xml中进行声明 步骤 1.新建一个android工程 默认创建即可 ...
- POJ1964-City Game
给你N×M大的矩阵,里面分别有字符‘F'和’R',要找到一个最大的只有‘F'的矩阵,不能包含有’R‘.N,M<=1000. 一开始的思路是单调栈来求最大矩形面积,因为没看清题目不能包含’R'字符 ...
- Java工具eclipse控制台console输出乱码问题
捣鼓了一下午,终于tm解决! 我的是Scanner读入,println打印乱码问题. 首先在cmd窗口运行java,是没有乱码问题的,这证明了在cmd窗口时Scanner输入的和println打印的编 ...
- 有哪些知名的公司在用Python
谷歌:Google App Engine.code.Google.com.Google earth.谷歌爬虫.Google广告等项目都在大量使用Python开发 CIA:美国中情局网站就是用Pytho ...
- C++11常用特性的使用经验总结
转自:http://www.cnblogs.com/feng-sc C++11已经出来很久了,网上也早有很多优秀的C++11新特性的总结文章,在编写本博客之前,博主在工作和学习中学到的关于C++11方 ...
- 用不到 50 行的 Python 代码构建最小的区块链
引用 译者注:随着比特币的不断发展,它的底层技术区块链也逐步走进公众视野,引起大众注意.本文用不到50行的Python代码构建最小的数据区块链,简单介绍了区块链去中心化的结构与其实现原理. 尽管一些人 ...
- 万里长征第一步:Python进程池的一点点小坑
# -*- coding: utf- -*- """ Created on Thu Mar :: @author: lilide """ # ...