12.1.3.1 写序列表达式

在 C# 中,当我们实现返回 IEnumerable<T>、IEnumerator<T>,或对应的非泛型方法时,可以自动使用迭代器。F# 序列表达式使用 seq 标识符显式标记,而且不必要使用方法体或函数体。正如其名字所暗示的,序列表达式是表达式的不同类型,我们可以在代码中的任意位置使用。清单 12.2 演示了使用此语法,创建简单的序列。

清单 12.2 介绍序列表达式的语法 (F# Interactive)

> let nums =

seq { let n = 10    [1]

yield n + 1    [2]

printfn "second.."   [3]

yield n + 2 };;

val nums : seq<int>    [4]

写序列表达式时,我们把生成序列的整个 F# 表达式,括在一个 seq 块中[1]。块使用大括号,在开头使用 seq 标识符 1,表示编译器应该把块的主体解释为序列表达式。在后面我们将会看到,还有其他可能的标识符,指定其他选择性工作流。使用 seq 块,把整个表达式转换为延迟生成的序列,这从推断出的值类型中可以看到[4]。

序列表达式的主体可以包含具有专门含义的语句。与 C# 相类似,有从序列中返回元素的语句;在 F# 中,使用 yield 关键字[2]。主体也可以包含其他标准的 F# 结构,比如值绑定,甚至是执行有副作用的调用[3]。

类似于 C#,序列表达式的主体是延迟执行的。创建序列值(在前面示例中的值 nums)时,序列表达式的主体并不执行;只有访问序列中的元素时,才发生,每次访问一个元素时,序列表达式代码才执行,直到下一个 yield 语句。在 C# 中,访问迭代器中元素,最常用的是 foreach 循环。下面的 F# 示例,我们将使用 List.ofSeq 函数,把序列转换为不可变的 F# 列表:

> nums |> List.ofSeq;;

second..

val it : int list = [11; 12]

返回的列表包含序列生成两个的元素。这就是说,必须计算整个表达式,包括中途的执行 printfn 调用,因此,输出中包含来自序列表达式的打印行。如果我们只从序列中取一个元素,那么,序列表达式只计算到第一个 yield 调用,字符串不会打印出来:

> nums |> Seq.take 1 |> List.ofSeq;;

val it : int list = [11]

我们将使用Seq 模块中的一个序列处理函数,它只从序列中取一个元素。take 函数返回一个新的序列,参数指定元素的数量(示例中是 1),然后终止。我们可以将它转换为 F# 列表,就得到只包含一个元素的列表,但不调用 printfn 函数。

当我们实现序列表达式时,可能会遇到表达式主体太长的情况。在这种情况下,最自然的做法,就是将它拆分成几个生成序列部件的函数。如果序列使用多个数据源,我们可能要有在单独的函数中,读数据的代码。到目前为止,一切顺利,但是,还有一个问题,把从不同函数返回的序列组合起来。

------------------------------

1 你可能会感到奇怪,我们把 seq 称为标识符,而不关键字;后面会看到,它就是标识符(我们甚至可以自己定义),而不是 F# 语言中内置的、专门关键字。seq 标识符也不是由 seq <‘a> 类型自动定义的。名字虽然一样,但是在这里的seq 标识符是不同于由 F# 库定义的符号。

时间: 2024-11-06 22:55:47

12.1.3.1 写序列表达式的相关文章

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 表示终止序列),非标准的行为返回序列中下一个元素的值.在以后需要访问序列的时候(最后,计

12.2.1 递归的序列表达式

函数式编程中主要的控制流结构是递归.我们已经在很多例子中,写的普通函数就使用过递归,它能够解决命令式编程中的循环问题,而不需依赖可变状态.当我们想写一个简单的递归函数时,要使用 let rec 关键字,这样,就能函数以递归方式调用自身. 用于组合序列的 yield! 结构,也可以在序列表达式中执行递归调用,所以,我们同样可以使用函数编程的方法,生成序列.清单 12.4 生成所有的小于 1 百万的阶乘数,与清单 12.1 的 C# 示例一样. 清单 12.4 使用序列表达式生成序列数 (F# In

12.3.2.2 使用查询和序列表达式

在 C# 3.0 中,我们可以使用新的查询表达式语法,写有关映射和筛选数据的操作.查询表达式还支持许多其他操作,但我们会只关注映射和筛选,来演示函数技术和 F# 功能. F# 虽然没有专门提供的查询表达式,但是,使用序列表达式,仍可以轻松地写出映射和筛选数据的查询.这是因为序列表达式在 F# 中所有地方都可以使用,而不仅仅是返回序列的函数.清单 12.9 显示了使用 C# 中的查询和 F# 中的序列表达式,实现我们前面的示例. 清单 12.9 在 C# 和 F# 中的筛选和映射序列 C# F#

12.3.3.1 序列表达式中的平面映射

假设我们有一个关于城市的元组列表,每个元组包含城市的名字和它所在的国家,另外,我们还有一个列表,是用户所选的城市.因此,我们可以这样表示样本数据: let cities = [ ("New York","USA"); ("London", "UK"); ("Cambridge","UK"); ("Cambridge", "USA") ] let e

第十二章 序列表达式和可选工作流

第十二章序列表达式和可选工作流 本章介绍 ■生成和处理序列值 ■处理 F# 序列表达式 ■理解单子和 LINQ 表达式 ■实现 F# 计算表达式 在我们开始讨论序列表达式之前,必须知道什么是序列(sequence),这也是数学的F# 术语.序列是有序的列表,可能包含无穷的元素.这一切听上去有点抽象,但也不用担心,我们已经熟悉这种类型了,在.NET 中表达同样概念的是:IEnumerable<T>. 在.NET 框架中有IEnumerable<T> 类型的主要原因,是它提供一种统一的

12.6 实现选项的计算表达式

在 12.4 节,我们用选项值作为示例,介绍了用 LINQ 查询和 F# 计算表达式创建非标准计算的概念,处理选项值的代码,有自定义的值绑定读取实际值,如同标准值.既然我们已经知道如何转换计算表达式,也就知道我们的 Bind 成员会接收值和 lambda 函数.因为我们处理的是选项类型计算表达式,只有当值是 Some(x) 而不是 None 时,我们才打算执行 lambda 表达式:后一种情况,我们可以立即返回 None. 要运行前面的例子,我们需要在 C# 中实现 LINQ 查询运算符,在 F

解析MYsql写的表达式

今天遇到个问题,Sql中直接写的是复杂表达式,如何解析呢? round(((0.00579049505+0.00006600324*JING_JIE^2*SHU_GAO-0.00000046921*JING_JIE^3*SHU_GAO-0.000183033917*JING_JIE^2-0.000003192879*JING_JIE^2*SHU_GAO*LG(JING_JIE))),4) 可参考 https://www.objecthunter.net/exp4j/apidocs/index.h

深度学习面试题12:LeNet(手写数字识别)

目录 神经网络的卷积.池化.拉伸 LeNet网络结构 LeNet在MNIST数据集上应用 参考资料 LeNet是卷积神经网络的祖师爷LeCun在1998年提出,用于解决手写数字识别的视觉任务.自那时起,CNN的最基本的架构就定下来了:卷积层.池化层.全连接层.如今各大深度学习框架中所使用的LeNet都是简化改进过的LeNet-5(-5表示具有5个层),和原始的LeNet有些许不同,比如把激活函数改为了现在很常用的ReLu. 神经网络的卷积.池化.拉伸 前面讲了卷积和池化,卷积层可以从图像中提取特

x01.os.12: 在 windows 中写 OS

在 windows 中写操作系统,需要一系列的辅助工具.在此,要感谢川谷秀实!所有工具,都在 z_tools 文件夹中.有了大师的帮助,不妨也来尝试在 windows 中写一把 OS. 源代码及工具可到 x01.Lab.Download 中下载.进入 src 文件夹,只有两个文件,一个是 run.bat, 一个是 boot.s.boot.s  都是大同小异的,skip!run.bat 内容如下: ..\z_tools\nask boot.s boot.bin boot.txt ..\z_tool