Ваша проблема в том, что, хотя вы пытались исправить это различными способами, вы не пытались что-то сделать x
, именно в этом и заключается ваша проблема. Давайте посмотрим на тип sqrt
:
Prelude> :t sqrt
sqrt :: (Floating a) => a -> a
С другой стороны, x
- это Int
, и если мы запрашиваем у GHCi информацию о Floating
, он говорит нам:
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
Итак, единственными типами, которые Floating
, являются Float
с и Double
с. Нам нужен способ конвертировать Int
в Double
, так же как floor :: (RealFrac a, Integral b) => a -> b
идет в другом направлении. Всякий раз, когда у вас есть такой вопрос типа, вы можете задать Hoogle , поисковую систему Haskell, которая ищет типы. К сожалению, если вы ищете Int -> Double
, вы получите паршивые результаты. Но что, если мы расслабимся, что мы ищем? Если мы ищем Integer -> Double
, мы обнаруживаем, что есть функция fromInteger :: Num a => Integer -> a
, которая почти соответствует вашим ожиданиям. И если мы ослабим наш тип до (Integral a, Num b) => a -> b
, вы обнаружите, что есть функция fromIntegral :: (Integral a, Num b) => a -> b
.
Таким образом, чтобы вычислить квадратный корень из целого числа, используйте floor . sqrt $ fromIntegral x
или
isqrt :: Integral i => i -> i
isqrt = floor . sqrt . fromIntegral
Вы думали о проблеме в правильном направлении для вывода sqrt
; он вернул число с плавающей точкой, но вы хотели целое число. В Haskell, однако, нет понятия подтипов или неявных приведений, поэтому вам также нужно изменить input на sqrt
.
Для решения некоторых других ваших проблем:
intSqrt :: Int -> Int
intSqrt x = floor (sqrt (x + 0.0))
Вы называете это "чепухой", поэтому ясно, что вы не ожидаете, что это сработает, но почему нет? Проблема в том, что (+)
имеет тип Num a => a -> a -> a
- вы можете добавить только две вещи одного типа. Как правило, это хорошо, поскольку это означает, что вы не можете добавить комплексное число к реальной матрице 5 × 5; однако, поскольку 0.0
должен быть экземпляром Fractional
, вы не сможете добавить его к x :: Int
.
Кажется, что (sqrt 500) работает нормально ...
Это работает, потому что тип 500
не тот, который вы ожидаете. Давайте спросим нашего верного спутника GHCi:
Prelude> :t 500
500 :: (Num t) => t
Фактически, все целочисленные литералы имеют этот тип; они могут быть любым видом числа, что работает, потому что класс Num
содержит функцию fromInteger :: Integer -> a
. Поэтому, когда вы написали sqrt 500
, GHC понял, что 500
необходимо для удовлетворения 500 :: (Num t, Floating t) => t
(и он будет неявно выбирать Double
для числовых типов, подобных этому, благодаря правилам по умолчанию ). Аналогично, 0.0
выше имеет тип Fractional t => t
, благодаря функции Fractional
fromRational :: Rational -> a
.
… но (sqrt x) настаивает на том, чтобы x был плавающим…
Смотрите выше, где мы смотрим на тип sqrt
.
… и я не могу найти функцию для преобразования Int в реальное….
Ну, теперь у вас есть один: fromIntegral
. Я не знаю, почему ты не смог его найти; видимо, Google дает гораздо худшие результаты, чем я ожидал, благодаря универсальному типу функции.
Почему это так сложно?
Я надеюсь, что это больше не так, теперь, когда у вас есть fromIntegral
.