Я бавлюся з початківцем Хаскеллом, і я хотів написати середню функцію. Це здавалося найпростішим у світі, чи не так?
Неправильно.
Здається, що система типу Хаскелла забороняє в середньому працювати над загальним числовим типом - я можу змусити його працювати у списку інтегралів або списку фракціонів, але не в обох.
Я хочу:
average :: (Num a, Fractional b) => [a] -> b
average xs = ...
Але я можу отримати лише:
averageInt :: (Integral a, Fractional b) => [a] -> b
averageInt xs = fromIntegral (sum xs) / fromIntegral (length xs)
або
averageFrac :: (Fractional a) => [a] -> a
averageFrac xs = sum xs / fromIntegral (length xs)
а другий, здається, працює. Поки я не спробую передати змінну.
*Main> averageFrac [1,2,3]
2.0
*Main> let x = [1,2,3]
*Main> :t x
x :: [Integer]
*Main> averageFrac x
<interactive>:1:0:
No instance for (Fractional Integer)
arising from a use of `averageFrac ' at <interactive>:1:0-8
Possible fix: add an instance declaration for (Fractional Integer)
In the expression: average x
In the definition of `it': it = averageFrac x
Очевидно, Хаскелл справді вибагливий до своїх типів. Що має сенс. Але не тоді, коли вони обидва могли бути [Num]
Чи мені не вистачає очевидного застосування RealFrac?
Чи є спосіб примусити інтеграли до дробових частин, які не задихаються, коли він отримує дробове введення?
Чи є спосіб використовувати Either
і either
створити якусь середню поліморфну функцію, яка працювала б на будь-якому числовому масиві?
Чи система типу Хаскелла прямо забороняє цю функцію коли-небудь існувати?
Навчання Haskell - це все одно, що вивчити Калькуляцію. Це дійсно складно і базується на теоретичних горах, а іноді проблема настільки складна, що я навіть не знаю, щоб правильно сформулювати питання, тому будь-яке розуміння буде тепло прийняте.
(Крім того, виноска: це базується на проблемі домашнього завдання. Усі згодні з тим, що середній Frac, наведений вище, отримує повні бали, але у мене є підступна підозра, що є спосіб зробити так, щоб він працював як на інтегральних, так і на дробових масивах)