12.4.2 自定义 F# 语言

到目前为止,我们所讨论过的序列表达式,都是用 seq 标识符表示,后面的代码块括在大括号中。然而,F# 还允许我们创建自己的标识符,给代码块以特殊的意义。通常,这个功能称为计算表达式(computation expressions),而序列表达式是它的一个特例,是由 F#核心所实现,并经编译器优化。

我们已经知道,计算表达式可以包含标准的语言结构,比如 for 循环,还有别的结构,像 yield。在代码块之前的标识符,描述构造的意义,其方式与查询运算符(例如,Select 和 Where 扩展方法)描述 LINQ 查询所执行的操作,完全相同。这就是说,我们可以创建自定义的计算表达式,用于处理选项值。我们可以用 for 结构处理选项值,但是,F# 提供了更好的自定义表达式的方法,在清单 12.16 中可以看到这些替代方法。第一个版本使用的语法类似于序列表达式;第二个版本功能相同,但方法更自然。

清单 12.16 处理选项值的计算表达式 (F#)

// 使用自定义的 ‘for‘ 基本操作,进行值绑定

option {

for n in tryReadInt() do

for m in tryReadInt() do

yield n * m

}

// 使用专门的 ‘let!‘ 基本操作,进行值绑定

option {

let! n = tryReadInt()

let! m = tryReadInt()

return n * m

}

在计算表达式内部,所有自定义的基本操作(例如,for、yield 和 let!)所发生的行为,由可选(option)标识符决定,它定义了我们所写的计算表达式的种类。现在,我们可以知道,序列表达式就是由 seq 标识符定义的特殊情况。我们将在 12.5 节学习定义标识符,现在,先看一下清单 12.16 中的两个例子。

第一个版本与清单 12.15 中的 LINQ 查询极为相似,每一个 for 循环至少能够执行一次。当选项值包含值时,将分别绑定到符号 n 或 m,并执行循环体。开发人员只希望循环处理集合,而是不处理选项值,而结构 for 和 yield 通常只能用于处理序列。当我们创建计算表达式,处理其他类型值时,将使用后面的语法。第二个版本使用了不止两个计算表达式基本操作,第一个是 let!,表示自定义的值绑定。

在这两个版本中,值 n 和 m 的类型是整数,自定义的值绑定从类型 option<int> 的值中取出实际值。当从TryReadInt 返回的值为 None时,它可能无法把值分配给符号,这样,整个计算表达式将立即返回 None,不会执行其余的代码。表达式中的第二个非标准基本操作是 return,描述了如何从值构建选项值。在清单 12.16 中,我们给它的是整数值,它构造的结果类型是 option<int>。

我们刚才所了解的概念,可以看作是一种函数式的设计模式,使用 F# 计算表达式,可以不要了解模式的所有细节。如果想学习如何自定义计算表达式,了解概念和术语有关的背景知识,是非常有用的。补充材料“计算表达式和单子”更详细地讨论了这种模式,以及它与 Haskell 单子的关系。

计算表达式和单子

我们在前面提到过,F# 中的计算表达式是一种称为单子(monads,一元运算)思想的实现,在 Haskell 中非常有用。单子是数学术语,但 F# 使用了不同的名字,更好地反映了这种思想在 F# 语言中的使用。

当定义计算表达式(或单子)时,我们总是使用泛型类型,比如 M <‘a>,这通常称为单子类型(monadic type),它描述了计算的含义,这种类型能够给我们所写代码增加了含义。例如,刚才我们看到的 option<‘a>,给代码增加了返回未定义值(None)的可能性。序列也是一种形式的单子,类型 seq <‘a> 给代码增加了处理多个值的能力。

每个计算表达式(或单子)是由两个函数,bind 和 return,实现的。bind 能够创建和组合计算,处理单子类型的值。在清单 12.16 中,每当我们使用 let! 基本操作时,就使用了bind  操作。return 用于构造单子类型的值。

值得注意的是,序列表达式也是单的一个实例。对于序列,绑定操作是 Seq.collect,虽然在序列表达式中,我们没有用 let! 语法,而是使用更舒服的 for 循环语法。清单 12.16 展示了两者密切相关。序列的 return 操作创建了只有一个元素的序列。在序列表达式的内部,可以用更自然的 yield 基本操作来写。

在下一节,我们将学习可能是最简单的自定义计算,用 C# 和 F# 来实现,解释单子类型的含义,以及 bind 和 return 操作。

时间: 2024-10-01 06:59:06

12.4.2 自定义 F# 语言的相关文章

12个有趣的C语言问答(详解)

本文参照博文<12个有趣的C语言问答>,在原文的基础上增加来对应的知识点的详细介绍. 1 gets()方法 Q:下面的代码有一个被隐藏的问题,你能找到它吗? 1 #include <stdio.h> 2 3 int main(void) 4 { 5 char buff[10]; 6 memset(buff, 0, sizeof(buff)); 7 gets(buff); 8 printf("%s\n", buff); 9 10 return 0; 11 } A:

12.1.3 使用 F# 序列表达式 在 C# 中的迭代器非常方便(comfortable),能够在普通的 C# 方法中写复杂的代码 (实现 IEnumerable&lt;T&gt;/IEnumerator

12.1.3 使用 F# 序列表达式 在 C# 中的迭代器非常方便(comfortable),能够在普通的 C# 方法中写复杂的代码(实现 IEnumerable<T>/IEnumerator<T> 接口的类型).开发人员写的代码使用标准的C# 功能,比如环,唯一的改变只是我们可以使用一种新的语句,来做一些非标准的事情,这个新语句用 yield return 表示(或者 yield break 表示终止序列),非标准的行为返回序列中下一个元素的值.在以后需要访问序列的时候(最后,计

自定义模板语言整合

这篇文章主要对比一下两大框架Tornado和Django自定义模块语言,以及对Tornado的自定义模块语言进行一个分离整合 首先我们先看一下在Tornado里,我怎么实现的自定义模板语言 第一步,创建UIMethods.py文件,写入自定义方法(第一参数一定为self),创建UIModules.py文件,定义类(必须继承Tornado一个导入类UIModule,通过重写render方法实现) 第二步,注册到settings里 第三步,在模板语言里调用  {{ 函数方法 }}  {% modul

12.5.3 在 F# 中实现计算生成器

在计算表达式块前面的标识符,是类的实例,把所需的操作实现成为实例成员.许多操作都已经有了,我们根本不必要提供所有的,最基本的操作用 Bind 和 Return 成员实现.当 F# 编译器看到计算表达式,比如清单 12.18 时,会把它转换为使用这些成员的F# 代码.F# 示例转换成这样: value.Bind(ReadInt(), fun n –> value.Bind(ReadInt(), fun m–> let add = n + m let sub = n – m value.Retur

12个有趣的C语言面试题及答案

12个C语言面试题,涉及指针.进程.运算.结构体.函数.内存,看看你能做出几个! 1.gets()函数 问:请找出下面代码里的问题: #include<stdio.h> int main(void) { char buff[10]; memset(buff,0,sizeof(buff)); gets(buff); printf("\n The buffer entered is [%s]\n",buff); return 0; } 答:上面代码里的问题在于函数gets()的

《ArcGIS Runtime SDK for Android开发笔记》——(12)、自定义方式加载Bundle格式缓存数据

随着ArcGIS 10.3的正式发布,Esri推出了新的紧凑型缓存格式以增强用户的访问体验.新的缓存格式下,Esri将缓存的索引信息.bundlx包含在了缓存的切片文件.bundle中.具体如下图所示: 对于bundle格式的具体解析,这里就不再详述,具体可以查阅8013是我的博文<ArcGIS for Server 10.3.X 新型紧凑型缓存的解读和应用>,本文内容就是根据其所述实现.再熟悉bundle实现机理后,结合相关加密算法,可以实现进一步缓存数据的加密解密过程. 转载请注明出处:h

12.4.1 自定义查询表达式

原则上,我们可以使用查询处理任何类型,只要它提供了绑定操作.这是函数式编程中这类函数的标准名称,像上一节类型签名所展示的.从技术角度来讲,我们需要实现一些方法,在把查询表达式转换为标准的函数调用,由 C# 编译器所使用.我们将为 12.6 节中的 Option<T> 的类型实现这些方法,该类型没有实现 IEnumerable<T>,所以,不能使用标准查询运算符. 我们首先考虑一下,查询应用到选项类型,是什么意思.清单 12.15 有两个查询,左边的处理列表,右边的处理选项类型.我们

[软件推荐]VMware Workstation 12.1.1多国语言(含简体中文)+激活方法

虚拟机VMware功能强大,使用方便,可以在同一台电脑上安装多个系统(Windows.Linux.OS).虚拟机上的所有操作都不会影响到“实体机”,因此在虚拟机中可以进行很多测试操作,如果某些软件使用上不放心,可先在虚拟机中进行测试,检测无误后再实际使用.VMware目前最新版为12.1.1,现在提供最新的多国语言版(包含简体中文版)下载. VMware Workstation官方网站:点击进入. VMware Workstation 12.1.1官方原版下载:点击下载. VMware Work

自定义模板语言之simple_tag和自定义过滤器

扩展你的模板系统 一般是扩展模板的tag和filter两个功能.可以用来创建你自己的tag和filter功能库. 创建模板库 分为两步: 1. 首先决定由模板库在哪一个注册的app下放置,你可以放在一个已有的app目录下,也可以新建一个专门管理模板库的app,比如python manage.py startapp myTemplateLibrary.推荐后者,因为可以方便将来的重用. 2. 在app目录下创建templatetags子目录,并在里面创建两个文件,__init__.py,用来声明这