On Fri, Jul 27, 2012 at 3:42 PM, Ian Lynagh <span dir="ltr">&lt;<a href="mailto:igloo@earth.li" target="_blank">igloo@earth.li</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Fri, Jul 27, 2012 at 03:06:04PM -0400, Edward Kmett wrote:<br>
&gt; There is currently no way to know whether or not calling<br>
</div>&gt; Data.Bits.bitSizewill crash your program.<br>
<div class="im">&gt;<br>
&gt; I propose extending the Bits class to include:<br>
&gt;<br>
&gt; hasBitSize :: Bits b =&gt; b -&gt; Bool<br>
&gt;<br>
&gt; such that it returns False for Integer and True for the other instances<br>
<br>
</div>Can you give an example of a situation in which you would use<br>
hasBitSize, and do something useful if it returned False?<br></blockquote><div><br></div><div>The following can only work if bitSize is well defined.</div><div><br></div><div>traverseBits :: (Applicative f, Bits b) =&gt; (Bool -&gt; f Bool) -&gt; b -&gt; f b </div>
<div>traverseBits f b = snd . Prelude.foldr step (bitSize b - 1,0) &lt;$&gt; traverse (f . testBit b) [0 .. bitSize b - 1] where</div><div>  step True (n,r) = (n - 1, setBit r n)</div><div>  step _    (n,r) = (n - 1, r)</div>
<div> </div><div>to work around this I&#39;ve had to use:</div><div><br></div><div><div>traverseBits :: (Applicative f, Bits b) =&gt; (Bool -&gt; f Bool) -&gt; b -&gt; f b </div><div>traverseBits f b = Prelude.foldr step 0 &lt;$&gt; traverse g bits</div>
<div>  where</div><div>    g n      = (,) n &lt;$&gt; f (testBit b n)</div><div>    bits     = Prelude.takeWhile hasBit [0..]</div><div>    hasBit n = complementBit b n /= b -- test to make sure that complementing this bit actually changes the value</div>
<div>    step (n,True) r = setBit r n</div><div>    step _        r = r</div></div><div><br></div><div>where I&#39;m manually probing each bit to see that changing it changes the value.</div><div><br></div><div>Used with the other combinators in lens the former just crashes when you use</div>
<div><br></div><div><div><div>foldMapOf :: ((c -&gt; Const m d) -&gt; a -&gt; Const m b) -&gt; (c -&gt; m) -&gt; a -&gt; m</div></div><div>foldMapOf l f = getConst . l (Const . f)</div></div><div><br></div><div>toListOf :: ((c -&gt; Const [c] d) -&gt; a -&gt; Const [c] b) -&gt; a -&gt; [c]</div>
<div><div>toListOf l = foldMapOf l return</div></div><div><br></div><div>Now when we use it with an explicit signature both of these can do reasonable things:</div><div><br></div><div><div>ghci&gt; toListOf traverseBits (5 :: Int)</div>
<div>[True,False,True,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False]</div>
<div><br></div><div>But with defaulting choosing Integer</div><div>ghci&gt; toListOf traverseBits 5</div><div><br></div><div>the former instance will crash, whereas the latter properly returns an infinite lazy list</div><div>
<br></div><div>[True,False,True,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,False,...</div>
</div><div><br></div><div>It would be much nicer not to have to probe using complementBit creating ever larger temporary integers just to see if the list of valid bit positions hadn&#39;t been exhausted.</div><div><br></div>
<div>Then I could test at the start to know whether I should use [0..] or [0..bitSize-1] and get away with much less code and much less unnecessary memory allocation.</div><div><br></div><div>-Edward</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Would it be better to move bitSize into a separate class?</blockquote><div><br></div><div>I don&#39;t think so. Ultimately, you should be able to know for every numeric type if it has a fixed or variable number of bits. In a perfect world &#39;d rather just have bitSize return a Maybe that way we don&#39;t have to truck with partial functions in the API.  </div>
<div><br></div><div>However, the case for just adding hasBitSize is that it avoids breaking existing code.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">
&gt; since the vast majority of instances are finite, it may be reasonable to<br>
&gt; set the default definition to<br>
&gt;<br>
&gt; hasBitSize _ = False<br>
<br>
</div>Did you mean True?<br></blockquote><div> </div><div>Yes</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Either way, I think I would personally prefer not to have a default, so<br>
that people need to actually check existing instances.</blockquote><div><br></div><div>Also perfectly reasonable. </div><div><br></div><div>-Edward</div></div>