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-allowambiguoustypes-when-used-with-typeapplications>
>
> 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 }