Целое число для плавания

Этот код работает:

posToXY :: Float -> Float -> Integer
posToXY a b = do
        let y = a / b
        round y

Но это не работает:

posToXY :: Integer -> Integer -> Integer
posToXY a b = do
        let y = a / b
        round y

Я понимаю, что операция '/' не определена для типа Integer, но я не знаю, как исправить код для работы с параметрами Integer.

Ответы

Ответ 1

Если вы хотите выполнить дробное деление, вы можете конвертировать из любого типа Integral с помощью fromIntegral или fromInteger для преобразования только из Integer.

Существуют похожие функции, относящиеся к другим классам с числовым типом: toRational, fromRational, realToFrac и т.д. И, конечно, вы можете преобразовать дробные типы обратно в интегральные типы с помощью round, floor, ceiling или такой.

И, наконец, вовремя, что вы действительно хотели целое деление, вместо дробного деления с округлением впоследствии функции div и quot (в зависимости от того, какое поведение усечения вы хотите).

Кроме того, вы, вероятно, должны написать свою функцию как нечто вроде posToXY a b = round $ a / b. Необязательные do и несколько строк затрудняют чтение.

Ответ 2

Вы можете использовать fromIntegral для преобразования любого интегрального типа в любой тип Num. Итак:

let y = fromIntegral a / fromIntegral b

Ответ 3

Ваш код может быть легко упрощен до

posToXY :: Float -> Float -> Integer
posToXY a b = round (a / b)

Тогда

posToXY :: Integer -> Integer -> Integer
posToXY a b = round (fromIntegral a / fromIntegral b)

Ответ 4

Если вам требуется целочисленное деление, вы можете использовать div.

posToXY :: Integer -> Integer -> Integer
posToXY = div

Обратите внимание, что это не совсем то же самое, что округление деления с плавающей запятой, потому что div всегда округляется вниз.

Для более общей сигнатуры типа вы можете сделать это вместо

p :: (Real a, Real a1, Integral b) => a -> a1 -> b
posToXY a b = round (realToFrac a / realToFrac b)