Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как использовать классы типов в функциях Haskell?

Автор вопроса: FrawstcrabsОтветов: 1

В настоящее время я пытаюсь научить себя Haskell с помощью Learn You A Haskell, и поэтому, чтобы проверить себя, я пытаюсь написать функцию, которая принимает список чисел и возвращает среднее значение.

listlen :: [a] -> Int
listlen [] = 0
listlen (x:xs) = 1 + listlen xs

avg :: (Num a) => [a] -> a
avg [] = error "Cannot average list of length 0"
avg l = ((foldr (+) 0 l) `div` (listlen l))

main = putStrLn (show (avg [1,2,3,4,5]))

Однако, когда я запускаю этот код, я получаю это сообщение об ошибке:

test.hs:7:10: error:
    • Couldn't match expected type ‘a’ with actual type ‘Int’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          avg :: forall a. Num a => [Int] -> a
        at test.hs:5:8
    • In the expression: ((foldr (+) 0 l) `div` (listlen l))
          In an equation for ‘avg’:
          avg l = ((foldr (+) 0 l) `div` (listlen l))
    • Relevant bindings include
        avg :: [Int] -> a (bound at test.hs:6:1)

Я возился с подписью, и единственный способ заставить ее работать - преобразовать типы в реальные типы, например. avg :: [Int] -> Int. Буду очень признателен за любые советы.

typeclasshaskelltype-declaration

Ответы

Ответ 1 · рейтинг 2 · Dannyu NDos

Проблема отсюда:

avg l = ((foldr (+) 0 l) `div` (listlen l))

div определяется по Integrals, а не только по Nums. Кроме того, div занижает результат. Нормальное деление - (/), которое определяется Fractionals.

Также (более непосредственно) отсюда:

listlen :: [a] -> Int
listlen [] = 0
listlen (x:xs) = 1 + listlen xs

listlen возвращает Int, что делает div типом Int -> Int -> Int.

Это должно работать:

listlen :: (Num n) => [a] -> n
listlen [] = 0
listlen (x:xs) = 1 + listlen xs

avg :: (Fractional a) => [a] -> a
avg [] = error "Cannot average list of length 0"
avg l = foldr (+) 0 l / listlen l

Или с некоторыми функциями из Prelude:

avg :: (Fractional a) => [a] -> a
avg [] = error "Cannot average list of length 0"
avg l = sum l / fromIntegral (length l)

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы