Haskell - 一个非常简单的功能

问题描述 投票:2回答:1

我正在尝试理解以下功能:

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)有点令人困惑。谢谢!

list haskell
1个回答
7
投票

Haskell中的列表 - 至少在概念上 - 是一个链表。有两种可能性:

  • 空名单[];要么
  • 一个“cons”(x:xs),其中x是头(第一项),xs是尾部(列表的其余部分)。

Haskell也使用了语法糖。例如,[1]在幕后翻译为(1:[])[1,4,2,5]翻译为(1:(4:(2:(5:[]))))

为什么这很重要?我们首先会尝试了解q1函数。如果我们查看类型,我们会看到q1Ints列表作为输入,并返回Int。它以递归方式定义为:

q1 :: [Int]  -> Int
q1 [] = 0
q1 [x] = x
q1 (x:_:xs) = max x (q1 xs)

这意味着q1为空列表为零(0); q1列表中有一个元素xx。对于具有两个或更多元素的列表,该列表maximum的第一项的x和该列表尾部的尾部。这是因为我们模式匹配(x:_:xs)的缩写(x:(_:xs))。下划线基本上意味着“不在乎”。因此列表应该是尾部也是缺点的缺点,我们对列表x的头部以及列表xs尾部的尾部感兴趣。

如果我们对此进行推理,我们就会发现q1返回奇数索引处的元素的最大值(所以第一个,第三个,第五个等元素)。如果列表具有偶数长度,我们还计算最大值为零(因此,如果奇数索引处的所有元素都是负数,则函数将返回零,但这仅在我们具有偶数长度列表的情况下)。

现在,如果用q1 (map abs [-1,-6,-5,7])来称呼它,那么就意味着我们将在q1上对map abs的结果调用[-1, -6, -5, 7]map abs构造了一个列表,其中abs应用于列表的所有元素(尽管它是懒惰地应用)。所以在map abs [-1, -6, -5, 7]之后,我们获得了[1, 6, 5, 7]列表。现在奇数指数的元素是15。所以q1将计算这些元素的最大值和零(因为列表的长度是4,这是偶数)。并且max(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)
© www.soinside.com 2019 - 2024. All rights reserved.