- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
非功能方式:arr = [1, 2, 3]
变成arr = [1, 5, 3]
。在这里,我们更改相同的数组。
在函数编程中不建议这样做。我知道,由于计算机每天都在变得越来越快,并且要存储更多的内存,因此函数式编程对于提高可读性和简洁代码似乎更为可行。
功能方式:arr = [1, 2, 3]
不变arr2 = [1, 5, 3]
。我看到一个普遍的趋势,就是我们使用更多的内存和时间来仅更改一个变量。
在这里,我们将内存加倍,时间复杂度从O(1)
更改为O(n)
。
对于较大的算法,这可能会代价高昂。这在哪里补偿?还是因为我们可以负担得起更昂贵的计算费用(例如当Quantum计算成为主流时),我们是否只是为了提高可读性而牺牲了速度?
最佳答案
功能数据结构不一定占用更多空间或需要更多处理时间。这里重要的一点是,纯功能数据结构是不可变的,但这并不意味着您总是制作某些东西的完整副本。实际上,不变性正是有效工作的关键。
我将提供一个简单列表作为示例。假设我们有以下列表:
列表的开头是元素1
。列表的末尾是(2, 3)
。假设此列表是完全不变的。
现在,我们要在该列表的开头添加一个元素。我们的新列表必须如下所示:
您无法更改现有列表,它是不可变的。因此,我们必须重新制作一个,对吗?但是,请注意我们新列表的尾部是(1, 2 ,3)
。这与旧列表相同。因此,您可以重复使用它。新列表只是元素0
,其指针指向旧列表的开头作为尾部。这是新列表,突出显示了各个部分:
如果我们的清单是可变的,那将是不安全的。如果您更改了旧列表中的某些内容(例如,将元素2
替换为其他列表),则更改也将反映在新列表中。这就是可变性的危险所在:数据结构上的并发访问必须同步,以避免不可预测的结果,并且更改可能会带来意想不到的副作用。但是,由于不变的数据结构不可能发生这种情况,因此可以安全地在新结构中重用另一结构的一部分。有时候,您希望改变一件事情以反映另一件事情。例如,当您在Java中删除Map
的键集中的条目时,您也希望删除映射本身。但是在其他情况下,可变性会带来麻烦(Java中臭名昭著的Calendar
类)。
那么,如果您不能更改数据结构本身,怎么办呢?您如何制作新清单?请记住,如果我们仅在功能上工作,我们将使用可变指针来摆脱经典数据结构,而是评估函数。
在功能语言中,创建列表是使用cons
函数完成的。 cons
使两个元素成为一个“单元”。如果要仅列出一个元素,则第二个为nil
。因此,只有一个3
元素的列表为:(cons 3 nil)
如果以上是一个函数,并且您询问其head
是什么,则会得到3
。询问tail
,您得到nil
。现在,尾巴本身可以是一个函数,例如cons
。
然后,我们的第一个列表表示为:(cons 1 (cons 2 (cons 3 nil)))
询问上述函数的head
,您会得到1
。询问tail
,您会得到(cons 2 (cons 3 nil))
。
如果我们想在前面添加0
,则只需创建一个新函数,其计算结果为cons
,其中0
为头,上面为tail。(cons 0 (cons 1 (cons 2 (cons 3 nil))))
由于我们执行的功能是不可变的,因此我们的列表也将不可变。诸如添加元素之类的事情就是创建一个新函数,在正确的位置调用旧函数。以命令式和面向对象的方式遍历列表是通过指针从一个元素到达另一个元素。以功能方式遍历列表就是评估功能。
我喜欢这样想数据结构:数据结构基本上是在内存中存储运行某种算法的结果。 它“缓存”计算结果,因此我们不必每次都进行计算。纯功能数据结构通过功能对计算本身进行建模。
实际上,这意味着它可以提高内存效率,因为可以避免很多数据复制。随着对处理并行化的日益关注,不可变数据结构将非常有用。
编辑
考虑到评论中的其他问题,我将尽我所能在上面添加一些内容。
What about my example? Is it something like cons(1 fn) and that function can be cons(2 fn2) where fn2 is cons(3 nil) and in some other case cons(5 fn2)?
cons
函数是最好的。就像您想象的那样,如果给您一个由
cons
单元格组成的列表,那么您得到的只是头,因此不可能随机访问某个索引。在您的数组中,您可以只调用
arr[1]
并以恒定的时间获取数组中的第二项(因为它的索引为0)。如果您声明类似
val list = (cons 1 (cons 2 (cons 3 nil)))
的内容,则不能不遍历就直接询问第二个项目,因为
list
实际上是您要评估的函数。因此,访问需要线性时间,并且访问最后一个元素所需的时间将比访问head元素花费的时间更长。同样,由于它等效于单链接列表,因此遍历只能在一个方向上进行。因此,其行为和性能更像是单链接列表,而不是数组列表或数组。
cons
单元格组成的结构可以很好地工作。在函数式编程中,您经常使用递归调用遍历结构,而在命令式编程中,您将使用
for
循环。
What are we actually storing underneath? If we need to traverse a list, we need a mechanism to point to next elements right? or If I think a bit, I feel like it is irrelevant question to traverse a list since whenever a list is required it should probably be reconstructed everytime?
cons
?由两个元素组成的简单结构:
head
和
tail
。只是下面的指针。在像Java这样的面向对象的语言中,您可以将其建模为
Cons
类,该类包含两个在构造时分配的
最终字段
head
和
tail
(不可变),并具有相应的获取方法。这是LISP变体
(cons 1 (cons 2 nil))
new Cons(1, new Cons(2, null))
val list = (cons 1 (max 2 3))
list.head
,我得到1,如果我问
list.tail
,我得到
(max 2 3)
,然后求值,结果就是3。您编写了
函数。将其视为建模行为而不是数据。这带给我们
Could you elaborate "Purely functional data structures model the computation itself via functions."?
list.tail
将返回可以评估的值,然后返回一个值。换句话说,它返回一个函数。如果在该示例中调用
list.tail
,它将返回
(max 2 3)
,显然是一个函数。计算它会产生
3
,因为它是参数的最大数量。在这个例子中
(cons 1 (cons 2 nil))
tail
会得出一个新的
cons
(即
(cons 2 nil)
一个),然后可以使用它。
int[] array = new int[] {1, 2, 3}
数组,则需要执行以下操作
int sum = 0;
for (int i = 0; i < array.length; ++i) {
sum += array[i];
}
(define sum (arg)
(eq arg nil
(0)
(+ arg.head (sum arg.tail))
)
)
cons
。因此
a + b
被写为
(+ a b)
。
define
让我们定义一个函数,名称(
sum
),该函数的参数列表(
(arg)
),然后是实际的函数主体(其余)作为参数。
eq
函数组成,我们将其定义为比较其前两个参数(
arg
和
nil
),如果它们相等,则对下一个参数(在这种情况下为
(0)
)求值,否则对之后的参数(总和)。因此,可以将其视为带有true和false的
(eq arg1 arg2 true false)
(无论您想要什么)(值,函数...)。
(+ arg.head (sum arg.tail))
中。我们要说明的是,我们将参数的
head
加上尾部对
sum
函数本身的递归调用。假设我们这样做:
val list = (cons 1 (cons 2 (cons 3 nil)))
(sum list)
list
中所有元素的总和。
sum
是
函数的方式。在Java示例中,我们有一些数据结构,然后对其进行迭代,对其进行访问,以创建总和。在功能示例中,评估
是计算的。其中一个有用的方面是,
sum
作为函数可以仅在实际需要时才传递和评估。那是懒惰的评价。
set
。对于元素相等性的某种定义,一组只能包含一个元素的一个实例。对于整数这样的事情很简单;如果它们是相同的值(例如
1 == 1
),则它们相等。但是,对于对象,我们通常进行一些相等性检查(例如Java中的
equals()
)。那么如何知道集合中是否已经包含元素?您遍历集合中的每个元素,并检查其是否等于要查找的元素。
hash set
为每个元素计算一些哈希函数,并将具有相同哈希值的元素放在相应的存储桶中。对于一个良好的哈希函数,存储桶中很少有一个以上的元素。如果现在提供一些元素,并且想要检查它是否在集合中,则操作为:
关于algorithm - 进行函数式编程时需要权衡哪些方面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43730613/
我在一本书(Interview Question)中读到这个问题,想在这里详细讨论这个问题。请点亮它。 问题如下:- 隐私和匿名化 马萨诸塞州集团保险委员会早在 1990 年代中期就有一个绝妙的主意
我最近接受了一次面试,面试官给了我一些伪代码并提出了相关问题。不幸的是,由于准备不足,我无法回答他的问题。由于时间关系,我无法向他请教该问题的解决方案。如果有人可以指导我并帮助我理解问题,以便我可以改
这是我的代码 public int getDist(Node root, int value) { if (root == null && value !=0) return
就效率而言,Strassen 算法应该停止递归并应用乘法的最佳交叉点是多少? 我知道这与具体的实现和硬件密切相关,但对于一般情况应该有某种指南或某人的一些实验结果。 在网上搜索了一下,问了一些他们认为
我想学习一些关于分布式算法的知识,所以我正在寻找任何书籍推荐。我对理论书籍更感兴趣,因为实现只是个人喜好问题(我可能会使用 erlang(或 c#))。但另一方面,我不想对算法进行原始的数学分析。只是
我想知道你们中有多少人实现了计算机科学的“ classical algorithms ”,例如 Dijkstra's algorithm或现实世界中的数据结构(例如二叉搜索树),而不是学术项目? 当有
我正在解决旧编程竞赛中的一些示例问题。在这个问题中,我们得到了我们有多少调酒师以及他们知道哪些食谱的信息。制作每杯鸡尾酒需要 1 分钟,我们需要使用所有调酒师计算是否可以在 5 分钟内完成订单。 解决
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 8 年前。 Improve
我开始学习 Nodejs,但我被困在中间的某个地方。我从 npm 安装了一个新库,它是 express -jwt ,它在运行后显示某种错误。附上代码和错误日志,请帮助我! const jwt = re
我有一个证书,其中签名算法显示“sha256rsa”,但指纹算法显示“sha1”。我的证书 SHA1/SHA2 的标识是什么? 谢谢! 最佳答案 TL;TR:签名和指纹是完全不同的东西。对于证书的强度
我目前在我的大学学习数据结构类(class),并且在之前的类(class)中做过一些算法分析,但这是我在之前的类(class)中遇到的最困难的部分。我们现在将在我的数据结构类(class)中学习算法分
有一个由 N 个 1x1 方格组成的区域,并且该区域的所有部分都是相连的(没有任何方格无法到达的方格)。 下面是一些面积的例子。 我想在这个区域中选择一些方块,并且两个相邻的方块不能一起选择(对角接触
我有一些多边形形状的点列表,我想将其包含在我页面上的 Google map 中。 我已经从原始数据中删除了尽可能多的不必要的多边形,现在我剩下大约 12 个,但它们非常详细以至于导致了问题。现在我的文
我目前正在实现 Marching Squares用于计算等高线曲线,我对此处提到的位移位的使用有疑问 Compose the 4 bits at the corners of the cell to
我正在尝试针对给定算法的约束满足问题实现此递归回溯函数: function BACKTRACKING-SEARCH(csp) returns solution/failure return R
是否有包含反函数的库? 作为项目的一部分,我目前正在研究测向算法。我正在使用巴特利特相关性。在 Bartlett 相关性中,我需要将已经是 3 次矩阵乘法(包括 Hermitian 转置)的分子除以作
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 8 年前。 Improve
问题的链接是UVA - 1394 : And There Was One . 朴素的算法是扫描整个数组并在每次迭代中标记第 k 个元素并在最后停止:这需要 O(n^2) 时间。 我搜索了一种替代算法并
COM 中创建 GUID 的函数 (CoCreateGUID) 使用“分散唯一性算法”,但我的问题是,它是什么? 谁能解释一下? 最佳答案 一种生成 ID 的方法,该 ID 具有一定的唯一性保证,而不
在做一个项目时我遇到了这个问题,我将在这个问题的实际领域之外重新措辞(我想我可以谈论烟花的口径和形状,但这会使理解更加复杂).我正在寻找一种(可能是近似的)算法来解决它。 我有 n 个不同大小的容器,
我是一名优秀的程序员,十分优秀!