7.3.1 转换表示

728 篇文章 1 订阅
349 篇文章 0 订阅

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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 爱普生 rc 7.3.1 是一款激光投影机的软件版本。在这个版本中,爱普生对其投影机进行了升级和优化,为用户带来更好的视觉体验。 首先,爱普生 rc 7.3.1 提供了更高的图像分辨率和画质,让投影出的图像更加清晰和细腻。无论是观看电影,还是演示工作中的内容,用户都能够享受到更加逼真的影像效果。 其次,爱普生 rc 7.3.1 还加强了对色彩的控制和调节功能。用户可以根据自己的喜好和需要,进行色彩的调整,以达到最佳的视觉效果。无论是需要更加生动鲜明的色彩,还是更加柔和的色调,都可以通过软件来实现。 此外,爱普生 rc 7.3.1 还提供了更加智能化的操作方式。用户可以通过手机或者电脑等设备,对投影机进行连线,实现远程控制。这样不仅方便了用户的操作,还可以让用户更加自由地控制投影机,享受更好的观影体验。 综上所述,爱普生 rc 7.3.1 是一款功能强大的投影机软件版本。它通过提供更高的图像分辨率和画质,加强色彩控制和调节功能,以及智能化的操作方式,为用户带来更好的视觉体验。无论是在家庭娱乐还是办公展示中,用户都能够受益于这款软件的升级和优化。 ### 回答2: 爱普生 rc 7.3.1 是一个软件版本号,可能指的是爱普生公司的某款产品的软件版本。由于未提供具体产品信息,我不能给出详细的回答,但是一般来说,软件版本号的升级通常包含了修复漏洞、增加新功能和改进性能等方面的内容。 对于用户而言,升级软件版本可以带来多种好处。首先,新版本的软件可能修复之前版本中的一些已知问题和漏洞,提高产品的稳定性和安全性。其次,升级软件版本可能会引入新的功能和特性,提升使用体验和效果。最后,新版本的软件可能针对之前版本的性能问题进行了优化,提高了软件的响应速度和运行效率。 然而,升级软件版本也可能会带来一些问题。例如,旧版本的一些功能可能在新版本中被删除或改变,用户需要重新适应和学习。此外,升级软件也存在风险,可能会导致不兼容问题或引入新的错误。因此,在进行软件升级前,用户应该先了解新版本的改动和可能出现的问题,并评估是否需要升级。 总而言之,爱普生 rc 7.3.1 是一个软件版本号,升级软件版本可能带来修复漏洞、增加新功能和改进性能的好处,但也需要用户谨慎评估是否需要升级,并了解升级可能带来的风险和问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值