[Haskell-cafe] Ambiguous types

Juan Casanova juan.casanova at ed.ac.uk
Wed Aug 7 12:53:17 UTC 2019

There are two important things to say about your e-mail, but one is a  
lot more important than the other.

> And no, I don't want the general code to be specific for lists, thus  
> no extra type
> signatures or changes to make it more list of Ints.

You did not understand my (and Paolino's) point about using lists. By  
using lists *internally* you're not making it less generic. The  
function still works for any foldable. But you are building another  
foldable *within your function* as a way to check for duplication,  
that isn't returned. When you build an element, you need to specify  
it's type (or use a function passed as parameter to build it). In this  
case, list is just as good as any other foldable for the internal  
workings. You can use another foldable if you wish, but you need to  
use some foldable, because Foldable itself is only a behavioural  
definition that cannot be used directly. Thus, what I personally said  
about efficiency was in the case that you wanted the user to be able  
to *specify as an argument* what instance of Foldable to use for this.  
If you don't care about efficiency, then use lists, or any other  
foldable of your choice.

Let me see if I can make this clearer with an analogy. You go to a  
workshop and ask them to build a metal bar for you. You say: it needs  
to be this size, this weight and be able to resist this amount of  
strength (that would be equivalent to the typeclass, it needs to be  
Foldable). Now, what would break the transparency that typeclasses and  
genericity provide would be if they asked you: "what are you going to  
use this metal bar for?". They don't need to know, as long as they  
produce a metal bar that fulfills your requirements. So far so good.  
But now, imagine that you asked them: "I want you to build the metal  
bar in such a way that it is independent of the tools that you have  
available". They would be puzzled. Why do you care what tools they use  
to build the metal bar? You want a metal bar with a set of  
characteristics, you will get it. How they build the metal bar and how  
specific that building of the metal bar may be is absolutely  
irrelevant to you. This is the list. The list (or any other foldable  
that you wish to use), is just the tool that you use to check for  
duplicity. It is *not* the output result of your function. So using it  
does not break genericity in any way.

The second, slightly less important point, is about the type  
signatures. You want GHC to derive the signatures on its own? Fine.  
Take the code that I provided you, and remove the type signatures. It  
compiles, it works, and it infers exactly the same type signatures  
that I provided. There are two reasons for which I think your approach  
that "it is better if I don't specify the type signatures" is mistaken.

First, the reason you want to provide type signatures is because it  
makes the code clearer. Saying that "GHC should derive the type  
signatures" is a bit like writing a mono-function program and saying  
"the compiler should not care about how long my functions are". Type  
signatures help the programmer understand what the functions do, help  
you program by making it easier to see if you can use a function or  
not by looking at its type signature, and make it easier to debug by  
modularizing the problems.

Second, depending on what extensions you use (and you are using  
RankNTypes and KindSignatures, which are not trivial extensions), type  
signatures on functions or type annotations might not be avoidable,  
precisely because of ambiguity. In this particular case, they can be  
removed, as I said, but there are some programs that are inevitably  
ambiguous unless you explicitly specify the types. And this is not a  
GHC limitation, it is a mathematical limitation of the programming  
model, so type signatures are not optional sometimes.

But, as I said, if you really disagree and prefer not to provide type  
signatures, then don't. The code I provided still works perfectly, and  
the reason why using lists internally does not break genericity still  
holds regardless of that.


Quoting Dušan Kolář <kolar at fit.vut.cz> on Wed, 07 Aug 2019 14:38:12 +0200:

> Thanks all for the answers, and no, they are not what I was asking for...
> Not providing type signatures, yes, no type signatures provided, GHC  
> should derive
> them on its own. My question was, why it is not able to do that and  
> how force GHC
> to do that. Without extra type info...
> The original type signature was simple: chkDup :: (Eq a, Num a) =>  
> [a] -> Bool
> I would be quite happy to have something similar, just for [] to  
> have some generic
> type - auto-magically :-)
> And no, my intention was not to make it a bit faster for larger  
> inputs, just make
> clear and clean code without extra type signatures, easy to read and  
> simple to
> understand. Real-life input has 36 six members at most.
> So thank you once again, unfortunately, my conclusion is that  
> writing generic code
> is not always beneficial - neither for reading nor for generality...
> Thank you once again,
> Dušan

The University of Edinburgh is a charitable body, registered in
Scotland, with registration number SC005336.

More information about the Haskell-Cafe mailing list