Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell's if statement for error checking

Tags:

haskell

I wrote a function for the Haar wavelet transformation given that the input is a List with a power of 2. I was trying to error check by making sure that the length of the List is a power of 2 before preforming the transformation. I am comparing the log base 2 of the length of the list to see if it comes out evenly (nothing to the right of the decimal point). I think there is something going on with the if statement in haskell that I am not used to in other languages. It works perfectly if I don't error check and just call haar with the proper argument.

haar :: (Fractional a) => [a] -> [a]
haar xs = if logBase 2 (fromIntegral (length xs)) /= truncate (logBase 2 (fromIntegral (length xs)))
             then error "The List must be a power of 2"
             else haarHelper xs (logBase 2 (fromIntegral (length xs)))

haarHelper xs 1 = haarAvgs xs ++ haarDiffs xs
haarHelper xs level = haarHelper (haarAvgs xs ++ haarDiffs xs) (level - 1)

haarAvgs [] = []
haarAvgs (x:y:xs) = ((x + y) / 2.0) : haarAvgs xs 

haarDiffs [] = []
haarDiffs (x:y:xs) = ((x - y) / 2.0) : haarDiffs xs

I am getting the following error message:

functions.hs:52:13:
    Ambiguous type variable `t' in the constraints:
      `Floating t'
        arising from a use of `logBase' at functions.hs:52:13-48
      `Integral t'
        arising from a use of `truncate' at functions.hs:52:53-99
    Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
like image 267
Ben Avatar asked Apr 22 '26 20:04

Ben


2 Answers

There's a much simpler and faster implementation to check that a positive integer is a power of two:

import Data.Bits

powerOfTwo' n = n .&. (n-1) == 0

(Note: this omits the check that n is positive, assuming we can rely on it coming from length.)

Explanation, for the curious:

This algorithm relies on the unique property that only powers of 2 have a single 1 bit (by definition), and decrementing them inverts all the lower bits:

2^n      =  100000...
2^n - 1  =  011111...

This leaves no bits in common, making their bitwise-and zero.

For all non-powers-of-two, the decrement will leave at least the highest 1 bit unchanged, keeping the bitwise-and result non-zero.

(Wikipedia: Fast algorithm to check if a positive number is a power of two)

like image 111
Pi Delport Avatar answered Apr 30 '26 04:04

Pi Delport


haar :: (Fractional a) => [a] -> [a]
haar xs | r /= (truncate r) = error "The List must be a power of 2"
        | otherwise = haarHelper xs (logBase 2 (fromIntegral (length xs)))
            where r = logBase 2 (fromIntegral (length xs))

Yea, seems like its something with truncate. Easier way to write if then statements with haskell is shown above. Might help with the debugging a bit.

I think i may know. I think truncate is returning an int where the other number is a float.

Try this

haar :: (Fractional a) => [a] -> [a]
haar xs | r /= w = error "The List must be a power of 2"
        | otherwise = haarHelper xs (logBase 2 (fromIntegral (length xs)))
            where 
                r = logBase 2 (fromIntegral (length xs))
                w = intToFloat (truncate r) 

haarHelper xs 1 = haarAvgs xs ++ haarDiffs xs
haarHelper xs level = haarHelper (haarAvgs xs ++ haarDiffs xs) (level - 1)

haarAvgs [] = []
haarAvgs (x:y:xs) = ((x + y) / 2.0) : haarAvgs xs 

haarDiffs [] = []
haarDiffs (x:y:xs) = ((x - y) / 2.0) : haarDiffs xs

intToFloat :: Int -> Float
intToFloat n = fromInteger (toInteger n)
like image 37
Matt Avatar answered Apr 30 '26 02:04

Matt