What, in Haskell, does an underscore preceding a variable mean?

  • A+

I was browsing the source of Data.Foldable, where I came accross Endo #. f, and upon clicking this link, was confronted with:

(#.) _f = coerce 

Now, first, I don't know what coerce and the before-that mentioned Coercible is, however, it baffles me more what the _f could mean. I have searched "Haskell underscore before variable" and similar and have only found discussions about the _ pattern matching syntax.


According to the Haskell spec, it is just another possible name for a variable. But the truth is a bit longer, because most Haskell developers write code specifically for GHC, and this is one of those times.

GHC has lots of helpful warnings; one is to warn you when you write a pattern that binds a variable that isn't used in the body of the function. It's pretty handy, and has caught a couple bugs of mine. However, it has a knock-on effect: if you write a function that uses some of the variables only in one clause or the other, you get a warning. For example, here is a very natural definition of foldr on lists:

 foldr f z [] = z  foldr f z (x:xs) = x `f` foldr f z xs 

Oops! We didn't use f in the first clause, and we'll get a warning. Okay, so it's easy enough to fix:

foldr _ z [] = z foldr f z (x:xs) = x `f` foldr f z xs 

Unfortunately now we've lost the information about what that first variable's role in the code is supposed to be. In this case, foldr is so familiar that it's no big loss, but in unfamiliar codebases with functions that take a lot of arguments, it can be nice to know what data is ignored by each "hole". So GHC adds a special rule: the warning about unused variables doesn't warn you about variable names that start with _ -- by analogy to the _ pattern that it also doesn't warn you about. So now I can write:

foldr _f z [] = z foldr  f z (x:xs) = x `f` foldr f z xs 

Now I get the best of both worlds: I get a nice warning if I forget to use a variable I bound, and I can still give the reader information about the meaning of the holes in patterns that I don't need for the current clause. (As a side note, I'd love an additional warning that reported if I do mistakenly use a variable starting with _, but I don't think it exists at the moment! It sounds stupid ("just don't type _ in a function body"), but I've found my editor's tab-completion occasionally inserting them for me, and it would be easy not to notice if you were coding quickly.)


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: