#haskell
Недавно начал пробовать Haskell на примере маленьких задачек - хеллоуворлдов. Сама
задача состоит в том, что нужно посчитать некоторое выражение при разных x - ничего
сложного. Но для красоты решил округлить ответ до 2 знаков после запятой и тут столкнулся
со сложностями. Так как стандартной реализации такого округления не нашел, завелосипедил
свою:
main :: IO ()
main = do
let x = 1.7
in putStrLn $ show $ roundTo2 ((x + 1) ^ 2 + 3 * (x + 1))
roundTo2 :: Num a => a -> Float
roundTo2 x = truncate (x * 100) / 100
Ругань компилятора:
Could not deduce (RealFrac a) arising from a use of \`truncate'
from the context (Num a)
bound by the type signature for roundTo2 :: Num a => a -> Float
at prog.hs:6:13-31
Possible fix:
add (RealFrac a) to the context of
the type signature for roundTo2 :: Num a => a -> Float
In the first argument of \`(/)', namely \`truncate (x * 100)'
In the expression: truncate (x * 100) / 100
In an equation for `roundTo2':
roundTo2 x = truncate (x * 100) / 100
Понимаю что проблема где-то в типах, но не понимаю, как эту проблему решить
Ответы
Ответ 1
Используйте функцию printf из модуля Text.Printf. import Text.Printf main :: IO () main = do let x = 1.7 printf "%.2f\n" ((x + 1) ^ 2 + 3 * (x + 1))Ответ 2
Во-первых, можно воспользоваться советом из текста об ошибке: добавить класс (RealFrac a) в определение типа функции. (Num a) при этом можно убрать: RealFrac включает в себя Num. Во-вторых, можно воспользоваться ghci и подсмотреть тип функции: GHCi, version 7.10.1: http://www.haskell.org/ghc/ :? for help Prelude> let roundTo2 x = truncate (x * 100) / 100 Prelude> :t roundTo2 roundTo2 :: (Fractional a, Integral a, RealFrac a1) => a1 -> aОтвет 3
Поборол ошибку следующим образом: main :: IO () main = do let x = 1.7 f = (x + 1) ^ 2 + 3 * (x + 1) in print $ roundTo2 f roundTo2 :: (RealFrac a) => a -> a roundTo2 x = fromIntegral f / 100 where f = round (x * 100) Проблема оказалась в функции деления (/) а не truncate, как я предполагал(Кстати в итоговом решении заменил на round как более подходящую). Суть проблемы в том, что деление в Haskell определено для дробных аргументов, принадлежащих классу типов Fractional: :t (/) (/) :: Fractional a => a -> a -> a Но truncate(и round) возвращают значение целочисленного типа Integral: :t round round :: (RealFrac a, Integral b) => a -> b Для решения задачи я воспользовался функцией fromIntegral, которая приводит значение целочисленного типа к значению произвольного числового типа Num, подклассом которого является класс Fractional: :t fromIntegral fromIntegral :: (Num b, Integral a) => a -> b
Комментариев нет:
Отправить комментарий