
Anthony> I am interested in how you got into such a pickle in the first place: Anthony> Why set `AllowAmbiguousTypes`? Did you understand what that means? ----------------------^^^^^^^^^^^^^^^^^^^^
I read
https://stackoverflow.com/questions/49684655/how-dangerous-is-allowambiguous...
which seems to indicate that using it is "a perfectly reasonable thing"
Hmm, I don't think that's how you got into the pickle. That SO answer (and there are plenty on the subject) says the "combination" of `AllowAmbiguousTypes` + `TypeApplications` is reasonable. But your first post had `AllowAmbiguousTypes` without `TypeApplications`. That is not "a perfectly reasonable thing"; no SO answer says it is. If you had already looked at that SO answer, how did you not use `TypeApplications`? Let me suggest how you got into the pickle, because there is a repeated experience here which is poor for learners: You wrote the method signature for `toBool`. That's ambiguous. GHC gave you an error message suggesting `AllowAmbiguousTypes` might get the method signature to compile -- which it did. `AllowAmbiguousTypes` works at the declaration site, not the usage site. Which is why: * It doesn't make sense to switch it on everywhere -- as one of the SO comments suggests. * It does need you to take action at the usage site, but GHC's message doesn't tell you that. * So your first post showed more `ambiguous` rejections at the usage site. * What's more there was a red herring about non-injective type families. * And to fix it per Li-yao's suggestion needs a whole bunch more extensions, * including the deeply flawed `ScopedTypeVariables`, * when the simpler `PatternSignatures` would be more appropriate -- except that's now deprecated. * `AllowAMbiguousTypes` is module-wide: that means you get no validation of any of your method sigs; although probably you mean only a few of the to be ambiguous. * Then any/every usage site for any method might turn out to be ambiguous. IMO GHC has got itself into a total mess in this bit of the language, and the error messages lead learners rapidly into deep water. I think `AllowAmbiguousTypes` might as well be spelled `AllhopeAbandonTypes`. Those other extensions might be the best approach for your full requirements, but might not. So as to other possible designs: * I didn't want to get into the FunDeps vs TypeFamilies war. * If method `toBool` is only going to be called on the result of `toSubAmbi`, I would go
toBool :: a -> Bool -- not ambiguous
instance Ambi blah where type SubAmbi blah = ... toSubAmbi x = ... toBool x = case toSubAmbi x of { ... -> True; _ -> False }
Then in your `whatsWrong` function, call only `toBool`. So the instances are a little more verbose but the usage sites are more succinct and don't need all those extensions. AntC