Haskell: Проблема преобразования результата разделения в интегральный тип
Вопрос
Я учусь Haskell и застрял пытаясь понять систему типа.
Я пытаюсь написать функцию, которая возвращает длину половины или три или три плюс «для ввода». Вот моя попытка функции, используя рекурсивный подход (функция действительна только для интегральных входов):
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)
Вот ошибка, которую я получаю, когда я пытаюсь загрузить этот файл в 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]
Работает, поэтому я не могу понять это сообщение об ошибке. Где я пойду не так?
Решение
То /
Оператор в Haskell используется для дивизии с плавающей точкой. Если вы действительно хотели использовать дивизион с плавающей точкой и truncate
, Вы бы использовали fromIntegral
на num
Сначала, чтобы преобразовать его в номер плавающей запятой. Ошибка, которую вы получаете, говорят, что вы не можете использовать дробное разделение на интегральном номере (5/2 работает, потому что компилятор подчеркивает тип с плавающей точкой для обоих чисел). Тем не менее, вы можете сделать то, что вы хотите гораздо легче, используя div
функция. Обычно это используется инфикс, окружая имя функции с помощью Backquotes (это работает для любой функции HASKELL):
| even num = hotpoHelper (num `div` 2) (count+1)