我是 Haskell 的新手,正在努力学习基础知识。我很难理解如何操作列表的内容。
假设我有以下列表,我想创建一个函数从列表中的每个元素中减去 1,我可以简单地将 x 传递给函数,这将如何完成?
Prelude>let x = 1:2:3:4:5:[]
就像是:
Prelude>subtractOne(x)
我是 Haskell 的新手,正在努力学习基础知识。我很难理解如何操作列表的内容。
假设我有以下列表,我想创建一个函数从列表中的每个元素中减去 1,我可以简单地将 x 传递给函数,这将如何完成?
Prelude>let x = 1:2:3:4:5:[]
就像是:
Prelude>subtractOne(x)
(你可以1:2:3:4:5:[]
更简单地写成[1,2,3,4,5]
甚至[1..5]
。)
你想使用列表推导,所以这里是:
subtractOne xs = [ x-1 | x <- xs ]
在这里,我xs
用来代表我从中减去一个的列表。
首先要注意的是x <- xs
,您可以将其解读为“x
取自xs
”。这意味着我们将xs
依次获取每个数字,并且每次我们都会调用该数字x
。
x-1
是我们为 each 计算和返回的值x
。
更多示例,这里有一个给每个元素加一[x+1|x<-xs]
或对每个元素求平方的例子[x*x|x<-xs]
。
让我们更深入地了解列表理解,编写一个函数,先找到平方数,然后再找到我们给它的数字的立方数,所以
> squaresAndCubes [1..5]
[1,4,9,16,25,1,8,27,64,125]
我们需要
squaresAndCubes xs = [x^p | p <- [2,3], x <- xs]
这意味着我们取p
2 然后 3 的幂,对于每个幂,我们x
从 中取所有 s xs
,并计算x
到幂p
( x^p
)。
如果我们反过来做会发生什么?
squaresAndCubesTogether xs = = [x^p | x <- xs, p <- [2,3]]
我们得到
> squaresAndCubesTogether [1..5]
[1,1,4,8,9,27,16,64,25,125]
它取了每一个x
,然后给你它的两种力量。
结论 -<-
位的顺序告诉您输出的顺序。
如果我们只想允许一些答案怎么办?
2 到 100 之间的哪些数可以写成x^y
?
> [x^y|x<-[2..100],y<-[2..100],x^y<100]
[4,8,16,32,64,9,27,81,16,64,25,36,49,64,81]
在这里,我们允许所有x
,y
只要x^y<100
.
由于我们对每个元素都做同样的事情,我会在实践中使用map
:
takeOne xs = map (subtract 1) xs
或更短为
takeOne = map (subtract 1)
(我必须调用它,subtract 1
因为它- 1
会被解析为负 1。)
您可以使用以下map
功能执行此操作:
subtractOne = map (subtract 1)
List Comprehensions 的替代解决方案更加冗长:
subtractOne xs = [ x - 1 | x <- xs ]
为了清楚起见,您可能还想添加类型注释。
您可以使用该map
功能很容易地做到这一点,但我怀疑您想自己滚动一些东西作为学习练习。在 Haskell 中执行此操作的一种方法是使用递归。这意味着您需要将函数分为两种情况。第一种情况通常是最简单类型输入的基本情况。对于列表,这是一个空列表[]
。从空列表的所有元素中减一的结果显然是一个空列表。在哈斯克尔:
subtractOne [] = []
现在我们需要考虑稍微复杂的递归情况。对于空列表以外的任何列表,我们可以查看输入列表的头部和尾部。我们将从头部减去一个,然后应用于subtractOne
列表的其余部分。然后我们需要将结果连接在一起形成一个新列表。在代码中,这看起来像这样:
subtractOne (x:xs) = (x - 1) : subtractOne xs
正如我之前提到的,您也可以使用map
. 实际上,它只是一条线,并且是首选的 Haskellism。另一方面,我认为编写自己的函数使用显式递归以了解其工作原理是一个非常好的主意。最终,您甚至可能想编写自己的map
函数以供进一步练习。
map (subtract 1) x
将工作。
subtractOne = map (subtract 1)
该map
函数允许您将函数应用于列表的每个元素。