问题
I'm learning Haskell and stuck trying to understand the type system.
I'm trying to write a function which returns the length of the series 'Half or Three Plus One' for an input. Here's my attempt at the function, using a recursive approach (the function is valid for integral inputs only):
hotpo :: (Integral a) => a->a
hotpo n = hotpoHelper n 1
hotpoHelper:: (Integral a) => a->a->a
hotpoHelper 1 n = n
hotpoHelper num count
| even num = hotpoHelper (truncate (num/2)) (count+1)
| otherwise = hotpoHelper (3*num+1) (count+1)
Here is the error I get when I try to load this file in GHC 6.12.3
test.hs:8:30:
Could not deduce (RealFrac a) from the context (Integral a)
arising from a use of `truncate' at test.hs:8:30-45
Possible fix:
add (RealFrac a) to the context of
the type signature for `hotpoHelper'
In the first argument of `hotpoHelper', namely
`(truncate (num / 2))'
In the expression: hotpoHelper (truncate (num / 2)) (count + 1)
In the definition of `hotpoHelper':
hotpoHelper num count
| even num = hotpoHelper (truncate (num / 2)) (count + 1)
| otherwise = hotpoHelper (3 * num + 1) (count + 1)
take (truncate (5/2)) [1,2,3]
works, so I'm unable to understand this error message.
Where am I going wrong?
回答1:
The /
operator in Haskell is used for floating point division. If you really did want to use floating point division and truncate
, you'd use fromIntegral
on num
first to convert it to a floating point number. The error you get is saying that you can't use fractional division on an integral number (5/2 works because the compiler infers a floating point type for both numbers). However, you can do what you want much more easily, using the div
function. This is typically used infix, by surrounding the function name with backquotes (this works for any Haskell function):
| even num = hotpoHelper (num `div` 2) (count+1)
来源:https://stackoverflow.com/questions/4203178/haskell-problem-converting-result-of-division-to-integral-type