Your issue is that, although you've tried to fix it in a variety of ways, you haven't tried to do something x
, which is exactly where your problem lies. Let's look at the type of sqrt
:
Prelude> :t sqrt
sqrt :: (Floating a) => a -> a
On the other hand, x
is an Int
, and if we ask GHCi for information about Floating
, it tells us:
Prelude> :info Floating
class (Fractional a) => Floating a where
pi :: a
<...snip...>
acosh :: a -> a
-- Defined in GHC.Float
instance Floating Float -- Defined in GHC.Float
instance Floating Double -- Defined in GHC.Float
So the only types which are Floating
are Float
s and Double
s. We need a way to convert an Int
to a Double
, much as floor :: (RealFrac a, Integral b) => a -> b
goes the other direction. Whenever you have a type question like this, you can ask Hoogle, a Haskell search engine which searches types. Unfortunately, if you search for Int -> Double
, you get lousy results. But what if we relax what we're looking for? If we search for Integer -> Double
, we find that there's a function fromInteger :: Num a => Integer -> a
, which is almost exactly what you want. And if we relax our type all the way to (Integral a, Num b) => a -> b
, you find that there is a function fromIntegral :: (Integral a, Num b) => a -> b
.
Thus, to compute the square root of an integer, use floor . sqrt $ fromIntegral x
, or use
isqrt :: Integral i => i -> i
isqrt = floor . sqrt . fromIntegral
You were thinking about the problem in the right direction for the output of sqrt
; it returned a floating-point number, but you wanted an integer. In Haskell, however, there's no notion of subtyping or implicit casts, so you need to alter the input to sqrt
as well.
To address some of your other concerns:
intSqrt :: Int -> Int
intSqrt x = floor (sqrt (x + 0.0))
You call this "nonsense", so it's clear you don't expect it to work, but why doesn't it? Well, the problem is that (+)
has type Num a => a -> a -> a
—you can only add two things of the same type. This is generally good, since it means you can't add a complex number to a 5×5 real matrix; however, since 0.0
must be an instance of Fractional
, you won't be able to add it to x :: Int
.
It seems that (sqrt 500) works fine…
This works because the type of 500
isn't what you expect. Let's ask our trusty companion GHCi:
Prelude> :t 500
500 :: (Num t) => t
In fact, all integer literals have this type; they can be any sort of number, which works because the Num
class contains the function fromInteger :: Integer -> a
. So when you wrote sqrt 500
, GHC realized that 500
needed to satisfy 500 :: (Num t, Floating t) => t
(and it will implicitly pick Double
for numeric types like that thank to the defaulting rules). Similarly, the 0.0
above has type Fractional t => t
, thanks to Fractional
's fromRational :: Rational -> a
function.
… but (sqrt x) insists on x being a Floating …
See above, where we look at the type of sqrt
.
… and there is no function I can find to convert an Int to a real ….
Well, you have one now: fromIntegral
. I don't know why you couldn't find it; apparently Hoogle gives much worse results than I was expecting, thanks to the generic type of the function.
Why is this so hard?
I hope it isn't anymore, now that you have fromIntegral
.
sqrt 500
is valid because 500 is a valid literal for a floating point number. Howeversqrt (500 :: Int)
would be invalid. – FeverFloat
,Double
,floor
?:squares = map (\x -> x * x) [0 ..]
squareRoot n = last $ takeWhile (<= n) squares
– Scudder