首页 文章

声明式编程和命令式编程有什么区别? [关闭]

提问于
浏览
418

我一直在网上寻找声明性和命令式编程的定义,这将为我提供一些启示 . 但是,我发现的一些资源中使用的语言令人生畏 - 例如在Wikipedia . 有没有人有一个现实世界的例子,他们可以告诉我可能会给这个主题带来一些看法(也许在C#中)?

16 回答

  • 22

    我喜欢剑桥课程的解释他们的例子:

    • Declarative - 指定 what 来执行, not how 执行此操作

    • 例如:HTML描述了网页上应该出现的内容,而不是如何在屏幕上绘制

    • Imperative - 同时指定 whathow

    • int x; - 什么(声明性的)

    • x=x+1; - 怎么样

  • 114

    LINQ是声明性与命令式编程的一个很好的C#示例 .

    使用 imperative 编程,您可以逐步告诉编译器您想要发生什么 .

    例如,让我们从这个集合开始,然后选择奇数:

    List<int> collection = new List<int> { 1, 2, 3, 4, 5 };
    

    通过命令式编程,我们将逐步完成,并决定我们想要什么:

    List<int> results = new List<int>();
    foreach(var num in collection)
    {
        if (num % 2 != 0)
              results.Add(num);
    }
    

    在这里,我们说:

    • 创建结果集合

    • 逐步浏览集合中的每个数字

    • 检查数字,如果是奇数,请将其添加到结果中

    另一方面,使用 declarative 编程,您可以编写描述所需内容的代码,但不一定如何获取它(声明您想要的结果,但不是逐步说明):

    var results = collection.Where( num => num % 2 != 0);
    

    在这里,我们说“给我们所有奇怪的东西”,而不是“逐步收集 . 检查这个项目,如果它很奇怪,将它添加到结果集合中 . ”

    在许多情况下,代码也将是两种设计的混合,因此它并不总是黑白的 .

  • 2

    声明性编程就是当你说出你想要的东西时,命令式语言就是当你说出如何获得你想要的东西时 .

    Python中的一个简单示例:

    # Declarative
    small_nums = [x for x in range(20) if x < 5]
    
    # Imperative
    small_nums = []
    for i in range(20):
        if i < 5:
            small_nums.append(i)
    

    第一个示例是声明性的,因为我们没有指定构建列表的任何“实现细节” .

    为了配合C#示例,通常使用LINQ会产生声明式样式,因为您没有说明如何获得您想要的内容;你只是说你想要的 . 你可以对SQL说同样的话 .

    声明性编程的一个好处是它允许编译器做出可能导致代码比手工编写的代码更好的决策 . 运行SQL示例,如果您有类似的查询

    SELECT score FROM games WHERE id < 100;
    

    SQL "compiler"可以"optimize"这个查询,因为它知道 id 是一个索引字段 - 或者它可能没有索引,在这种情况下它将不得不迭代整个数据集 . 或许SQL引擎知道这是利用所有8个内核进行快速并行搜索的最佳时机 . 作为程序员,您不必编写代码来以这种方式处理任何特殊情况 .

  • 8

    声明与命令

    programming paradigm是计算机编程的基本风格 . 有四种主要范例:命令式,声明式,功能性(被认为是声明性范式的一个子集)和面向对象 .

    Declarative programming:是一种编程范式,表示计算的逻辑(做什么)而不描述其控制流(如何做) . 一些着名的声明性域特定语言(DSL)示例包括CSS,正则表达式和SQL的子集(例如,SELECT查询)许多标记语言(如HTML,MXML,XAML,XSLT ......)通常都是声明性的 . 声明性编程试图模糊作为一组指令的程序和作为关于期望答案的断言的程序之间的区别 .

    Imperative programming:是一种编程范例,它根据改变程序状态的语句来描述计算 . 声明性程序可以被视为编程命令或数学断言 .

    函数式编程:是一种编程范式,将计算视为数学函数的评估,并避免状态和可变数据 . 它强调功能的应用,与强调状态变化的命令式编程风格形成对比 . 在纯函数语言(如Haskell)中,所有函数都没有副作用,状态更改仅表示为转换状态的函数 .

    以下MSDN中的命令式编程示例循环遍历数字1到10,并查找偶数 .

    var numbersOneThroughTen = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    //With imperative programming, we'd step through this, and decide what we want:
    var evenNumbers = new List<int>();
    foreach (var number in numbersOneThroughTen)
    {    if (number % 2 == 0)
        {
            evenNumbers.Add(number);
        }
    }
    //The following code uses declarative programming to accomplish the same thing.
    // Here, we're saying "Give us everything where it's odd"
    var evenNumbers = numbersOneThroughTen.Select(number => number % 2 == 0);
    

    两个例子都产生相同的结果,一个既不好也不差 . 第一个示例需要更多代码,但代码是可测试的,并且命令式方法使您可以完全控制实现细节 . 在第二个例子中,代码可以说更具可读性;但是,LINQ并不能让您控制幕后发生的事情 . 您必须相信LINQ将提供所请求的结果 .

  • 3

    我将添加另一个很少出现在声明/命令式编程讨论中的例子:用户界面!

    在C#中,您可以使用各种技术构建UI .

    在命令性结束时,您可以使用DirectX或OpenGL非常强制性地绘制按钮,复选框等...逐行(或实际上,三角形三角形) . 由您来说明如何绘制用户界面 .

    在声明性结束时,你有WPF . 你基本上写了一些XML(是的,是的,技术上是“XAML”),框架为你工作 . 你说的是用户界面的样子 . 由系统决定如何做到这一点 .

    无论如何,还有另外一件事要考虑 . 仅仅因为一种语言是声明性的或命令式的并不意味着它没有另一种语言的某些特征 .

    此外,声明性编程的一个好处是,通过阅读代码通常可以更容易地理解目的,而命令式可以让您更好地控制执行 .

    这一切的要点:

    声明 - > what 你想要完成

    势在必行 - > how 你想要它完成

  • 2

    以上所有答案和其他在线帖子提到以下内容:

    • 使用 declarative 编程,您可以编写描述所需内容的代码,但不一定是如何获取代码

    • 您应该优先于命令式编程进行声明式编程

    他们没有告诉我们的是 how to achieve it . 对于部分程序要更具说明性,其他部分必须 provide the abstraction 来隐藏实现细节(即 imperative 代码) .

    • 例如,LINQ比循环更具说明性(for,while等),例如,您可以使用list.Where()来获取新的过滤列表 . 为了实现这一目标,微软已经完成了LINQ抽象背后的所有繁重工作 .

    实际上,函数式编程和函数库更具说明性的原因之一是因为它们抽象了循环和列表创建,隐藏了场景后面的所有实现细节(最有可能是带循环的命令式代码) .

    在任何程序中,您将始终拥有命令式和声明性代码,您应该的目标是隐藏抽象背后的所有 imperative 代码,以便程序的其他部分可以使用它们 declaratively .

    最后,虽然函数式编程和LINQ可以使您的程序更具声明性,但您可以通过提供更多抽象来使其更具说明性 . 例如:

    // JavaScript example
    
    // Least declarative
    var bestProducts = [];
    for(var i = 0; i < products.length; i++) {
        var product = products[i];
        if (product.rating >= 5 && product.price < 100) {
            bestProducts.push(product);
        }
    }
    
    
    // More declarative
    var bestProducts = products.filter(function(product) {
        return product.rating >= 5 && product.price < 100;
    });
    
    // Most declarative, implementation details are hidden in a function
    var bestProducts = getBestProducts();
    
  • 83

    命令式编程要求开发人员逐步定义代码的执行方式 . 要以强制性的方式发出指示,你会说:“去第一街,左转进入Main,开两个街区,右转进入Maple,然后停在左边的第三个房子 . ”声明版可能听起来像这样:“开车去苏的家 . ”一个人说怎么做;另一个人说需要做什么 . 声明式风格比命令式风格有两个优点:它不会强迫旅行者记住一长串指令 . 它允许旅行者在可能的情况下优化路线 .

    Calvert,C Kulkarni,D(2009) . 必不可少的LINQ . 艾迪生韦斯利 . 48 .

  • 7

    差异主要与整体抽象水平有关 . 使用声明,在某些时候,你离各个步骤太远,程序在如何获得结果方面有很大的自由度 .


    你可以看到每一条指令都落在连续体的某个地方:

    Degree of abstraction:

    Declarative <<=====|==================>> Imperative
    

    声明性真实世界示例:

    • 图书管理员,请检查一下Moby Dick的副本 . (图书馆员可自行选择执行请求的最佳方法)

    势在必行的现实世界示例:

    • 进入图书馆

    • 查找图书组织系统(卡片目录 - 旧学校)

    • 研究如何使用卡片目录(你也忘了,对吧)

    • 了解货架的标签和组织方式 .

    • 弄清楚如何在书架上组织书籍 .

    • 从卡片目录与组织系统交叉参考书籍位置以查找所述书籍 .

    • 带书到退房系统 .

    • 看书 .

  • 11

    在计算机科学中,声明性编程是一种编程范式,它表达了计算的逻辑而没有描述其控制流程 .

    来自http://en.wikipedia.org/wiki/Declarative_programming

    简而言之,声明性语言更简单,因为它缺乏控制流的复杂性(循环,if语句等)

    一个很好的比较是ASP.Net'代码隐藏'模型 . 你有声明的'.ASPX'文件,然后是命令式'ASPX.CS'代码文件 . 我经常发现,如果我可以在脚本的声明性部分中完成所有我需要的工作,那么就会有更多的人可以按照所做的那样做 .

  • 17

    命令式编程明确告诉计算机该做什么,以及如何做,如指定顺序等

    C#:

    for (int i = 0; i < 10; i++)
    {
        System.Console.WriteLine("Hello World!");
    }
    

    陈述是当你告诉计算机做什么,但不是真的如何做 . Datalog / Prolog是这方面首先想到的语言 . 基本上一切都是陈述性的 . 你无法保证订购 .

    C#是一种更为迫切的编程语言,但某些C#特性更具说明性,如Linq

    dynamic foo = from c in someCollection
               let x = someValue * 2
               where c.SomeProperty < x
               select new {c.SomeProperty, c.OtherProperty};
    

    必须写同样的事情:

    dynamic foo = SomeCollection.Where
         (
              c => c.SomeProperty < (SomeValue * 2)
         )
         .Select
         (
              c => new {c.SomeProperty, c.OtherProperty}
         )
    

    (来自维基百科Linq的例子)

  • 2

    偷窃Philip Roberts here

    • 命令式编程告诉机器如何做某事(导致你想要发生的事情)

    • 声明性编程告诉机器您想要发生什么(计算机会弄清楚如何操作)

    两个例子:

    1. Doubling all numbers in an array

    势在必行:

    var numbers = [1,2,3,4,5]
    var doubled = []
    
    for(var i = 0; i < numbers.length; i++) {
      var newNumber = numbers[i] * 2
      doubled.push(newNumber)
    }
    console.log(doubled) //=> [2,4,6,8,10]
    

    声明的:

    var numbers = [1,2,3,4,5]
    
    var doubled = numbers.map(function(n) {
      return n * 2
    })
    console.log(doubled) //=> [2,4,6,8,10]
    

    2. Summing all items in a list

    势在必行

    var numbers = [1,2,3,4,5]
    var total = 0
    
    for(var i = 0; i < numbers.length; i++) {
      total += numbers[i]
    }
    console.log(total) //=> 15
    

    以声明

    var numbers = [1,2,3,4,5]
    
    var total = numbers.reduce(function(sum, n) {
      return sum + n
    });
    console.log(total) //=> 15
    

    注意命令性示例如何涉及创建新变量,改变它并返回该新值(即,如何使某些事情发生),而声明性示例在给定输入上执行并基于初始输入返回新值(即,我们想要发生什么) .

  • 638

    Imperative programming
    一种需要编程规则的编程语言,如C / C,Java,COBOL,FORTRAN,Perl和JavaScript . 以这些语言编写的程序员必须根据数据处理和编程知识,制定适当的动作顺序以解决问题 .

    Declarative programming
    一种不需要编写传统编程逻辑的计算机语言;用户专注于定义输入和输出,而不是过程编程语言(如C或Java)中所需的程序步骤 .

    声明性编程示例是CSS,HTML,XML,XSLT,RegX .

  • 32

    只是在移动应用程序开发方面添加另一个示例 . 在iOS和Android中,我们有Interface Builders,我们可以在其中定义应用程序的UI .

    使用这些构建器绘制的UI本质上是声明性的,我们拖放组件 . 实际的抽象发生在框架和系统下面并由其执行 .

    但我们也可以在代码中绘制整个组件,这本质上是必要的 .

    此外,Angular JS等一些新语言专注于以声明方式设计UI,我们可能会看到许多其他语言提供相同的支持 . 就像JAVA没有任何好的声明方式来在JAVA swing或JAVA FX中绘制原生桌面应用程序,但在不久的将来,它们可能就是这样 .

  • 42

    声明性程序只是一些或多或少的“通用”命令式实现/ vm的数据 .

    优点:只指定一个数据,以某种硬编码(和检查)格式,比直接指定某些命令式算法的变体更简单,更不容易出错 . 一些复杂的规范不能直接编写,只能以某种DSL形式编写 . DSL和数据结构中使用的最佳和频率是集合和表格 . 因为你没有元素/行之间的依赖关系 . 当你没有依赖关系时,你可以自由地修改和轻松支持 . (例如,比较具有类的模块 - 使用您喜欢的模块以及具有易碎基类问题的类)所有声明性和DSL的商品都会立即从该数据结构(表和集)的优势中获得 . 另一个好处 - 如果DSL或多或少是抽象的(设计良好),你可以改变声明性语言vm的实现 . 例如,进行并行实现 . 或将其移植到其他操作系统等所有良好的模块化隔离接口或协议为您提供这种自由和简单的支持 .

    缺点:你猜对了 . 通用(并由DSL参数化)命令式算法/ vm实现可能比特定的更慢和/或内存饥饿 . 在某些情况下 . 如果这种情况很少见 - 只要忘记它,就让它变慢 . 如果它是frequient - 你总是可以为这种情况扩展你的DSL / vm . 在某个地方放慢所有其他情况,当然......

    附:框架在DSL和命令之间是中途 . 并且作为所有中途解决方案......它们结合了缺点,而不是利益 . 他们不是那么安全而且不那么快:)看看万能的杰克 - 它是强大的简单ML和灵活的metaprog Prolog之间的中间点......它是一个什么样的怪物 . 你可以将Prolog看作是一个只有布尔函数/谓词的Haskell . 它的灵活性对Haskell有多么简单......

  • 8

    我只是想知道为什么没有人提到属性类作为C#中的声明性编程工具 . 这个页面的流行答案刚刚讨论了LINQ作为声明性编程工具 .

    根据维基百科

    通用声明性语言包括数据库查询语言(例如,SQL,XQuery),正则表达式,逻辑编程,函数编程和配置管理系统 .

    因此LINQ作为一种功能语法绝对是一种声明性方法,但C#中的属性类作为配置工具也是声明性的 . 以下是阅读更多信息的好起点:Quick Overview of C# Attribute Programming

  • 1

    根据我的理解,这两个术语都源于哲学,有陈述性和命令式的知识 . 陈述性知识是真理的断言,是数学公理的事实陈述 . 它告诉你一些事情 . 当务之急,或程序性知识,告诉你如何到达某事 . 这就是算法的定义本质上是什么 . 如果愿意,可以将计算机编程语言与英语进行比较 . 陈述句陈述某事 . 一个无聊的例子,但这里是一个声明性的方式来显示两个数字是否相等,在Java中:

    public static void main(String[] args)
    {
        System.out.print("4 = 4.");
    }
    

    另一方面,英语中的命令句则给出命令或提出某种要求 . 因此,命令式编程只是一个命令列表(这样做,这样做) . 这是在Java中接受用户输入时显示两个数字是否相等的必要方法:

    private static Scanner input;    
    
    public static void main(String[] args) 
    {
        input = new Scanner(System.in);
        System.out.println();
        System.out.print("Enter an integer value for x: ");
        int x = input.nextInt();
        System.out.print("Enter an integer value for y: ");        
        int y = input.nextInt();
    
        System.out.println();
        System.out.printf("%d == %d? %s\n", x, y, x == y);
    }
    

    从本质上讲,声明性知识会跳过某些元素,形成一个对这些元素的抽象层 . 声明性编程也是如此 .

相关问题