xblax
xblax

Reputation: 223

Type casting in haskell, Fractional and Int

I've written a function that (should) takes an infinite list of booleans and calculate the ratio of True to False values over the first n elements:

prob n list = foldr (+) 0 (map boolToInt (take n list)) / n
    where boolToInt b
        | b == True = 1
        | otherwise = 0

unfortunately that's not working:

No instance for (Fractional Int)
  arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Int)
In the expression: foldr (+) 0 (map boolToInt (take n list)) / n
In an equation for `prob':
    prob n list
      = foldr (+) 0 (map boolToInt (take n list)) / n
      where
          boolToInt b
            | b == True = 1
            | otherwise = 0
Failed, modules loaded: none.

I tried to make a conversion, but that isn't working either:

prob n list = foldr (+) 0 (map boolToInt (take (fromIntegral (toInteger n)) list)) / n
    where boolToInt b
        | b == True = 1
        | otherwise = 0

It's compiling, but as soon as I try to call the function I get an error:

*Main> prob 50 toCoin1
<interactive>:1:6:
Ambiguous type variable `a0' in the constraints:
  (Num a0) arising from the literal `50' at <interactive>:1:6-7
  (Integral a0) arising from a use of `prob' at <interactive>:1:1-4
  (Fractional a0) arising from a use of `prob' at <interactive>:1:1-4
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `prob', namely `50'
In the expression: prob 50 toCoin1
In an equation for `it': it = prob 50 toCoin1

Any suggestions?

Upvotes: 3

Views: 7822

Answers (2)

pat
pat

Reputation: 12749

Bool is an instance of Enum, so boolToInt is already provided by fromEnum. Also, the foldr is doing sum, so the whole function can be simplified to:

prob n list = (fromIntegral . sum . map fromEnum . take n) list / fromIntegral n

We could abstract out the code for computing the mean (although this will have to determine the length of the list, which we already know):

mean xs = (fromIntegral . sum) xs / (fromIntegral . length) xs

prob n = mean . map fromEnum . take n

Upvotes: 0

Lily Ballard
Lily Ballard

Reputation: 185871

You're converting at the wrong place. Try just sticking a fromRational around the entire foldr and n.

prob n list = fromIntegral count / fromIntegral n
    where count = foldr (+) 0 (map boolToInt (take n list))
          boolToInt b
            | b == True = 1
            | otherwise = 0

Oh, and your boolToInt function is identical to fromEnum specialized to Bools.

prob n list = fromIntegral count / fromIntegral n
    where count = foldr (+) 0 (map fromEnum (take n list))

The fundamental problem with what you tried to do was you imposed conflicting requirements on the first argument to prob. Your use of toInteger constrained n to be Integral, but its use in / required that it be Fractional, and there's no type that's both Integral and Fractional.

Upvotes: 11

Related Questions