Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this a useful warning in Haskell when pattern matching? "Defined but not used"

In defining multiple pattern matches for a function, for instance as follows:

1: takeTree 0 tree                           = Leaf
2: takeTree levels (Leaf)                    = Leaf
3: takeTree levels (Branch value left right) = Branch value (takeTree...

I get two warnings in particular:

Source.hs:1: Warning: Defined but not used: `tree'

Source.hs:2: Warning: Defined but not used: `levels'

I'm not immediately convinced these are useful warnings though. If my code were instead:

1: takeTree 0 _                              = Leaf
2: takeTree _ (Leaf)                         = Leaf
3: takeTree levels (Branch value left right) = Branch value (takeTree...

which, fixes the warnings, I now find it to be far less readable, and obfuscates the semantics of what I expect as input values.

Why is Defined but not used a reasonable warning at all here, when among my exhaustive patterns each argument is in fact used at least once?

like image 537
DuckMaestro Avatar asked Jan 13 '13 23:01

DuckMaestro


People also ask

What does pattern matching mean in Haskell?

Pattern matching consists of specifying patterns to which some data should conform and then checking to see if it does and deconstructing the data according to those patterns. When defining functions, you can define separate function bodies for different patterns.

Does Haskell have pattern matching?

We use pattern matching in Haskell to simplify our codes by identifying specific types of expression. We can also use if-else as an alternative to pattern matching. Pattern matching can also be seen as a kind of dynamic polymorphism where, based on the parameter list, different methods can be executed.

What is pattern matching in Haskell?

In Haskell pattern matching does the same thing, which they or attempt to match any given value or user passed value to the function, after this we can return any value we want or simply we can assign the value to the variable and return it.

What is Haskell syntax and why is it important?

Given the central role that functions play in Haskell, these aspects of Haskell syntax are fundamental. Pattern matching consists of specifying patterns to which some data should conform, then checking to see if it does, and de-constructing the data according to those patterns.

What happens if we do not provide catch all block in Haskell?

2) catch all block: If we do not provide the catch all block then it will throw as error, because while doing pattern matching it will not able to find anything and throw us error. If you provide the catch block then the error can be avoided also, it is safer to use also known as default pattern matching block in Haskell.

How does pattern matching work with lists?

As for lists, they are no different from data -defined algebraic data types as far as pattern matching is concerned. It works as if lists were defined with this data declaration (note that the following isn't actually valid syntax: lists are actually too deeply ingrained into Haskell to be defined like this):


3 Answers

The assumption that if something was important enough to name it must be important enough to use is reasonable in many styles of coding.

But you can have your cake and eat it too:

takeTree 0 _tree                           = Leaf
takeTree _levels (Leaf)                    = Leaf
takeTree levels (Branch value left right)  = Branch value (takeTree...

The leading underscore in the name signals to both the human reader and the compiler that the name is not intended to be used in this equation, but the name being longer than a single underscore can still convey more meaning to the human.

like image 73
Ben Avatar answered Sep 21 '22 05:09

Ben


I've made coding errors that were pointed out by this warning. Simplified example:

fun x xs = go xs
  where
    go []      = ... 
    go (y:xs') = f y (go xs)

The recursive call should have xs' as argument, of course, and the "defined but not used" warning will catch that. To me, that's worth the inconvenience of using _ for unused matches.

The compiler is not able to guess your intentions, and the fact that you used the argument in another match does not mean that you didn't mean to use it in the match that generates the warning. After all, you could have used tree, so the warning that you didn't is reasonable.

See also the answer by Ben: you can use _name to use a name but still suppress the warning.

like image 23
Chris Avatar answered Sep 22 '22 05:09

Chris


The compiler's trying to suggest that you use a certain style of coding. If you don't like it (fair enough), there's a way to avoid the problem. See e.g.:

How to [temporarily] suppress "defined but not used" warnings?

As to the substance of the matter (whether or not this is a useful warning): the downside of naming your variables in such situations is it suggests that the names are meaningful to the compiler, when they're not. The upside, as you rightly point out, is that they are meaningful to humans. Basically there's a trade-off and it's quite subjective. The important thing is that you can get the behaviour you want if desired.

like image 33
Stuart Golodetz Avatar answered Sep 22 '22 05:09

Stuart Golodetz