• 命令式语言和声明式语言对比——JavaScript实现快速排序为例


    什么是命令式编程 (Imperative Programming)?

    命令机器如何做事情,强调细节实现

    java、c、c++等都属此类。

    “这些语言的特征在于,写出的代码除了表现出“什么(What)”是你想做的事情之外,更多的代码则表现出实现的细节,也就是“如何(How)”完成工作。这部分代码有时候多到掩盖了我们原来问题的解决方案。比如,你会在代码里写for循环,if语句,a等于b,i加一等等,这体现出机器如何处理数据。”

    什么是声明式编程(Declarative Programming)?

    声明式编程告诉机器做什么,至于怎么做到的,你可以不用管。

    代表语言:prolog
    特点:你只需向它提供一些事实(fact)和推论(inference),让它为你判断。

    声明式编程包含了函数式编程和逻辑编程。比如lisp haskell prolog,也包含下面示例代码中使用的js。js是一种多范式语言,既可以用命令式也可以用函数式风格编写代码。

    声明式语言来描述算法非常合适

    通过上面的简单对比得知,声明式编程的抽象程度更高,程序员不必纠缠与实现的细节,所以用来描述算法最合适了。

    以快速排序为例

    A、快速排序以声明式编程风格实现的例子

    function quicksort(list){
      if(list.length === 0){
        return [];
      }else{
        var n = first(list)            //1
          , lt = listlet(rest(list),n) //2
          , gt = listgt(rest(list),n)  //3
        // 递归 & 合并
        return [].concat(quicksort(lt) //4
                        ,n
                        ,quicksort(gt))//5
      }
    }
    console.log(quicksort([3,9,2,1,5,4]));
    // [ 1, 2, 3, 4, 5, 9 ]
    

    代码本身比较短小,它描述的算法是这样的

    1.取出一个元素作为参考元素n 。见标注1

    2.将这个元素之外的剩余元素分为两部分,小于等于n的元素lt,大于n的元素gt。见标注2、3

    3.将lt放n前面,gt放n后面,即按升序排列。但是在这样排列之前,要递归的执行上面两步,直到遇见空数组。见标注4、5

    quicksort依赖下面的工具函数。前两个工具函数本身也是声明式风格编写的。

    function listgt(list,n){
      return list.filter(function(m){
               return m > n;
             })
    }
    function listlet(list,n){
      return list.filter(function(m){
               return m <= n;
             })
    }
    function first(list){
      return list[0];
    }
    function rest(list){
      return list.slice(1);
    }
    

    以listgt为例,声明式风格的实现为:

    function listgt(list,n){
      return list.filter(function(m){
               return m > n;
             })
    }
    

    对应的命令式风格的实现为:

    function listgt(list,n){
      var ret = [];
      for(var i=0;i<list.length;i++){
        if(list[i]>n){
          ret.push(list[i]);
        }
      }
      return ret;
    }
    

    可以看出,上面的代码体现了“命令机器如何做事情,强调细节实现”,包含了一个for循环, 声明了额外的变量i,ret,调用了ret.push方法。感觉有很多噪音在里面。  

    而前一个listgt实现为一段声明,过滤(filter)这个数组,过滤规则为:这个数组元素m要大于n。过滤就是一种声明式的描述,“告诉机器做什么”。过滤功能可能语言本身已经提供给你了,你只需要告诉机器过滤规则就行了。 

    B、快速排序以命令式风格实现的例子

    function swap(items, firstIndex, secondIndex){
        var temp = items[firstIndex];
        items[firstIndex] = items[secondIndex];
        items[secondIndex] = temp;
    }
    function partition(items, left, right) {
        var pivot   = items[Math.floor((right + left) / 2)],
            i       = left,
            j       = right;
        while (i <= j) {
            while (items[i] < pivot) {
                i++;
            }
            while (items[j] > pivot) {
                j--;
            }
            if (i <= j) {
                swap(items, i, j);
                i++;
                j--;
            }
        }
        return i;
    }
    function quickSort(items, left, right) {
      var index;
      if (items.length > 1) {
        left = typeof left != "number" ? 0 : left;
        right = typeof right != "number" ? items.length - 1 : right;
        index = partition(items, left, right);
        if (left < index - 1) {
          quickSort(items, left, index - 1);
        }
        if (index < right) {
          quickSort(items, index, right);
        }
      }
      return items;
    }
    console.log(quickSort([4, 2, 6, 5, 3, 9]));
    

    left和right参数的引入是因为实现算法的细节需要——“命令机器如何做事情,强调细节实现”,用于partition函数划分数组。

    partition函数也有非常多的实现细节。相较而言,不太好阅读。

    参考:

    http://blog.zhaojie.me/2010/04/trends-and-future-directions-in-programming-languages-by-anders-2-declarative-programming-and-dsl.html

  • 相关阅读:
    php打印出10*10表格
    php打印出1到2000年之间所有的闰年
    借鉴一篇好文章
    女程序员的预备篇
    SQL存储过程删除数据库日志文件的方法
    Mongodb无法访问28107的问题
    使用 xsd.exe 命令工具将 xsd 架构生成 类(CS) 文件
    C# 用POST提交json数据
    WinForm 使用 HttpUtility
    Sql Server 分区之后增加新的分区
  • 原文地址:https://www.cnblogs.com/wewe/p/3189781.html
Copyright © 2020-2023  润新知