为什么 Haskell 是完全声明式的?

Why is Haskell fully declarative?

我不太了解命令式[​​=21=]和声明式编程范式之间的区别。我读到 Haskell 是一种声明性语言。在某种程度上,我会说是的,但在命令式的定义方面有一些事情让我感到困扰。

当我有一个数据结构并使用 Haskell 的函数进行转换时,我实际上只是告诉要转换的内容。所以我将数据结构作为函数的参数,并对结果感到满意。

但是没有真正满足我需求的功能怎么办?

我将开始编写一个自己的函数,该函数需要数据结构作为参数。之后,我将开始编写应该如何处理数据结构。因为我只能调用本机 Haskell 函数,所以我仍然使用声明式范例,对吗?但是当我开始使用 "if statement" 时会怎样呢?这不会结束声明性的性质吗,因为我要告诉程序从那时起如何做事?

Haskell中没有if语句,只有一个if表达式if a then b else c,其实相当于三元表达式,如类 C 语言中的 a ? b : c 或 Python 中的 b if a else c。您不能省略 else,它可以用在任何可以使用任意表达式的地方。进一步约束a必须有类型Booleanbc必须有相同的类型。它是

的语法糖
case a of
  True -> b
  False -> c

不要太在意标签"declarative";它只是该语言支持的一种风格编程。例如,考虑阶乘函数的典型声明性定义:

fact 0 = 1
fact n = n * fact (n - 1)

这也只是一些你会认为更命令的东西的语法糖:

fact n = case n of 
          0 -> 1
          otherwise -> n * fact (n - 1)

也许这是一个角度问题。在我看来,根据其他事物来定义事物并没有什么强制性的,因为我们总是可以用它的定义来替换某些东西(只要定义是纯粹的)。也就是说,如果我们有 f x = x + 1,那么我们看到 f z 的任何地方都可以替换为 z + 1。所以纯函数不应该真正被视为指令;它们应该被视为定义。

很多 Haskell 代码因此被认为是声明性的。我们只是将事物定义为其他事物的(纯)函数。

也可以在 Haskell 中编写命令式代码。有时候我们真的很想说 "do A, then do B, then do C" 这样的话。这为函数应用的简单世界增加了一个新的维度:我们需要一个 'happens before' 的概念。 Haskell 已经接受了 Monad 概念来描述具有计算顺序的计算。事实证明这非常方便,因为它可以封装更改状态等效果。

声明式语言由表达式构成,而命令式语言由语句构成。

通常的解释是做什么怎么做。你已经发现了其中的困惑。如果你这样理解,声明式就是使用定义(按名称),命令式就是编写定义。那么什么是声明式语言呢?一个只命名定义的?如果是这样,那么您唯一可以编写的 Haskell 程序就是 main!

有一种声明方式和一种命令方式来进行分支,它直接遵循定义。声明性分支是一个表达式,命令性分支是一个语句。 Haskell 有 case … of … (表达式),C 有 if (…) {…} else {…} (语句)。

表达式和语句有什么区别?表达式有值,而语句有效果。值和效果有什么区别?

对于表达式,有一个函数 μ 可以将任何表达式 e 映射到它的值 μ(e)。这也称为语义,或意义,理想情况下是一个定义明确的数学对象。这种定义值的方式称为指称语义。还有其他方法。

对于语句,在语句S之前有一个状态P,在语句S之后有一个状态Q。 S 的效果是从 P 到 Q 的增量。这种定义效果的方式称为 霍尔逻辑。还有其他方法。

坦率地说,"declarative programming" 一词更像是一个营销术语。它表示 "specifying what to do, not how to do it" 的非正式定义含糊不清,易于解释,绝对不是黑白分明的界限。实际上,它似乎适用于任何广泛属于函数式编程、逻辑编程或领域特定语言 (DSL) 类别的事物。

因此(我意识到这可能不符合您问题的答案,但仍然 :)),我建议您不要浪费时间思考某些内容是否仍然是声明性的。命令式编程、函数式编程和逻辑编程这两个术语已经更有意义了,所以反思这些也许更有用。

您不能在 Haskell 中使用 "if statement",因为有 none。您可以使用 "if-expression"

if c then a else b

但这只是

之类的语法糖
let f True a b = a; f False a b = b in f c a b  

这又是一个完整的声明。