最近我正在尝试学习函数式编程语言,并选择了Haskell
。
现在我在读了解你一个haskell 和here描述似乎是Haskell的哲学我不确定我是否完全理解它:你在Haskell中通过声明什么是什么来进行计算而不是宣布你如何得到它。
假设我想得到一个列表的总和。
在声明你如何获得的方式: 通过添加所有元素来获得总和,所以代码将是这样的(不是haskell,python):
sum = 0
for i in l:
sum += i
print sum
在中的方式是什么: 总和是第一个元素和其余元素之和的总和,所以代码将是这样的:
sum' :: (Num a) => [a] -> a
sum' [] = 0
sum' (x:xs) = x + sum' xs
但我不确定我是否得到它。有人可以帮忙吗?感谢。
答案 0 :(得分:9)
命令式和功能性是解决问题的两种不同方法。
命令(Python)为您提供了用于获取所需内容的操作。例如,您可以告诉计算机"揉面团。然后把它放入烤箱。打开烤箱。烤10分钟。"。
功能(Haskell,Clojure)为您提供解决方案。你更有可能告诉电脑"我有面粉,鸡蛋和水。我需要面包"。电脑碰巧知道面团,但它不知道面包,所以你告诉它"面包是烤好的面团"。计算机知道烘焙是什么,现在知道如何制作面包。你坐在桌旁10分钟,而电脑为你工作。然后,您可以在烤箱里享用新鲜的美味面包。
您可以看到工程师和数学家的工作方式有类似差异。工程师是必不可少的,看着问题并给工人一个蓝图来解决它。数学家定义问题(解决x)和解决方案(x = -----)并且可以使用任何数量的尝试和真实解决方案来解决较小的问题(2x - 1 = ----- => 2x = ----- + 1)直到他终于找到了理想的解决方案。
大学里的人们主要使用功能语言并不是巧合,不是因为它很难学,而是因为大学之外的数学思想家并不多。在你的引文中,他们试图通过巧妙地使用如何和 来定义思维过程中的这种差异。我个人认为,每个人都会通过把它们变成他们已经理解的东西来理解单词,所以我想象我的面包比喻应该为你澄清差异。
编辑:值得注意的是,当你强制命令电脑时,你不知道你最后是否有面包(也许你煮得太久了,它被烧了,或者你没有添加足够的面粉)。这在函数式语言中不是问题,您可以准确地知道每个解决方案为您提供的内容。在函数式语言中不需要反复试验,因为你所做的一切都是正确的(虽然并不总是有用,比如意外地解决 t 而不是 x )。 / p>
答案 1 :(得分:4)
解释中缺少的部分如下。
命令性示例逐步显示如何计算总和。 在任何阶段你都无法说服自己这确实是一个列表元素的总和。例如,最初不知道为什么sum=0
;它应该是0
吗?你循环通过正确的指数; sum+=i
给你的是什么。
sum=0 -- why? it may become clear if you consider what happens in the loop,
-- but not on its own
for i in l:
sum += i -- what do we get? it will become clear only after the loop ends
-- at no step of iteration you have *the sum of the list*
-- so the step on its own is not meaningful
声明性示例在这方面非常不同。在这种特殊情况下,您首先声明空列表的总和为0.这已经是总和的答案的一部分。然后添加一个关于非空列表的语句 - 非空列表的总和是尾部与添加了头元素的总和。这是总和的声明。您可以归纳地证明它找到了任何列表的解决方案。
请注意此证明部分。在这种情况下,很明显。在更复杂的算法中,它并不明显,因此正确性证明是一个重要部分 - 并且请记住,命令性案例仅作为一个整体才有意义。
另一种计算和的方法,希望陈述性和可原性变得更加清晰:
sum [] = 0 -- the sum of the empty list is 0
sum [x] = x -- the sum of the list with 1 element is that element
sum xs = sum $ p xs where -- the sum of any other list is
-- the sum of the list reduced with p
p (x:y:xs) = x+y : p xs -- p reduces the list by replacing a pair of elements
-- with their sum
p xs = xs -- if there was no pair of elements, leave the list as is
在这里我们可以说服自己:1。p
使列表更短,因此总和的计算将终止; 2. p
生成一个总和列表,因此通过总结更短的列表,我们得到一个只有一个元素的列表; 3.因为(+)
是关联的,重复应用p
产生的值与原始列表中所有元素的总和相同; 4.我们可以证明(+)
的应用程序数量小于直接实现中的应用程序。
换句话说,添加元素的顺序并不重要,因此我们可以先成对([a,b,c,d,e]
,a+b
)对元素(c+d
)求和,这为我们提供了一个较短的列表[a+b,c+d,e]
,其总和与原始列表的总和相同,现在可以以相同的方式减少:[(a+b)+(c+d),e]
,然后是[((a+b)+(c+d))+e]
。< / p>
答案 2 :(得分:3)
罗伯特哈珀声称in his blog&#34;声明&#34;没有任何意义。我想 他在谈论一个明确的定义,我通常认为这个定义更为狭隘 然后意思,但这篇文章仍然值得一试,并暗示你可能没有 找到你想要的答案。
然而,每个人都在谈论&#34;声明&#34;感觉就像我们经常做的那样 谈论同样的事情。即给一些人两种不同的api /语言/程序 并问他们哪个是最具声明性的,他们通常会选择相同的。
起初令人困惑的部分是你的陈述性总和
sum' [] = 0
sum' (x:xs) = x + sum' xs
也可以看作是如何获得结果的指令。它只是一个不同的。
值得注意的是,前奏中的函数sum
实际上并未定义为
因为计算总和的特定方式是低效的。事情显而易见
腥。
所以,&#34;什么,而不是&#34;解释似乎对我不满意。我认为它是 陈述性的&#34;如何&#34;此外还有一些不错的属性。我目前的直觉 关于这些属性是什么类似于:
如果事物不会改变任何状态,那么事情就更具说服力。
如果你可以对它进行肮脏的转换以及它的意义,那么事情就更具说明性
事情仍然完好无损。如果我们知道这一点,那么再给你的声明性总和
+
是可交换的,有一些理由认为写它就好
sum' xs + x
应该会产生相同的结果。
声明性的东西可以分解成更小的东西,但仍然有一些含义。喜欢
x
和sum' xs
在单独处理时仍具有相同的含义,但尝试执行此操作
与python的sum += x
相同也不起作用。
如果事物与时间的流动无关,那么它就更具说明性。例如css 没有描述页面加载时网页的样式。它描述了它的造型 网页随时都可以,即使页面会发生变化。
如果您不必考虑计划流程,那么事情就更具说服力。
其他人可能有不同的直觉,甚至是我不知道的定义, 但无论如何,希望这些都有所帮助。