posts - 176, comments - 240, trackbacks - 0, articles - 7

关于函数式语言的只言片语

Posted on 2007-12-05 22:09 canonical 阅读(4271) 评论(9)  编辑  收藏 所属分类: 设计理论
1. 函数式语言可以合理的看作是泛函分析思想的一种体现,从历史发展的时间上看大概也是具有这种可能性的。在Backus的论文中对函数式语言的一种乐观的情绪甚至扩大到functional algebra can be used to tranform programs and to solve equations whose "unknowns" are programms in much the same way one transform equations in high school algebra。这种信心只能来源于泛函分析和方程论,来自于数学分析学的发展。将函数的函数作为分析对象就构成泛函分析。泛函分析的最核心的思想当然不等价于它所研究的那些无穷维空间,不等价于种种正交基的构造。它的思想核心在于函数的函数具有独立的分析价值,具有脱离数量空间的具体的结构。这也是函数式语言试图推销的一种理念。


2. 最近这些年来一种称为"范畴"(Category)的东西在计算机理论研究中频频出现。范畴论是从同调代数发展而来的一种较新的代数语言,但它显然也不是可以解决任何问题的灵丹妙药。多一种表达方式当然在某种程度上可以增进我们的理解。但是范畴本身只是研究一种基础结构,它本身并没有承载所有的物理事实,基于它不可能对所有的规律一网打尽。不是明白了范畴,就懂了程序。范畴论是一种基础性的语言,有些人致力于基于范畴论来构建数学的其他分支,取代集合论的地位。将计算的本质重新归结于范畴论是无意义的,它不过是对事实的另一种陈述方式。说“函数式语言是基于范畴”是无意义的,因为这和说“所有现代数学都基于集合论”一样。无法发现新的相互作用关系,所有的概念都只是同义反复。不是一拿起数学,就找到了组织。

3. 我对函数式语言并没有什么反对意见。它是非常重要也非常优美的一种技术思想。但是现在一些函数式语言的狂热支持者似乎对函数世界充满了乌托邦式的幻想,一种大一统的世界观让人迷醉,但是它却解决不了现实的问题。所以我说无法认同函数式编程的世界观。作为一种具体的技术工具,问题不在于函数式语言是否体现了计算的本质,而在于它是否向我们提供了称手的兵器。现在我要计算两个小球相互碰撞的问题,我可以操起广义相对论,量子力学啥的开始大干一场,也可以用个牛顿力学小试牛刀,甚至可以只用反射关系摆个等式。但是在绝大多数情况下我们都会说这里面的物理是弹性反射而不是相对论。在理论分析中我们经常使用平面波假设,但只要实际关心的对象不在波包的边缘,没有人会认为平面波不是真实的物理机制。理论物理不是理想物理。在具体的参数设定下,我们只会使用特定的物理学。
   对世界的认识并不是非此即彼的。并不是说函数式语言好它就永远都好,要把所有对立面都灭掉。也不是说函数式不好,命令式就必然的好,就必然的能够解决问题。函数式语言的世界观过分单纯而排他,这是我反对的,我同样无法认同面向对象的本体论论调。就像CISC和RISC架构之争一样,最终我们在现实的物理约束下,运行的最好的芯片是两者思想的结合。这是我们面对物理世界的基本态度。
  
4. 函数式语言中时间是个有趣的概念。命令式语言中因为赋值语句的存在,使得我们可以观测到状态的变化,因此必然要定义时间。而函数式语言是无状态的,可以是无时间概念(对Lazy Caculation的依赖是否体现了深层次上对时间概念的需求?)。有些人认为函数可以看作是相空间中的迁移函数,是与相对论协调的,因而反映了时间的本质等等。相对论主要是解决了物理规律的协变性的问题,在此过程中它使人们认识到了时空之间奇异的对称性。但是广义相对论的表述中时间也是可逆的。真正定义了时间之箭的是热力学第二定律。根据Landauer's principle: 擦除(erase)1比特信息,耗散到环境中的能量至少是k*T*ln2, 或者说熵增至少是k*ln2. 这意味着只要我们对眼前的黑板不停的写了擦,擦了写,就必然无法回到过去。物理世界是复杂的。

5. 如果将状态看作是可以附着在某个对象上的标记,显然状态的存在性便于我们识认概念的唯一性。对象还是那个对象,只是状态标记发生了变化。而如果系统中没有状态,则必然产生了一个新的概念。这在很多情况下是不必要的负担。状态的存在使得系统在局部结构上允许出现非常复杂的变化,函数式编程的拥趸们对此多有诟病。但是从另一个方面上说,状态使得我们可以基于局部信息处理很多问题而不需要把它扩大化为一个全局匹配问题。

6. 函数构成函数似乎是很完备统一的世界。 但是在物理世界中发生的一切却复杂的多。虽然世界可以还原为原子,但是原子构成分子,分子构成宏观物质时,系统的基本性状发生了本质性的变化,并不再是统一的形式。每一个层面上都会产生独立的结构规律。

7. 函数式语言和命令式语言的计算能力相同(可以相差一个任意长度的多项式时间),但是在具体的情形下它们的描述能力是不同的。我所关心的不是语言层面的问题,因为语言本身的能力并不足以解决现实开发中的所有问题。即现实开发中所需要处理的结构问题并不是在语言层面得到充分解决的,这是我们需要做工作的地方。
   关于现实中的结构问题,我无意去定义什么万能的描述能力。你可以用微分几何,积分几何,广义变分等等手段去证明圆盘是某种意义下的周长最短的东西,但是这一切对你发明轮子并无本质上的助益。不过可以说说现实中的结构。这里不是要证明某种语言中无法描述这些结构,而是说结构是客观存在的,它并不是要在基础语言层面得到充分解决的。实际上现在的通用语言也是无法有效承载Domain Specific Structure的。
A. ErLang大概是目前世界上应用最为深入的函数式语言了。它确实发挥了函数式语言无显式状态变量的优势。但是它对程序构建本质上的帮助更多的来源于无共享的超轻量级进程模型,相当于定制了一般操作系统所提供的基本服务。微软的一个实验性操作系统项目Singularity, 其中也定义了只通过消息传递发生数据关联的超轻量级进程模型,它使用C#的一个扩展语言,额外增加的功能是消息管道上定义的规格状态机,对消息交互的时空模式进行额外的规约。这里对我们真正有价值的是隔离的单元结构。
B. AOP是程序结构空间中的定位和组装技术。在Witrix中我们规范化了切点处的状态空间,并对AOP进行了偏置处理.这种结构调整大大提高了AOP的可用性,使得它成为Witrix中的核心技术手段之一。
C. 面向对象的继承关系从结构观点上看是两个一维集合之间的覆盖关系。在Witrix中扩展了extends所对应的结构操作,创造了新的结构融合手段。

Feedback

# re: 关于函数式语言的只言片语  回复  更多评论   

2007-12-05 22:26 by POPPC
讲的不错,支持一下

# re: 关于函数式语言的只言片语  回复  更多评论   

2007-12-05 22:47 by 翻译公司
看不懂,但鼓励一下。
http://www.xinhua001.com北京翻译公司

# re: 关于函数式语言的只言片语  回复  更多评论   

2007-12-06 08:39 by bonny
我来看以下什么牛人能写这样的文章

深刻暂时还不能论定
广博倒是有的

# re: 关于函数式语言的只言片语[未登录]  回复  更多评论   

2007-12-06 08:54 by dennis
其他不敢讲,不过函数式语言无时间概念值的商榷,通过延时求值实现的stream本质上也是种时间概念。再说Erlang,在函数式语言里,会自动分析函数并找出适合并行执行的候选函数简单的像自动进行的函数内联化,也就是说函数式语言天生就是适宜并行的,如果仅仅是轻量级进程结构,这也达不到Erlang的无锁结构。

# re: 关于函数式语言的只言片语  回复  更多评论   

2007-12-06 21:09 by canonical
1. 语言中的时间观念这个论题绝对不是我的原创
2. 我一直强调思维的连续性。不是说"B这样搞来搞去还是达不到A的高度", 而是说我们如果把系统的特征逐个分解,到底需要做哪些工作才能逐步增加最有价值的部分,特征聚集产生的增值部分又是如何显现的。
3. 一种实现总是包容了太多的思想。思想错了,实现对了。实现死了,思想活着。

# re: 关于函数式语言的只言片语  回复  更多评论   

2009-08-06 17:23 by forrestju
理想的编程语言 鞠文广

以下纯粹是个人观点, 不代表任何组织或社团.

现在流行的编程语言如Java和C#, 大多是面向对象的, 程序的各部分是通过方法调用连在一起, 其编程范式是命令编程, 即使支持其他范式也包装得很难理解和使用.

面向对象实际上只适合实现抽象数据类型, 让它去完成除此之外的任务确实是勉为其难, 即便能完成也给人不伦不类的感觉, 既不像面向对象编程, 也不像它的前任(过程编程). 这些语言中的对象与物质世界的物质(或对象)很不一致, 它使用方法调用的方式与其他对象进行相互作用, 而这与物质之间的(通过通信或媒介)相互作用是截然不同的, 因此用面向对象无法很确切地模拟现实世界(面向对象思想的初衷), 更不用说准确地为现实世界建立模型.

这几年流行的web服务和SOA虽使程序间交互更方便, 但它从本质上说还是使用”面向对象+命令编程+方法调用”的思路, 在编程方法论上并没有实质的进步.

用现在流行的语言实现的完成复杂功能的程序逻辑不清晰, 原因在于”命令编程+方法调用”的设计机制. 这使程序很难模块化, 副作用无所不在, 因此很难正确实现复杂功能.

现实世界的发展变化是通过事物间的相互作用实现的, 而这种相互作用用计算机科学的语言来说就是并发(concurrency). 软件的本质是什么? 我觉得:软件总是完成某种功能的,归根到底是对现实世界的事物间相互作用进行建模. 因此软件的组成部分间自然就是并发的关系, 而不是过程调用的关系. 用通信进程来对现实世界的事物间相互作用进行建模是比较合理的. 所以进程应该作为语言的基础成分, 是软件的基本组成部分, 而不是只为了提高效率才采用的.

为了使程序能准确地为现实世界建立模型, 从而正确性更高, 结构更合理, 模块化程度更高, 因此在几种编程思想或语言的基础上(见references), 我提出一种新的编程方法论: 面向进程+函数编程+进程间通信+逻辑编程+约束编程+其他合理的范式(命令编程除外)和一门编程语言ProcessLog (全称process logic).

ProcessLog只支持一种并发:通信进程. 它就是计算机科学家在上世纪70年代为了克服现在的Java中仍采用的那种并发方式的缺点而提出的. 它是经过充分研究得到的一种理想并发方式, 看了并发理论(concurrency)和进程代数(Process algebra), 就会明白这种并发方式可解决实际中的各种并发问题, 用它足够了.

这里的进程是进程代数的进程,不是过程,也不是Java中的线程. 看看jcsp或Hoare的CSP(http://www.usingcsp.com/)就明白了.推荐网址:
http://www.cs.kent.ac.uk/projects/ofa/jcsp/,
其中有两个ppt说得很明白:
"Process Oriented Design for Java: Concurrency for All",
"Communicating Processes, Components and Scaleable Systems".

ProcessLog的语法概要如下:

1 运算符
(1) ? 输入; c ? x 从输入端口c或通道c上接收输入值放到变量x中
(2) ! 输出; c ! v 把v的值从输出端口或通道c上输出
(3) -> 顺序进行的事件的先后关系
(4) | b : s 分支
(5) || 进程并行
(6) // 附属进程
(7) and, or, not 逻辑运算符
(8) 算术运算符和关系运算符 与Java中相同

2 程序的组成成分
(1) Unit 程序单元
(2) Process 进程
(3) Function 函数
(4) Predicate 谓词
(5) Channel 通道, 有两个端口: in 输入端口, out 输出端口
(6) OutPort 输出端口
(7) InPort 输入端口

3 数据结构
(1) List (函数编程中的List类型, 对List的操作函数与函数编程中相同);
(2) Tuple 元组, 同Clean.
(3) Set 集合
没有数组

4 进程的定义
Process p1 (OutPort pt1, InPort pt2 ){
pt2?x -> pt1! compute(x) -> p1
}

5 进程间相互作用
(1) 进程并行 process1( c1.out, c2.in)|| process2(c1.in, c2.out)
(2) 附属进程 (getE: getElements || getR: getReleasedVersion) // X.(in?method -> getE ! method ? elems -> getR ! em ? rem-> … ->X)

6 函数
[Function] compute(double x)=
| x<=0: x*x+3
| x>0: compute(x-5)* compute(x-3)
函数只能以事件的方式在进程中使用或在其他函数中使用, 不能独立使用.

7 谓词
/* 建图 */
Predicate createGraph(t, graph):-
addNode(t, null, ({},{}), graph1),
getDS(t, graph1.ns, tlist),
addList(tlist, t, graph1, graph).
/* 加节点 */
Predicate addNode(t, null, (ns, es), (ns1, es):-
merge(ns, {t}, ns1).
Predicate addNode(t, upper, (ns, es), (ns1, es1)):-
merge(ns, {t}, ns1),
merge(es, {(upper, t)}, es1).

8 把谓词转换为函数
create(t)= graph
where createGraph(t, graph)

谓词不能独立使用也不能在进程中直接使用, 要在进程中使用需要先转换为函数.

9 程序单元: 包含进程和数据类型
Unit PmethodDAO;
interface
Tuple Method;
Process getLastVersion(OutPort pt1 , InPort pt2);

implementation
Method=(String id, String name, String version);
Process getLastVersion(OutPort pt1 , InPort pt2){

}

指导原则: 程序是由通过通道通信的进程组成的. 数据处理和算法用函数编程实现, 如果函数编程不适用于要处理的问题, 就使用逻辑编程或约束编程.

ProcessLog语言限制了编程的随意性, 要求只能用进程代数+函数编程+逻辑编程的方式编程, 不允许用Java或c#的命令方式编程.

ProcessLog 现在还没有在机器上实现. 我用该语言重写了实际项目中的一些复杂代码(原是Java代码), 证实用它写的程序确实简单清晰, 有类似数学的简洁美. "7 谓词"就是其中一部分代码.

我的想法是: 应先在纸面上规定它的语法与语义, 再通过使用它编写一些应用程序来发现它的不足,再进而改进它, 再实践, 再改进, 直到它基本完善再在机器上实现. 另外, 大家不要把语言分为中国人提出的还是外国人提出的, 科学无国界, 这里不存在狭隘的爱国主义. 我不是那种技术高手, 但我自信我是一个能将理论很好地联系实践的研究者.

希望有识之士和我一起共同发展这种编程方法论和这门语言.
juwenguang2000@yahoo.com.cn

References
1. CSP http://www.usingcsp.com/
2. JCSP http://www.cs.kent.ac.uk/projects/ofa/jcsp/
3. Clean http://clean.cs.ru.nl/
4. Prolog
5. Delphi

注: 转载时请注明作者.

# re: 关于函数式语言的只言片语[未登录]  回复  更多评论   

2009-11-01 16:06 by X
bingo!

函数式本质上是逻辑表达,而命令式是状态迁移的表达方式。
函数式中只有符号,没有变量,每个符号对应一个概念,而概念当然是没有状态的。

# re: 关于函数式语言的只言片语  回复  更多评论   

2009-11-12 09:02 by LoongWalker
我也曾学习过软件形式化与自动化的一些相关知识,很佩服贴主的勇气,但正是基于此种钦佩,我不得不说一说自己的一点观点,如果有一点点道理,那就希望会有点帮助。
我认为,任何一种真正有生命力,可以流传开来,并于是能够解决大量实际问题的工具一定有几个共同的特点:简单、条理、一致性、有秩序、虽然有悖论但其作用可以控制在很小的范围内。
贴主的这种将几种现有理论做杂凑,按照问题情况选用不同工具来处理的做法,我实在不敢苟同。如果能够将各种工具的内部构造图(其内部概念结构和关系)各自打开,找到其共同边界,进而做融合而非杂凑,或许效果更佳。
一点浅论,荒谬之处,望多多交流,LoongWalker@gmail.com

# re: 关于函数式语言的只言片语  回复  更多评论   

2013-11-01 11:12 by newskying
支持,“少谈些主义,多解决问题”

只有注册用户登录后才能发表评论。


网站导航: