简体   繁体   中英

Haskell types/type conversion (sqrt,floor)

I'm trying to implement the Cantor Pairing using Haskell. The encoding of a list of ints is working fine, the decoding however is just not working due to type errors.

I tried nearly everything I could think of, but nothing would work out:

cantorDecode :: Integer -> [Integer] -> [Integer]
cantorDecode e zs
    | length zs == 0    = cantorDecode y [x,y]
    | head zs == 0      = map toInteger $ tail zs    
    | otherwise         = cantorDecode y ((head zs)-1 : (tail zs) ++ [x,y])
        where
            a = fromRational e
            w = floor ((s-1.0)/2.0)
            s = fromIntegral $ sqrt(8.0*e+1.0) :: Double
            t = fromRational $ (w^2+w)/2.0
            y = toInteger $ e - (toInteger $ floor t)
            x = toInteger $ (toInteger w) - (toInteger y)
  1. input is the next Integer to decode
  2. input is the list with the already decoded Integers

As you can see, I'm using sqrt , floor and other things, so it's a bit messy...

OK that does look desperate. A couple points:

  1. You certainly don't want fromRational , since you have no actual Rational s here. Also, fromRational and toFractional are both strictly less general than their combination realToFrac , although you don't need that either - these are all for converting between different floating point/rational types, but you have only one involved, Double .
  2. You don't want toInteger , which is only for converting between different Integral types. You do want its generalization fromIntegral which converts from an Integral type to a general Num .

You should make a clear decision exactly which of your variables are Integer s, and which are Double s. Then use fromIntegral to convert from Integer to Double , and floor or another similar function to convert from Double to Integer , when necessary. You have several attempts there to convert between the same type (basically, all your toInteger s.)

Given this, you can clean your type-conversion code up into (adding explicit type annotations for clarity):

cantorDecode :: Integer -> [Integer] -> [Integer]
cantorDecode e zs
    | length zs == 0    = cantorDecode y [x,y]
    | head zs == 0      = tail zs    
    | otherwise         = cantorDecode y ((head zs)-1 : (tail zs) ++ [x,y])
        where
            w = floor ((s-1.0)/2.0)             :: Integer
            w' = fromIntegral w                 :: Double
            s = sqrt(8.0*fromIntegral e+1.0)    :: Double
            t = (w'^2+w')/2.0                   :: Double
            y = e - floor t                     :: Integer
            x = w - y                           :: Integer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM