5

我是初学者,基本上我需要对此进行解释

他用这段代码回答:

tupleToList :: [(a,a)] -> [a]
tupleToList ((a,b):xs) = a : b : tupleToList xs
tupleToList _          = []

但我不明白他为什么不使用:

tupleToList [] = []
tupleToList ((a,b):xs) = a : b : tupleToList xs

就像我通常在指南的第一个练习中看到的那样。我知道'_'是什么,但是,当列表为空时,使用'[]'不是更好吗?

4

2 回答 2

9

就像我通常在指南的第一个练习中看到的那样。我知道那是什么,但是,当列表为空时,_使用这个意思不是更好吗?[]

语义上两者是相同的,因为 2 元组只有一个构造函数(a,b),而列表有两个构造函数[](h:t)

由于第一个子句不匹配的唯一模式是空列表,因此通配符 _等效于[].

由于[]((a,b):xs)分离模式(即没有可以匹配两种模式的值),当[]显式使用时,两种模式的顺序并不重要。那么,我们可以按照我们喜欢的任何顺序编写它。

一些 Haskell 程序员更喜欢使用显式模式(所以用 with[]而不是_),因为这意味着我们知道我们用那个子句实际处理了哪些值。如果稍后 Haskell 社区决定引入一个额外的列表构造函数(是的,对于不太可能的列表,但对于其他data类型,这可能更合理),Haskell 编译器可以 (with -Wincomplete-patterns) 发出警告,指出某些模式没有被覆盖。通配符当然涵盖了所有模式,但右边的表达式可能不是我们打算用于附加构造函数的表达式。

因此,我建议在您想通过同一子句匹配多个模式时才使用通配符。如果很清楚其他模式是什么,最好是明确的。就像Python 之禅所说(是的,它是 Python,但大多数概念在某种程度上是通用的):“显式优于隐式”。

于 2018-05-21T10:00:20.890 回答
5

没有区别:它们的语义完全相同。

tupleToList [] = []
tupleToList ((a,b):xs) = a : b : tupleToList xs

相当于

tupleToList ((a,b):xs) = a : b : tupleToList xs
tupleToList [] = []

这相当于

tupleToList ((a,b):xs) = a : b : tupleToList xs
tupleToList _ = []

通常,_当我们需要对多个案例进行模式匹配时,会使用通配符。例如

myAnd :: Bool -> Bool -> Bool
myAnd True  y = y
myAnd False _ = False

上面,我们可以单独列举False FalseFalse True情况,并使用三个方程,但使用通配符更方便(并且使我们的函数稍微懒惰,例如myAnd False undefined计算为False)。

最后,这主要是风格问题。通常,当通配符_只能代表一种情况时,最好把它拼出来,明确地说明它。这样,代码通常更具可读性。例如

not :: Bool -> Bool
not False = True
not _     = False

等效但比差

not :: Bool -> Bool
not False = True
not True  = False

case当然,表达也是如此。

case x of
  Just y  -> 1 + y
  Nothing -> 0

可以说比

case x of
  Just y -> 1 + y
  _      -> 0
于 2018-05-21T09:55:44.357 回答