2016-04-16 2 views
0

Я новичок в Haskell, и мне любопытно, почему это вызывает ошибку.Haskell Inferred Type Error

sumtest :: (Real a) => [a] -> a 
sumtest [] = 0 
sumtest (x:xs) = x + sumtest xs 

avgFunction :: (Integral a, Floating b) => [a] -> b 
avgFunction a = sumtest a/length a 

Ошибка

ERROR file:code/test1.hs:114 - Inferred type is not general enough 
*** Expression : avgFunction 
*** Expected type : (Integral a, Floating b) => [a] -> b 
*** Inferred type : (Integral Int, Floating Int) => [Int] -> Int 

----- Рабочий код ниже Per Accepted Ответ ----

sumtest :: (Num a) => [a] -> a 
sumtest [] = 0 
sumtest (x:xs) = x + sumtest xs 

avgFunction :: (Integral a, Floating b) => [a] -> b 
avgFunction a = fromIntegral (sumtest a)/fromIntegral (length a) 
+0

Сигнатура 'avgFunction' предполагает, что вы конвертируете где-то из' a' в 'b'. Где это должно произойти? На данный момент вы не конвертируете нигде, следовательно, ошибку. BTW, преобразование из общего 'Num' не _possible_. Как вы «конвертируете» комплексное число в реальное? – leftaroundabout

+0

См. Правки. Да, я хотел бы взять целые числа и в итоге получить десятичное среднее значение. –

ответ

3
  • Результат sumtest a имеет тип a. Мы знаем это тип Integral. Следовательно, тип, который может не быть разделенным ...
  • Результат length a имеет тип Int. Это также тип Integral. (И, возможно, a будет другой.)

Так вы пытаетесь разделить два числа, оба из которых имеют типов, которые не могут быть разделены. Ну, это не сработает, не так ли?

К счастью, вы можете конвертировать числа. Некоторые языки фактически делают это неявно (регулярно приводя к всем видам хаоса & dagger;), но не Haskell. Ну, но у него есть функции, чтобы сделать это! hoogle is your friend:

avgFunction a = fromIntegral (sumtest a)/fromIntegral (length a) 


& крестик; По общему признанию, это is иногда просто надоедает, чтобы конвертировать каждые length в Int или Double. И некоторые консервативные неявные преобразования, такие как Python, наверняка не кажутся слишком плохой. Но any вид неявного преобразования не будет работать с системой типа Hindley-Milner, такой как Haskell's.


На другой ноте: эти ограничения фактически излишне сильным. Далее достаточно:

avgFunction :: (Real a, Fractional b) => [a] -> b 
avgFunction a = realToFrac (sumtest a)/realToFrac (length a) 

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

0

(Это действительно комментарий/повышение leftaroundabout's answer, но на самом деле нужно больше форматирование, чем комментарии позволяют.)


Модуль Data.Function обеспечивает функция on, которая позволяет вам указать функцию, применяемую к каждому аргументу другой функции. В этом случае,

avgFunction a = (sumtest a) ./ (length a) 
       where (./) = (/) `on` fromIntegral 

Это на самом деле немного больше, но это, возможно, яснее в том смысле, что локально определенные ./ оператора позволяет фокусировать алгоритм, абстрагируясь от шаблонного кода типа преобразования.


И тогда также это весело маленькая жемчужина с помощью Control.Arrow:

avgFunction = sum &&& length >>> uncurry ((/) `on` fromIntegral) 
+0

Обратите внимание, что это ограничивает подпись функции '[Int] -> b'. – leftaroundabout