锁定老帖子 主题:失踪的链环
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-10-08
charon 写道 但是为什么要从行为区分类型?
也许是说函数类型 (相当于函数签名)? inc ( N, 1 ) -> N + 1. 那么函数类型就是 int -> int |
|
返回顶楼 | |
发表时间:2006-10-08
buaawhl同学啊,我这里说的data as procedure和program as data是形而上的适从计算模型上来讨论的,而不是形而下的。因为lambda演算是FP的数学基础,所以FP的程序是可以等价写成lambda计算的。比如
pair(A, B) -> fun(select_head) -> A; (select_next) -> B end. 实际上是一组函数 pair(x,y) = (λf . f(x, y)) select_head(x) = x . first select_next(x) = x . last first(x, y) = x last(x, y) = y 其对应的lambda演算 Pair1 = pair("god", NextElement) -> (λf . f("god", NextElement)) select_head(Pair1) -> Pair1 . first -> (λf . f("god", NextElement)). first -> first("god", NextElement) -> "god" 这里pair携带数据的根本是,把数据变成函数,也就是data as procedure。 而所谓program as data则是从命令语言的计算模型图灵机入手的,图灵机就是一个大大纸带,然后读指令跟着如操作数,因此数据和代码是没有差别的。为了区分他们,才有了不同的段,或者说结构。 |
|
返回顶楼 | |
发表时间:2006-10-08
buaawhl 写道 charon 写道 但是为什么要从行为区分类型?
也许是说函数类型 (相当于函数签名)? inc ( N, 1 ) -> N + 1. 那么函数类型就是 int -> int 应该不是,和当时讨论的上下文好像有点差别。OO以后所谓的类型是一个筐子,duck typing中名字的作用比签名/返回值要重要得多(或者说签名的偶然重复性显然要比名字高很多). 而且, int -> int 这个类型也太宽泛了点,只与签名有关,与语义无关。也许会有某些不用不知道,用了下一跳的效果. |
|
返回顶楼 | |
发表时间:2006-10-08
charon 写道 buaawhl 写道 charon 写道 但是为什么要从行为区分类型?
也许是说函数类型 (相当于函数签名)? inc ( N, 1 ) -> N + 1. 那么函数类型就是 int -> int 应该不是,和当时讨论的上下文好像有点差别。OO以后所谓的类型是一个筐子,duck typing中名字的作用比签名/返回值要重要得多(或者说签名的偶然重复性显然要比名字高很多). 而且, int -> int 这个类型也太宽泛了点,只与签名有关,与语义无关。也许会有某些不用不知道,用了下一跳的效果. 其实当时我说这个说法是不准确的,应该举个例子来说,比如有一个方法 def printStudent(student) put student.name put student.age put student.grade end 对应于非duck typing的语言,必须要这样写: interface Student { String name(); int age(); String grade(); } void print(Student s) { System.out.println(s.name()); System.out.println(s.age()); System.out.println(s.grade()); } 对于duck type,当我增加一个方法 printPerson(person) put person.name put person.age end 我可以 student = Student.new("John", 10, "Grade 1") printStudent(student) printPerson(student) 这里,对于printPerson方法而言,他需要参数能够相应name和age消息,就可以粗略地认为,这里printPerson需要一个具有name和age方法的类型作为参数,对于这个方法而言,所有具有这两个消息的对象,都是同一类型的。因此,duck typing就是说,因为具有行为,从而显现这个类型的特质。 而反观非duck typing,类型是行为的集合,因为参数是这个类型,所以它具有这样的行为。 |
|
返回顶楼 | |
发表时间:2006-10-08
raimundox 写道 buaawhl同学啊,我这里说的data as procedure和program as data是形而上的适从计算模型上来讨论的,而不是形而下的。因为lambda演算是FP的数学基础,所以FP的程序是可以等价写成lambda计算的。比如
pair(A, B) -> fun(select_head) -> A; (select_next) -> B end. 实际上是一组函数 pair(x,y) = (λf . f(x, y)) select_head(x) = x . first select_next(x) = x . last first(x, y) = x last(x, y) = y 其对应的lambda演算 Pair1 = pair("god", NextElement) -> (λf . f("god", NextElement)) select_head(Pair1) -> Pair1 . first -> (λf . f("god", NextElement)). first -> first("god", NextElement) -> "god" 这里pair携带数据的根本是,把数据变成函数,也就是data as procedure。 而所谓program as data则是从命令语言的计算模型图灵机入手的,图灵机就是一个大大纸带,然后读指令跟着如操作数,因此数据和代码是没有差别的。为了区分他们,才有了不同的段,或者说结构。 参数 x, y 也是函数? 按照T1的说法,整数可以用函数执行次数来表示。 lambda演算中的任何基本数据(不仅是复合数据结构),也都可以用函数来表示? 比如,负数,小数,字符? 整数和分数,我都看到例子了。 |
|
返回顶楼 | |
发表时间:2006-10-08
引用 这里,对于printPerson方法而言,他需要参数能够相应name和age消息,就可以粗略地认为,这里printPerson需要一个具有name和age方法的类型作为参数,对于这个方法而言,所有具有这两个消息的对象,都是同一类型的。因此,duck typing就是说,因为具有行为,从而显现这个类型的特质。 不是因为具有行为,而是因为具有名字为xxx/yyy的行为,所以显现zzzzzzz 所以这里和是不是具有某种性质的行为是无关的,只是说具有某种名字的行为。 而静态语言的接口,通常会对其方法的语义加以约束(虽然不能从语法上表示出来,但会通过文档等等) |
|
返回顶楼 | |
发表时间:2006-10-08
FP 没有成员变量。要定义一个数据结构,一般都要用一组 contrustors, selector, operators 函数来表示。
Hash1 = newHashtable(), Hash2 = put(Hash1, "key", "value" ), Hash3 = remove(Hash2, "key"); 具备了 newHashtable, put, remove 这些函数的数据结构,就可以叫做 hashtable 类型。 印象中,haskell里面的 Num Type 好像是这样定义的。确实需要函数名。支持如下函数,就可以称为 Num。 + :: a -> a -> a (可以特化为 int -> int -> int,float -> float -> float ) - :: a -> a -> a (可以特化为 int -> int -> int, float -> float -> float ) ... 等等。 只要有一个数据结构,具备了这些函数定义,就可以叫做 Num 类型。 对 haskell 类型系统不是很熟悉,基本印象如此。 |
|
返回顶楼 | |
发表时间:2006-10-08
charon 写道 引用 这里,对于printPerson方法而言,他需要参数能够相应name和age消息,就可以粗略地认为,这里printPerson需要一个具有name和age方法的类型作为参数,对于这个方法而言,所有具有这两个消息的对象,都是同一类型的。因此,duck typing就是说,因为具有行为,从而显现这个类型的特质。 不是因为具有行为,而是因为具有名字为xxx/yyy的行为,所以显现zzzzzzz 所以这里和是不是具有某种性质的行为是无关的,只是说具有某种名字的行为。 而静态语言的接口,通常会对其方法的语义加以约束(虽然不能从语法上表示出来,但会通过文档等等) 那来的那么罗嗦的事情,duck typing就是一个request/response的过程.走在大街上我见到一个人很像你 于是我叫了一声charon,于是你抛给我一个媚眼.问题是我叫一声猪,你肯定头也不回的往前走.这就是所谓的 "我本将心向明月奈何明月照沟渠" |
|
返回顶楼 | |
发表时间:2006-10-08
charon 写道 不是因为具有行为,而是因为具有名字为xxx/yyy的行为,所以显现zzzzzzz 所以这里和是不是具有某种性质的行为是无关的,只是说具有某种名字的行为。 你这个从理论上讲是不错的,但是从实际上讲毫无意义。比如我们我有一个方法叫getName(),但是我偏偏要返回年龄,这里无论那种语言都无法解决。这个可以用停机定理来说明,停机是某种特定性质的行为,但是这个是不可用程序判定的。因此,也就是说,无论哪种语言,编译器都无法判定某个方法是否具有特定性质的行为。无论smalltalk,ruby,java或是c++,我们所能依赖的只有名字。 从实际意义来看,在smalltalk,ruby等oo语言里,行为就是相应消息,如果可以相应消息就可以看作具有某种行为。 |
|
返回顶楼 | |
发表时间:2006-10-08
buaawhl 写道 参数 x, y 也是函数? 按照T1的说法,整数可以用函数执行次数来表示。 lambda演算中的任何基本数据(不仅是复合数据结构),也都可以用函数来表示? 比如,负数,小数,字符? 整数和分数,我都看到例子了。 有一个取巧的办法....常数函数。f(x) = 1.1,然后我定义符号1.1就是这个函数...这类常数函数也满足所有的lambda计算...形式上可以得到这个基础函数处理基本数据: x = f(x) = define(symbol(x), x) 但实际上在实现fp语言的时候,谁也不会做这个东西,都是直接引入literal常量。 而且磐石T1同学说的是丘奇代数....你可以在丘奇数上定义加减乘等运算...丘奇数跟整数还是有差别的... |
|
返回顶楼 | |