• 理想的编程语言


    理想的编程语言 鞠文广

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

    关键词: 进程代数 函数编程 逻辑编程

    摘要: 由于现有语言不能很好的为现实世界建模, 我提出一种编程方法论和编程语言ProcessLog. 它的编程思想是"面向进程 + 函数编程+ 逻辑编程等", 用它写的程序的软件体系结构很清晰, 程序简洁优美, 程序的正确性容易用数学推理证明, 适用于各种领域.

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

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

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

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


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

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

    ProcessLog只支持一种并发:通信进程. 因其他并发机制要么不够理想, 存在不能接受的缺陷(Java中的monitor机制, Erlang中的Actor); 要么很难应用于实际(CSP的通道(channel)通信). 这种并发机制是我根据Abstract Behavior Types[1]的思想提出来的. 要完成两个进程间通信, 需把一个进程的输出端口和另一进程的输入端口相连, 然后在输出端口发送消息, 在输入端口接收消息就可以了. 这种机制很自然, 和现实世界的事物间相互作用是类似的.

    ProcessLog的语法概要如下:

    1 运算符

    (1) ? 输入; c ? x 从输入端口c或通道c上接收输入值放到变量x

    (2) ! 输出; c ! v v的值从输出端口或通道c上输出

    (3) -> 顺序进行的事件的先后关系

    (4) | b : s 分支

    (5) a >> p.b 输出端口a连接到进程p的输入端口b

    (6) a << p.b 输入端口a连接到进程p的输出端口b

    (7) and, or, not 逻辑运算符

    (8) 算术运算符和关系运算符 Java中相同

    2 程序的组成成分

    (1) Unit 程序单元

    (2) Process 进程

    (3) Function 函数

    (4) Predicate 谓词

    (5) DataInPort 数据输入端口类型

    (6) OutPort 输出端口类型

    (7) InPort 输入端口类型

    (8) ResultPort 结果输出端口类型

    3 原子数据结构

    (1) List (函数编程中的List类型, List的操作函数与函数编程中相同);

    (2) Tuple 元组, Clean.

    (3) Set 集合

    没有数组

    4 进程的定义   

    Process ChangeRel

           ( DataInPort dataIn(List, Em, Em);

            ResultPort resultOut(Em);

            InPort fromGetRel;

            OutPort toGetRel, toDetach, toAttach, toChangeRel

           )

           % 生成(或使用已有的)与当前进程相连接的进程, 并配置端口间的连接

           (

            GetRel getRel; Detach detach; Attach attach;

                 

            toGetRel >> getRel.dataIn,

            fromGetRel << getRel.resultOut;

                 

            toDetach >> detach.dataIn;

                 

            toAttach >> attach.dataIn

           )

          

    {

           dataIn?(list, rlEm, em) ->

                  ( | list=[cem:cems]:

                         ( ChangeRel changeRel;

                         toChangeRel >> changeRel.dataIn % 递归进程

                      )

                      toGetRel!(rlEm.id) -> fromGetRel?rel

                      -> toDetach!(cem, rlEm.id)

                      -> toAttach!(cem, em.id, rel.level, rel.weight, rel.relation)

                      -> toChangeRel!(cems, rlEm, em)

                  ) -> self   % 进程是一直运行的, 直到整个系统终止

    }    

          

    进程由事件组成, fromGetRel?rel是输入事件, toGetRel!(rlEm.id)是输出事件.

    该段程序的动态视图为:

    ProcessLog写的程序都可以用这种动态视图来表示, 其中的方形表示进程, 箭头表示数据流向. 进程间是并行运行的, 相互通信.

    5 函数

    [Function] compute(double x)=

    | x<=0: x*x+3

    | x>0: compute(x-5)* compute(x-3)

    函数只能以事件的方式在进程中使用或在其他函数中使用, 不能独立使用.

    6 谓词

    /* 建图 */

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

    7 把谓词转换为函数

    create(t)= graph

           where createGraph(t, graph)     

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

    8 程序单元: 包含进程和数据类型

    Unit PMDAO;

    interface

           Tuple M;

           Process GetReleasedVersion(DataInPort dtIn, OutPort pt1 , InPort pt2);

           …

    implementation

           M=(String id, String name, String version, …);

           Process GetReleasedVersion(DataInPort dtIn, OutPort pt1 , InPort pt2)

                  (…)

    {

                  …

           }

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

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

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

    我的想法是: 应先在纸面上规定它的语法与语义, 再通过使用它完成一些复杂的项目代码来发现它的不足, 再进而改进它, 再实践, 再改进, 直到它基本完善再在机器上实现.

    另外, 大家不要把语言分为中国人提出的还是外国人提出的, 科学无国界.

    现在需解决的问题是:

    在这种并发机制下,

    1怎么实现事务控制?

    2 怎么实现异常机制?

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

    联系方式: juwenguang2000@yahoo.com.cn

    博客: http://www.cnblogs.com/forrestju/

    References

    1. Farhad Arbab, Abstract Behavior Types: a foundation model for components and their composition

    2. Clean http://clean.cs.ru.nl/

    3. Prolog

    4. Delphi

    : 转载时请注明作者.

  • 相关阅读:
    JAVA知识点在整理(可供面试参考)
    Spring Destroying singletons ... root of factory hierarchy 问题【已解决】
    《Spring AOP的设计和实现方式》
    java源码集合体系解析
    springcloud的一些自己想法
    部署一套单Master的K8s集群
    K8S系统学习-----Pod 容器组
    RH358学习笔记--8(使用HAProxy终止HTTPS流量和并进行负载均衡)
    Docker 资源汇总
    RH358学习笔记--8(使用Nginx配置Web服务器学习)
  • 原文地址:https://www.cnblogs.com/forrestju/p/1539722.html
Copyright © 2020-2023  润新知