《how to design programs》15章 相互引用的数据定义
由结构体组成的表与结构体中的表。
在用追溯形式建立家家谱树时,我们通常从某个后代除法,依次处理它的父母,组父母等。而构建树时,我们会不断添加谁是谁的孩子,而不是写出谁是谁的父母,从而建立一颗后代家谱树。
绘制后代数与绘制祖先树一样,只是将所有箭头的方向都反了过来:
(define-struct parent (children name date eyes))
children数量不固定,怎么办?
自然的选择是另children代表由parent结构体组成的表,这个表代表孩子,
parent是结构体:
(make-parent loc n d e) loc是孩子的表。
不幸的是,这个数据定义违反了我们关于定义的标准,具体说,他提到了一个还没定义的集合:孩子的表。
既然无法在不知道孩子的表示什么的情况下定义父母类型,我们就先定义孩子的表:
list of childrens 是下列之一
1 empty
2 (cons p loc);其中p是parent,loc是孩子的表。
第二个定义时标准的,但是他遇到和parent一样的问题。
结论是,这2个定义在相互引用对方,他们只在同时定义的情况下才有意义:
hen two (or more) data definitions refer to each other, they are said to be MUTUALLY RECURSIVE or MUTUALLY REFERENTIAL. 如果2个或更多的数据定义相互引用,我们就称他们为相互引用的。
现在,我们可以把上图中的家谱树转成scheme表达式了,当然,在建立parent结构体之前,必须先定义所偶有表示其孩子的阶段,最好的方法是,在使用某个parent结构体之前先给他命名,如:
(define Gustav (make-parent empty 'Gustav 1988 'brown)) (make-parent (list Gustav) 'Fred 1950 'yellow)
To create a parent
structure for Fred, we first define one for Gustav so that we can form (list Gustav)
, the list of children for Fred.
完整定义:
;; Youngest Generation:
(define Gustav (make-parent empty 'Gustav 1988 'brown)) (define Fred&Eva (list Gustav)) ;; Middle Generation:
(define Adam (make-parent empty 'Adam 1950 'yellow))
(define Dave (make-parent empty 'Dave 1955 'black))
(define Eva (make-parent Fred&Eva 'Eva 1965 'blue))
(define Fred (make-parent Fred&Eva 'Fred 1966 'pink)) (define Carl&Bettina (list Adam Dave Eva)) ;; Oldest Generation:
(define Carl (make-parent Carl&Bettina 'Carl 1926 'green))
(define Bettina (make-parent Carl&Bettina 'Bettina 1926 'green))
Figure : A Scheme representation of the descendant family tree
现在我们来研究blue-eyed-descendent?的开发,他是blue-eyed-ancestor的自然对应物,该函数读入一个parent结构体,判断他或货代是否有眼睛是蓝色的。下面的有点难,我最开始试图只用一个函数来搞定,发现始终不行,看了答案才知道:
;; blue-eyed-descendant? : parent -> boolean
;; to determine whether a-parent any of the descendants (children,
;; grandchildren, and so on) have 'blue in the eyes field
(define (blue-eyed-descendant? a-parent)
(cond
[(symbol=? (parent-eyes a-parent) 'blue) true]
[else (blue-eyed-children? (parent-children a-parent))])) ;; blue-eyed-children? : list-of-children -> boolean
;; to determine whether any of the structures in aloc is blue-eyed
;; or has any blue-eyed descendant
(define (blue-eyed-children? aloc)
(cond
[(empty? aloc) false]
[else
(cond
[(blue-eyed-descendant? (first aloc)) true]
[else (blue-eyed-children? (rest aloc))])]))
;; blue-eyed-descendant? : parent -> boolean
;; to determine whether a-parent any of the descendants (children,
;; grandchildren, and so on) have 'blue in the eyes field
(define (blue-eyed-descendant? a-parent)
(or (symbol=? (parent-eyes a-parent) 'blue)
(blue-eyed-children? (parent-children a-parent)))) ;; blue-eyed-children? : list-of-children -> boolean
;; to determine whether any of the structures in aloc is blue-eyed
;; or has any blue-eyed descendant
(define (blue-eyed-children? aloc)
(cond
[(empty? aloc) false]
[else (or (blue-eyed-descendant? (first aloc))
(blue-eyed-children? (rest aloc)))]))
Figure : Two programs for finding a blue-eyed descendant
Exercise 15.1.2. Develop the function how-far-removed
. It determines how far a blue-eyed descendant, if one exists, is removed from the given parent. If the given parent
has blue eyes, the distance is 0
; if eyes
is not blue but at least one its children's eyes are, the distance is 1
; and so on. If no descendant of the given parent
has blue eyes, the function returns false
when it is applied to the corresponding family tree. Solution
;; A parent is a structure: (make-parent loc n d e)
;; where loc is a list of children,
;; n and e are symbols, and d is a number.
(define-struct parent (children name date eyes)) ;; A list of children is either
;; . empty or
;; . (cons p loc) where p is a parent and loc is a list of children. ;; EXAMPLES OF DATA
(define robby (make-parent empty "Robby" 'blue))
(define ted (make-parent empty "Ted" 'brown))
(define pat (make-parent empty "Pat" 'brown))
(define pete (make-parent empty "Pete" 'brown))
(define alice (make-parent (list robby ted pat pete) "Alice" 'blue))
(define bill (make-parent (list robby ted pat pete) "Bill" 'brown))
(define lolly (make-parent empty "Lolly" 'blue))
(define tutu (make-parent (list alice lolly) "Tutu" 'brown)) ;; how-far-removed : parent -> number or false
;; to find the distance to the nearest blue eyed descendent
;; or return false if there is no such descendant
(define (how-far-removed a-parent)
(cond
[(symbol=? 'blue (parent-eyes a-parent))
]
[else
(add1/false
(how-far-removed-children
(parent-children a-parent)))])) ;; how-far-removed-children : list of children -> number or false
;; to find the nearest blue eyed descent for a list of children,
;; assuming that one exists
(define (how-far-removed-children children)
(cond
[(empty? children) false]
[else (min/false (how-far-removed (first children))
(how-far-removed-children (rest children)))])) ;; add1/false : number or false -> number or false
;; to add one to a number, or return false
(define (add1/false n)
(cond
[(number? n) (+ n )]
[else false])) ;; min/false : (number or false) (number or false) -> (number or false)
;; to compute the minimum number of two numbers
;; if both are numbers, find the minimum.
;; if only one is a number, return that.
;; if both are false, return false.
(define (min/false n m)
(cond
[(and (number? n) (number? m)) (min n m)]
[(and (number? n) (boolean? m)) n]
[(and (boolean? n) (number? m)) m]
[(and (boolean? n) (boolean? m)) false])) ;; EXAMPLES AS TESTS
(how-far-removed ted) "should be" false
(how-far-removed robby) "should be"
(how-far-removed alice) "should be"
(how-far-removed bill) "should be"
(how-far-removed tutu) "should be"
Exercise 15.1.3. Develop the function count-descendants
, which consumes a parent and produces the number of descendants, including the parent.
Develop the function count-proper-descendants
, which consumes a parent and produces the number of proper descendants, that is, all nodes in the family tree, not counting the parent. Solution
(define (count-descendants a-parent)
(cond
[(empty? (parent-children a-parent)) ]
[else (+ (count-children (parent-children a-parent)))]
)
) ;; count-children : list-of-children -> number
;; consumes a list-of-children c
;; produces the number of parents in c
(define (count-children a-loc)
(cond
[(empty? a-loc) ]
[else (+ (count-descendants (first a-loc))
(count-children (rest a-loc)))])) (count-descendants Eva)
(count-descendants Carl)
(define (count-proper-descendants a-parent)
(count-children (parent-children a-parent))
)
Exercise 15.1.4. Develop the function eye-colors
, which consumes a parent and produces a list of all eye colors in the tree. An eye color may occur more than once in the list.
Hint: Use the Scheme operation append
, which consumes two lists and produces the concatenation of the two lists. Solution
;; eye-colors : parent -> list
;; consumes a parent and produces a list of all eye colors in the tree
(define (eye-colors a-parent)
(cons (parent-eyes a-parent) (children-eyes (parent-children a-parent)))
) (define (children-eyes a-loc)
(cond
[(empty? a-loc) empty]
[else (append (eye-colors (first a-loc))
(children-eyes (rest a-loc))
)
]
)
)
(eye-colors Carl)
相互递归
为相互引用的定义设计函数:
在上述例子中,我们需要2个相关的定义:
Templates:The templates are created in parallel, following the advice concerning compound data, mixed data, and self-referential data. Finally, we must determine for each selector expression in each template whether it corresponds to a cross-reference to some definition. If so, we annotate it in the same way we annotate cross-references.
Here are the templates for our running example:
模板被并行地创建。
fun-parent模板中没有条件,因为parent的数据定义中并不包含任何子句,而是包含对第二个模板的相互引用:处理parent结构体中的chidlren字段。按照同样的规则,fun-children是一个条件式,第2个cond子句中包含了一处自引用,处理表的rest部分,以及对表的first元素,即parent结构体-的一处相互引用。
对数据定义和模板的比较表明了他们是多么的类似。
15.3 网页再谈
《how to design programs》15章 相互引用的数据定义的更多相关文章
- MySQL高级查询与编程笔记 • 【第2章 数据定义和操作】
全部章节 >>>> 本章目录 2.1 数据定义语言和数据操作语言 2.1.1 设计"优乐网"数据库 2.1.2 数据定义语言 2.1.3 数据操作语言 ...
- 《how to design programs》12章函数复合
我们写代码时要学会适应辅助函数.作者提出了一个问题,如何对一个表排序.排序函数读取一个表,产生另一个表.排序函数的合约和用途如下: (sort empty) ;; expected value: em ...
- 《how to design programs》14章 再论自引用数据
这是一个家族谱: ;child(define-struct child (father mother name date eyes)) #lang racket ;child (define-stru ...
- 《how to design programs》第11章自然数
这章让我明白了原来自然数的定义本来就是个递归的过程. 我们通常用枚举的方式引出自然数的定义:0,1,2,3,等等(etc).最后的等等是什么意思?唯一能把等等从描述自然数的枚举方法中去除的方法是自引用 ...
- Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式
Linux就这个范儿 第15章 七种武器 linux 同步IO: sync.fsync与fdatasync Linux中的内存大页面huge page/large page David Cut ...
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...
- MySQL性能调优与架构设计——第 15 章 可扩展性设计之Cache与Search的利用
第 15 章 可扩展性设计之Cache与Search的利用 前言: 前面章节部分所分析的可扩展架构方案,基本上都是围绕在数据库自身来进行的,这样是否会使我们在寻求扩展性之路的思维受到“禁锢”,无法更为 ...
- C++ Primer Plus 第15章 友元、异常和其它
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/chudaxiakkk/article/details/30502807 第15章 友元.异常和其它 ...
- 《Think Python》第15章学习笔记
目录 <Think Python>第15章学习笔记 15.1 程序员定义的类型(Programmer-defined types) 15.2 属性(Attributes) 15.3 矩形( ...
随机推荐
- Qt 学习之路 :Repeater
前面的章节我们介绍过模型视图.这是一种数据和显示相分离的技术,在 Qt 中有着非常重要的地位.在 QtQuick 中,数据和显示的分离同样也是利用这种“模型-视图”技术实现的.对于每一个视图,数据元素 ...
- Fix java version mismatch in windows---stackoverflow
Question: I have the 64bit version of the jdk installed on windows 7. I installed the 32 bit version ...
- Sharpdevelop使用StyleCop
使用Visual Studio时,用resharper+stylecop感觉不错.后来因为单位电脑实在太卡,平时自己写个小片段什么的就用SharpDevelop,这里需要设置一下. 安装StyleCo ...
- 给sqlserver配置内存参数
操作环境:windows server 2003 R2 Enterprise Edition SP1 + 4G 内存 + Sqlsever 2005 在以上环境中,运行公司的ERP数据服务,sqlse ...
- css 不确定元素宽度的水平居中
对于一个不确定宽度的元素居中,我们想到使用的方法是 text-align:center; 或者 margin:0 auto; text-align只对行内元素有效,对于块元素我们要用margin,块元 ...
- Java设计模式(学习整理)---工厂模式
1.工厂模式 1.1 为什么使用工厂模式? 因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时 ...
- Cocos2dx开发(1)——Win8.1下 NDK r10 环境搭建
内容简要:仅讲述NDK在Windows环境下搭建方法,至于NDK何物一概不属于本文内容,老鸟或已有环境的跳过. 笔者已安装的环境: vs2013企业版.谷歌官网adt 22.3.0(推荐)省得自己ec ...
- 转载-Linux下svn搭建配置流程
Linux下svn搭建配置流程 一. 源文件编译安装.源文件共两个,为: 1. 下载subversion源文件 subversion-1.6.1.tar.gz http://d136 ...
- 【JQuery学习历程】2.JQuery选择器
基本选择器 选择器 描述 返回 示例 #id 根据给定的id匹配元素 单个元素 $("#myId") .class 根据给定的class类匹配元素 集合元素 $(".my ...
- WPF自定义DataGrid分页控件
新建Custom Control,名:PagingDataGrid 打开工程下面的Themes\Generic.xaml xaml里面代码替换如下 <Style x:Key="{x:T ...