<div dir="ltr"><div>This seems like the canonical illustration of the dangers of UndecidableInstances.  Normally an instance of the form "instance C1 a => C2 a" would be forbidden specifically because it does not exclude the possibility of some other "instance C2 a => C1 a" elsewhere that would create a loop.  UndecidableInstances disables this check, passing off on you (the programmer) the responsibility of ensuring that you don't actually do this.  You did, so you get the loop, and the compiler doesn't care because you told it not to.  <br></div><div><br></div><div>The reason the instance definitions don't loop during compilation is that the type "HasBool a => Has Bool a" conveniently furnishes a HasBool instance whence boolL can be obtained, so the compiler doesn't need to go looking for an instance elsewhere, and so doesn't go into an infinite recursion with the one that's on the next line.</div><div><br></div><div>The reason that even the line "runRIO () $ view boolL" doesn't cause the compiler to loop is that, although it does infer that a = (), and therefore does tie the knot with those two instances, it doesn't actually need to look farther than the "HasBool ()" part of "instance Has Bool () => HasBool ()" to get boolL, as the constraint is not used in selecting an instance, and since once that instance is selected it can easily also verify that we do have "instance Has Bool ()" in the same oblivious way.  It just happens that the particular definition of boolL that it gets is equivalent (after two round of substitution) to "boolL = boolL", which only loops when it is run.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Jul 23, 2018 at 2:10 PM, Theodore Lief Gannon <span dir="ltr"><<a href="mailto:tanuki@gmail.com" target="_blank">tanuki@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div style="font-size:small;text-decoration-style:initial;text-decoration-color:initial"><span style="font-family:monospace,monospace">λ. :set -XFlexibleContexts -XFlexibleInstances -XMultiParamTypeClasses -XUndecidableInstances</span><br></div><font face="monospace, monospace">λ. import RIO</font></div><div><font face="monospace, monospace">λ. import Data.Has</font></div><div><font face="monospace, monospace">λ. class HasBool a where boolL :: Lens' a Bool</font></div><div><font face="monospace, monospace">λ. instance {-#OVERLAPPABLE#-} HasBool a => Has Bool a where hasLens = boolL<br></font></div><div><font face="monospace, monospace">λ. instance {-#OVERLAPPABLE#-} Has Bool a => HasBool a where boolL = hasLens</font></div><div><font face="monospace, monospace">λ. runRIO () $ view boolL</font></div><div><font face="monospace, monospace">^CInterrupted.<br></font></div><div><br></div><div>The RIO environment <font face="monospace, monospace">()</font> doesn't contain a Bool. I can see how the typechecker might get lost in this, but I can compile an equivalent program; it loops on execution.</div></div>
<br>______________________________<wbr>_________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-<wbr>bin/mailman/listinfo/haskell-<wbr>cafe</a><br>
Only members subscribed via the mailman list are allowed to post.<br></blockquote></div><br></div>