我已经学习Haskell几周了,我对使用下划线(_
)作为函数参数有疑问。我想用一个具体的例子可以更好地问我的问题。假设我想定义一个函数,该函数根据提供的索引提取列表元素 - 是的,我意识到(!!)
已经预定义了。我可以定义函数的两种方式(我确定还有更多)如下:
版本1
indexedElement :: [a] -> Int -> a
indexedElement xs n | n < 0 = error "Index can not be negative."
indexedElement [] n = error "Index must be smaller than the length of the list."
indexedElement (x:xs) 0 = x
indexedElement (x:xs) n = indexedElement xs (n - 1)
版本2
indexedElement :: [a] -> Int -> a
indexedElement _ n | n < 0 = error "Index can not be negative."
indexedElement [] _ = error "Index must be smaller than the length of the list."
indexedElement (x:_) 0 = x
indexedElement (_:xs) n = indexedElement xs (n - 1)
这两个版本显然非常相似。两者之间的唯一区别是使用显式变量或下划线。对我来说_
意味着字面上可以写任何东西,而像n
这样的显式变量使得参数必须是整数更明显。出于这个原因,我更喜欢第1版;但(!!)
的GHC源代码与版本2类似。第二版是否具有功能优势?如果没有,那么“硬核”Haskell程序员会不会对版本1有疑问?我理解使用一致的编写代码的方法的重要性,因此我尝试遵循用于特定语言编程的“不成文规则”。这是一个我非常喜欢第一个版本的例子,我认为它不会让代码更难阅读。我不知道这是因为我的纯数学背景还是什么,但我想听听你更多经验丰富的人--Haskell兽医认为。
答案 0 :(得分:18)
第二个版本有功能优势吗?
我认为他们没有任何操作上的差异。但我发现第二个版本更具可读性。 _
表示根本没有使用它。因此,在阅读代码时,我可以忽略它,只关注其他参数。在第一个版本中,我会认为n
已定义,但作者可能忘了使用它?或者也许这个论点是不必要的。第二个版本只是避免了这种心理超负荷。但这只是我的意见。 :)
事实上,如果您启用警告标志(-Wall
)并编译代码,它将为您的第一个版本发出警告:
[1 of 1] Compiling Main ( code.hs, code.o )
code.hs:2:16: Warning: Defined but not used: ‘xs’
code.hs:3:19: Warning: Defined but not used: ‘n’
code.hs:4:19: Warning: Defined but not used: ‘xs’
code.hs:5:17: Warning: Defined but not used: ‘x’
code.hs:8:17: Warning: Defined but not used: ‘xs’