由结构体组成的表与结构体中的表。

在用追溯形式建立家家谱树时,我们通常从某个后代除法,依次处理它的父母,组父母等。而构建树时,我们会不断添加谁是谁的孩子,而不是写出谁是谁的父母,从而建立一颗后代家谱树。

绘制后代数与绘制祖先树一样,只是将所有箭头的方向都反了过来:

(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章 相互引用的数据定义的更多相关文章

  1. MySQL高级查询与编程笔记 • 【第2章 数据定义和操作】

    全部章节   >>>> 本章目录 2.1 数据定义语言和数据操作语言 2.1.1 设计"优乐网"数据库 2.1.2 数据定义语言 2.1.3 数据操作语言 ...

  2. 《how to design programs》12章函数复合

    我们写代码时要学会适应辅助函数.作者提出了一个问题,如何对一个表排序.排序函数读取一个表,产生另一个表.排序函数的合约和用途如下: (sort empty) ;; expected value: em ...

  3. 《how to design programs》14章 再论自引用数据

    这是一个家族谱: ;child(define-struct child (father mother name date eyes)) #lang racket ;child (define-stru ...

  4. 《how to design programs》第11章自然数

    这章让我明白了原来自然数的定义本来就是个递归的过程. 我们通常用枚举的方式引出自然数的定义:0,1,2,3,等等(etc).最后的等等是什么意思?唯一能把等等从描述自然数的枚举方法中去除的方法是自引用 ...

  5. 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 ...

  6. 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化

    第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...

  7. MySQL性能调优与架构设计——第 15 章 可扩展性设计之Cache与Search的利用

    第 15 章 可扩展性设计之Cache与Search的利用 前言: 前面章节部分所分析的可扩展架构方案,基本上都是围绕在数据库自身来进行的,这样是否会使我们在寻求扩展性之路的思维受到“禁锢”,无法更为 ...

  8. C++ Primer Plus 第15章 友元、异常和其它

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/chudaxiakkk/article/details/30502807 第15章 友元.异常和其它 ...

  9. 《Think Python》第15章学习笔记

    目录 <Think Python>第15章学习笔记 15.1 程序员定义的类型(Programmer-defined types) 15.2 属性(Attributes) 15.3 矩形( ...

随机推荐

  1. Qt 学习之路 :Repeater

    前面的章节我们介绍过模型视图.这是一种数据和显示相分离的技术,在 Qt 中有着非常重要的地位.在 QtQuick 中,数据和显示的分离同样也是利用这种“模型-视图”技术实现的.对于每一个视图,数据元素 ...

  2. 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 ...

  3. Sharpdevelop使用StyleCop

    使用Visual Studio时,用resharper+stylecop感觉不错.后来因为单位电脑实在太卡,平时自己写个小片段什么的就用SharpDevelop,这里需要设置一下. 安装StyleCo ...

  4. 给sqlserver配置内存参数

    操作环境:windows server 2003 R2 Enterprise Edition SP1 + 4G 内存 + Sqlsever 2005 在以上环境中,运行公司的ERP数据服务,sqlse ...

  5. css 不确定元素宽度的水平居中

    对于一个不确定宽度的元素居中,我们想到使用的方法是 text-align:center; 或者 margin:0 auto; text-align只对行内元素有效,对于块元素我们要用margin,块元 ...

  6. Java设计模式(学习整理)---工厂模式

    1.工厂模式 1.1 为什么使用工厂模式? 因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时 ...

  7. Cocos2dx开发(1)——Win8.1下 NDK r10 环境搭建

    内容简要:仅讲述NDK在Windows环境下搭建方法,至于NDK何物一概不属于本文内容,老鸟或已有环境的跳过. 笔者已安装的环境: vs2013企业版.谷歌官网adt 22.3.0(推荐)省得自己ec ...

  8. 转载-Linux下svn搭建配置流程

    Linux下svn搭建配置流程     一.    源文件编译安装.源文件共两个,为: 1.   下载subversion源文件 subversion-1.6.1.tar.gz http://d136 ...

  9. 【JQuery学习历程】2.JQuery选择器

    基本选择器 选择器 描述 返回 示例 #id 根据给定的id匹配元素 单个元素 $("#myId") .class 根据给定的class类匹配元素 集合元素 $(".my ...

  10. WPF自定义DataGrid分页控件

    新建Custom Control,名:PagingDataGrid 打开工程下面的Themes\Generic.xaml xaml里面代码替换如下 <Style x:Key="{x:T ...