7.3.1 转换表示

在我们实现数的据类型之间,存在两个关键的不同:

[两个不同,怎么出现三项]

1、在新的表示形式中,文件是一个(递归)值,而在第一种情况下,是元素的列表。

2、第 7.2 节的数据类型显式包含边框,指定内容的位置。

3、第二个数据类型,只表示各部分是如何嵌套的。

因此,当我们进行表示形式的转换时,需要计算每个嵌套部分的位置。

这些差异影响转换函数的签名,在我们实现之前先分析一下:

val documentToScreen : DocumentPart * Rect-> ScreenElement list

这个函数取的第一个参数是转换的文档部分,返回第 7.2 节中ScreenElement 值的列表,这样,输入的参数值和结果都能表示整个文档;函数的第二个参数,指定整个文档的边框,在转换期间,我们将需要用它来计算每个部分的位置。清单 7.10 的实现,使用了(毫不奇怪)递归函数。

清单 7.10 在文档的表示形式之间进行转换 (F#)

let rec documentToScreen(doc, bounds)=

match doc with

| SplitPart(Horizontal, parts)–>   [1]

let width = bounds.Width/ (float32(parts.Length))   <-- 计算每一部分的大小

parts

|>List.mapi (fun i part ->                           | [2]

let left = bounds.Left + float32(i) * width             |

let bounds = { bounds with Left = left; Width = width }  |

documentToScreen(part, bounds))                   |

|>List.concat             [3]

| SplitPart(Vertical, parts)–>   [4]

let height =bounds.Height / float32(parts.Length)

parts

|>List.mapi (fun i part ->

let top = bounds.Top + float32(i) * height               | 计算行边框

let bounds = { bounds with Top = top; Height = height }   |

documentToScreen(part, bounds))  <-- 递归处理元素

|>List.concat

| TitledPart(tx, content)->    [5]

let titleBounds = {bounds with Height = 35.0f }

let restBounds = {bounds with Height = bounds.Height - 35.0f;

Top = bounds.Top + 35.0f }

let convertedBody =documentToScreen(content, restBounds)  <-- 转换正文,加标题

TextElement(tx,titleBounds)::convertedBody

| TextPart(tx) -> [TextElement(tx, bounds) ]       | [6]

| ImagePart(im) -> [ImageElement(im, bounds) ]  |

我们先从代码的后面开始看,处理表示内容的部分很容易[6],因为只返回包含一个屏幕元素的列表。我们可以使用提供的矩形作为参数值,表示位置和大小,无需更多的计算。

其余部分是由其他部分组成的。在这种情况下,函数递归地调用自己,处理构成更大部分的所有子部分。这是必须进行布局计算的地方,因为当我们再次调用 documentToScreen 时,用子部分和子部份的边框作为参数。我们不能复制 bounds 参数,否则,所有的子部分会在同一地方终结!相反,我们把矩形划分为更小的矩形,每个子部分一个。

TitledPart [5]包含一个子部分,因此,只要进行一次递归调用。在此之前,我们已经计算了标题的边框(前面 35 个像素),和正文的边框(除了前面 35 个像素之外的一切)。接下来,我们递归地处理正文,添加表示标题的 TextElement 到要返回的屏幕元素列表中。

处理 SplitPart,两个方向使用单独的分支[1][4],计算每行或列的大小,并转换它的所有部件。 我们使用 List.mapi 函数[2],它很像 List.map,但它同时提供了当前正在处理部分的索引,可以使用这个索引来计算更小部分边框相对主矩形左上角的偏移量。这个 Lambda 函数然后递归调用 documentToScreen,返回每个文档部件对应屏幕元素的列表。这样,我们得到List.mapi 映射结果列表的列表,结果的类型是 list<list<ScreenElement>>,不是我们需要返回的平面列表,因此,需要使用标准的
F# 库函数List.concat[3],把结果变成list<ScreenElement> 类型的值。

注意

在文档的不同表示形式之间进行转换,是这一章的难点,因此,可能想要下载源代码,并体验看它是如何运行的。最重要(也是最困难)的部分是每次递归调用计算边框。有必要确保能理解函数返回的列表,以及它如何从每次更深的递归调用建立的。我们会发现,用铅笔和纸张完整地走一遍,跟踪矩形边框和返回屏幕元素,是有用的。

不同的表示形式之间的转换,通常是简化函数式编程的关键,因为它能够为实现其他操作的每个部分,找到最适合这种情况的数据结构。我们知道,第一种表示形式适合绘制文档,而第二种形式使构造更简单,同时操作更容易,我们将在 7.4 节讨论。在此之前,我们要介绍另一种表示:XML。

时间: 2024-10-05 01:48:59

7.3.1 转换表示的相关文章

WORD2010如何把全角字母和数字批量转换成半角

个人觉得全角字符看起来相当别扭,如果文档中存在大量全角形式的字母和数字,要如何把它们全部转化成半角的呢? 全角和半角 全角是指一个字符占用两个标准字符位置的状态.汉字字符和规定了全角的英文字符及国标GB2312-80中的图形符号和特殊字符都是全角字符. 半角的显示内码都是一个字节,英文字母.罗马数字.西方语言的符号都是半角形式. END 如何实现全角半角间的转换 全角字符占用更多字符,看起来也不够美观,如何将全角字符转换成半角的呢?这里我们可以利用word来实现.   不论是txt文档还是其他什

经济动能转换现万亿商机,腾讯云造人工智能数字商业

2017年6月,发改委印发<服务业创新发展大纲(2017-2025年)>(以下简称<大纲>),大纲指出我国正处于工业转型升级.新型城镇化推进和消费结构升级的大趋势中.预计到2025年,服务业增加值占GDP比重提高到60%. 根据国家统计局,2016年我国服务业增加值占GDP的比重达到51.6%.按2016年中国74万亿GDP估算,未来8年我国服务业增加值将有6.2万亿的增长空间.而数字经济和数字服务则是服务业增加值新增长的来源,对于企业来说则要把握历史机遇.加快推动数字商业创新发展

JSON与Javabean转换的几种形式

JSON格式的数据传递是最常用的方法之一,以下列出了常用的几种形态以及与Javabean之间的转换: String json1="{'name':'zhangsan','age':23,'interests':[{'interest':'篮球','colors':['绿色','黄色']},{'interest':'足球','colors':['红色','蓝色']}]}"; String json2="[{'name':'zhangsan'},{'name':'lisi'},{

myasql支持的数据类型以及函数转换

myasql支持的数据类型 1.数值类型 tinyint 1 小整数 smallint 2 大整数 mediumint 3 大整数 int 4 大整数 bigint 8 极大整数 如果插入 的较大较小 会自动改编为范围值 多余的数截取 float 4 double 8 decimal 默认是10 可以指定多少个整数和小数 2.字符串类型 char 0-255字节 定长字符串 varchar 0-255字节 变长字符串 tinyblob 0-255字节 不超过255个字符的二进制字符 tintex

zzuli oj 1134 字符串转换

题目链接: https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1134 Description 输入一个以回车结束的字符串,它由数字和字母组成,请过滤掉所有非数字字符,然后将数字字符串转换成十进制整数后乘以2输出. Input 输入一个以回车结束的字符串,长度不超过100,由数字和字母组成. Output 将转换后的整数乘以2输出,测试数据保证结果在int范围内. Sample Input sg987aa65t498 Sample Output 1

Date常用转换、比较

在项目开发过程中,遇到了一个需要把本年本月的充值超过1000元的用户都获取出来,但是我数据库时间存的是int类型.所以不知道where的条件语句怎么写,特此查了一下,再此总结一下,希望对需要的朋友能有所帮助. 总体思想是获取出来本月初和本月末的时间转化成int在where查询条件为之间的值. 引发出的问题:1) java获取当前系统时间 2)获取月初的月末的时间 3)时间格式转化成int 3. 时间转化用到的两个类 import java.util.Calendar; (日历) import j

关于raw_input输入中文时的编码转换

今日在敲代码时出现了如下问题 中文的编码出现了问题(在键盘输入中文时也会出现同样的问题),中文的编码应该是utf-8编码格式,有以下两种方式来进行编码转换: (1)decode用法:str  -> decode('the_coding_of_str') -> unicode 即写为格式:raw_input('净利润为:'.decode('utf-8').encode('gbk')) (2)encode用法:unicode -> encode('the_coding_you_want')

C#中图片.BYTE[]和base64string的转换

在C#中 图片到byte[]再到base64string的转换: Bitmap bmp = new Bitmap(filepath); MemoryStream ms = new MemoryStream(); bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Gif); byte[] arr = new byte[ms.Length]; ms.Position = 0; ms.Read(arr, 0, (int)ms.Length); ms.Clo

js中汉字utf8编码互相转换

//UTF字符转换var UTFTranslate = {Change:function(pValue){return pValue.replace(/[^\u0000-\u00FF]/g,function($0){return escape($0).replace(/(%u)(\w{4})/gi,"&#x$2;")});},ReChange:function(pValue){return unescape(pValue.replace(/&#x/g,'%u').rep

Day2-字符编码转换

1.在python2默认编码是ASCII, python3里默认是unicode 2.unicode 分为 utf-32(占4个字节),utf-16(占两个字节),utf-8(占1-4个字节), so utf-16就是现在最常用的unicode版本, 不过在文件里存的还是utf-8,因为utf8省空间 3.在py3中encode,在转码的同时还会把string 变成bytes类型,decode在解码的同时还会把bytes变回string python2支持以下图: Python2# vim en