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.
Often an underscore character in Haskell code represents something we don't care about or don't know about – whether it's a wildcard, a hole, or a discarded result. Underscores appear both in types and in terms.
An underscore in front usually indicates an instance variable as opposed to a local variable. It's merely a coding style that can be omitted in favor of "speaking" variable names and small classes that don't do too many things. Follow this answer to receive notifications.
(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.
Foo (pronounced FOO) is a term used by programmers as a placeholder for a value that can change, depending on conditions or on information passed to the program. Foo and other words like it are formally known as metasyntactic variables.
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.)
It's just a convention to mark an unused variable. As you see, _f
isn't used in the definition of #.
, so it is marked with the underscore.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With