Proposal: change the Bits instance for Bool to align with other basic types and support branchless calculations

Anthony Cowley acowley at seas.upenn.edu
Mon Sep 29 14:14:03 UTC 2014


On Sun, Sep 28, 2014 at 11:06 PM, Gershom B <gershomb at gmail.com> wrote:
> Did I miss in this thread an actual use-case for strict and/or for Bool such that it might occur in a tight inner loop? Absent such a use case, I’m -1 on this proposal. If I wanted to use something that I felt had strict bitwise behaviour, I’d never reach for a bool, no matter what operator set I was working with. My instinct would be to reach for a Word8 or the like, since on any real implementation it would take up the same space regardless?
>
> Essentially, to my laziness-infected brain, the current instance obeys the principle of least surprise, and the proposed instance violates the sort of wall of “abstraction intuitions” I’ve built up regarding when I should and shouldn’t expect lazy behaviour.
>
> -g

The problem is that Bool is the odd duck with respect to the Data.Bits
operations, so the only way your intuition would serve you is if you
were sure you would only be working with Bool, in which case the
question is why you were reaching for Data.Bits.

Anthony


>
>
> On September 27, 2014 at 1:59:43 PM, David Feuer (david.feuer at gmail.com) wrote:
>> Currently, the (.&.) and (.|.) methods for Bool are short-circuiting,
>> defined like this:
>>
>> instance Bits Bool where
>> (.&.) = (&&)
>>
>> (.|.) = (||)
>>
>> Unlike the instances for Int, Word, etc., this gives short-circuiting
>> behavior (conditionally lazy in the second operand). Unfortunately, this
>> requires a conditional branch to implement, which can sometimes be bad.
>> Since (&&) and (||) are readily available to anyone who wants
>> short-circuiting, I propose that we use the following instead. Note that
>> the Bits class does not specify anything about this aspect of instance
>> behavior.
>>
>> x .&. y = tagToEnum# (dataToTag# x `andI#` dataToTag# y)
>>
>> x .|. y = tagToEnum# (dataToTag# x `orI#` dataToTag# y)
>>
>> The rest of the operations look like this:
>>
>> x `xor` y = tagToEnum# (dataToTag# x `xorI#` dataToTag# y)
>>
>> complement x = tagToEnum# (dataToTag# x `xorI#` 1#)
>>
>> shift x s = testBit x s
>>
>> rotate x _ = x
>>
>> -- I don't think we gain anything changing this one.
>> bit 0 = True
>> bit _ = False
>>
>> testBit x b = tagToEnum# (dataToTag# x `andI#` (dataToTag# b ==# 0#))
>>
>> bitSizeMaybe _ = Just 1
>>
>> bitSize _ = 1
>>
>> isSigned _ = False
>>
>> popCount x = I# (dataToTag# x)
>>
>> instance FiniteBits Bool where
>> finiteBitSize _ = 1
>> countTrailingZeros x = I# (dataToTag# x `xorI#` 1#)
>> countLeadingZeros x = I# (dataToTag# x `xorI#` 1#)
>> _______________________________________________
>> Libraries mailing list
>> Libraries at haskell.org
>> http://www.haskell.org/mailman/listinfo/libraries
>>
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://www.haskell.org/mailman/listinfo/libraries


More information about the Libraries mailing list