解释一下这个 Haskell 函数 "list of tuples to list"。

5
我是一名初学者,基本上我需要解释关于此问题的这个
他用以下代码回答:
tupleToList :: [(a,a)] -> [a]
tupleToList ((a,b):xs) = a : b : tupleToList xs
tupleToList _          = []

但我不理解为什么他不使用以下内容:
tupleToList [] = []
tupleToList ((a,b):xs) = a : b : tupleToList xs

就像我通常在指南的第一项练习中看到的那样。 我知道'_'表示任何内容,但是使用'[]'表示空列表不是更好吗?


1
我也是Haskell的初学者...但我认为它们是等价的。你的看起来更好看。 (虽然我更喜欢将“[]”情况放在第二行。) - Mateen Ulhaq
2个回答

9
就像我通常在指南的第一个练习中看到的那样。我知道_是任何东西,但是使用[]不是更好,表示列表为空吗?
从语义上讲,两者是相同的,因为2元组只有一个构造函数(a,b),而列表有两个构造函数[](h:t)
由于第一个子句没有匹配的模式是空列表,因此通配符_等同于[]
由于[]((a,b):xs)互斥模式(即没有值可以同时匹配两个模式),因此当显式使用[]时,两个模式的顺序无关紧要。我们可以按任意顺序编写它。
一些Haskell程序员喜欢使用显式模式(因此使用[]而不是_),因为这意味着我们知道我们实际处理的值是哪些。如果以后Haskell社区决定引入其他列表构造函数(对于列表而言是非常不可能的,但对于其他data类型来说可能更合理),Haskell编译器可以(使用-Wincomplete-patterns)警告某些模式不被覆盖。通配符当然涵盖所有模式,但也许右侧的表达式并不是我们打算为附加构造函数使用的表达式。
因此,我建议仅在您想通过同一子句匹配多个模式时使用通配符。如果其他模式清楚,则最好明确。就像Python的Zen所说(是的,它是Python,但大多数概念在某种程度上都是通用的):“显式胜于隐式”。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接