Haskell underscore vs. explicit variable

2020-08-26 11:43发布

问题:

I've been learning Haskell for a few weeks, and I have a question about the use of the underscore (_) as a function parameter. I think my question will be better asked with a specific example. Let's say I want to define a function that extracts the element of a list based on the provided index—yes, I realize (!!) is already pre-defined. The two ways that I can define the function (I'm sure there are more) are the following:

Version 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)

Version 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)

The two versions are obviously very similar. The only difference between the two is the use of an explicit variable or an underscore. To me _ means that literally anything can be written there while an explicit variable like n makes it more obvious that the argument must be an integer. For that reason, I prefer Version 1; but the GHC source code for (!!) is written like Version 2. Is there a functional advantage of the second version? If not, would "hardcore" Haskell programmers take issue with Version 1? I understand the importance of having a consistent way of writing code, so I try to follow the "unwritten rules" for programming in a particular language. This is an example where I much prefer the first version though, and I don't think it makes the code any more difficult to read. I don't know if it's due to my background in pure math or what, but I'd like to hear what you more-seasoned-Haskell vets think.

回答1:

Is there a functional advantage of the second version?

I don't think they have any operational difference. But I find the second version more readable. _ indicates that it isn't used at all. So while reading the code, I can just ignore it and just concentrate on the other parameters. Whereas in the first version, I will be thinking that n is defined but maybe the author forgot to use it ? Or maybe the argument isn't required. The second version just avoids this kind of mental overload. But this is just my opinion. :)

In fact, if you enable the warning flag (-Wall) and compile your code, it will throw warning for your first version:

[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’


标签: haskell