List Haskell-一个非常简单的函数
我试图理解以下函数:List Haskell-一个非常简单的函数,list,haskell,List,Haskell,我试图理解以下函数: q1 :: [Int] -> Int q1 [] = 0 q1 [x] = x q1 (x:_:xs) = max x (q1 xs) 当输入这个:q1(映射abs[-1,-6,-5,7])时,它得到5。有人能告诉我为什么会这样吗?我理解map是如何工作的,但是模式匹配(x:xs)有点让人困惑。谢谢 Haskell中的列表至少在概念上是一个链表。有两种可能性: 空
q1 :: [Int] -> Int
q1 [] = 0
q1 [x] = x
q1 (x:_:xs) = max x (q1 xs)
当输入这个:q1(映射abs[-1,-6,-5,7])时,它得到5。有人能告诉我为什么会这样吗?我理解map是如何工作的,但是模式匹配(x:xs)有点让人困惑。谢谢 Haskell中的列表至少在概念上是一个链表。有两种可能性:
- 空列表
;或[]
- 一个“cons”
,其中(x:xs)
是头(第一项),而x
是尾(列表的其余部分)xs
[1]
被翻译成(1:[])
,而[1,4,2,5]
被翻译成(1:(4:(2:[])
为什么这很重要?我们首先尝试理解q1
函数。如果我们查看类型,就会看到q1
将Int
s列表作为输入,并返回Int
。其递归定义为:
q1 :: [Int] -> Int
q1 [] = 0
q1 [x] = x
q1 (x:_:xs) = max x (q1 xs)
这意味着空列表的q1
为零(0
);对于一个元素为x
的列表,其q1
为x
。对于包含两个或多个元素的列表,是该列表第一项的最大值,以及该列表尾部的尾部。这是因为我们的模式匹配是(x::xs)
,它是(x:(:xs))
的缩写。下划线的基本意思是“不在乎”。所以列表应该是一个cons,其中尾部也是cons,我们感兴趣的是列表的头部x
,以及列表的尾部xs
如果我们对此进行推理,我们就会发现q1
返回奇数索引处元素的最大值(因此第一个、第三个、第五个等元素)。如果列表长度为偶数,我们也会用零计算最大值(因此,如果奇数索引处的所有元素都为负数,则函数将返回零,但这仅限于偶数长度列表的情况)
现在如果我们用q1(map abs[-1,-6,-5,7])
来调用它,这意味着我们将在[-1,-6,-5,7]
上调用map abs
的结果map abs
构造一个列表,其中abs
应用于列表的所有元素(尽管它是惰性应用的)。所以在映射abs[-1,-6,-5,7]
之后,我们获得列表[1,6,5,7]
。现在奇数索引处的元素是1
和5
。因此q1
将计算这些元素的最大值和零(因为列表的长度是4,这是偶数)。最大值(0,1,5)是5
个人而言,尤其是我们也考虑零,但只有在列表长度相等的情况下,才是非常“不稳定”的。它可能导致难以理解的错误,因为它可能是函数细节的结果。例如,无论列表的长度如何,我们都可以用零计算最大值:
q2 :: (Num a, Ord a) => [a] -> a
q2 [] = 0
q2 [x] = max 0 x
q2 (x:_:xs) = max x (q2 xs)
或者我们可以决定根本不使用零,也不在空列表上定义最大值,例如:
q3 :: Ord a => [a] -> a
q3 [x] = x
q3 [x,_] = x
q3 (x:_:xs) = max x (q3 xs)
模式x:xs:xs
与至少包含两个元素的列表相匹配;第一个元素命名为x
,第二个元素被丢弃,列表的其余部分(除前两个元素外)命名为xs
。这是否阐明了这种模式的含义?是的,这就解释了。现在觉得自己很愚蠢,因为我错过了第二个被丢弃的机会。。。谢谢该死,这是一个非常好的回答,一个彻底的回答!我不知道在问之前我们会通过奇怪的指数,但现在我完全明白为什么我会得到5!非常感谢您花时间回答这个问题!。。。然后你说q3。地图abs
超过了列表,因此相当于最大值。(0:) . 地图(abs.head)。chunksOf 2
或什么的。@WillNess:当然可以,但最后一节更像是对q
根本不是一个好函数这一事实的评论,不是为了设计更好的函数,只是用外行的话简单概述了两个选项:)顺便说一句0
东西意味着q1
期望(不需要)它在列表中的参数都是非负的,这是它接口的一个重要部分(不是由它的类型捕获的)。与映射abs
也很相配。@WillNess:没错,而且它不受类型限制,也不执行abs
本身,也不总是使用零,这使得它的功能非常糟糕。