это - вопрос:
"Запишите функцию, которая вычисляет средний из списка, т.е. сумму всех элементов в списке, разделенном на его длину. (Вы, возможно, должны использовать функцию fromIntegral для преобразования длины списка от целого числа в число с плавающей точкой.)"
сначала я попробовал это:
mean :: [Double] -> Double
mean [] = 0
mean (x:xs) = (x + mean xs) / (1 + mean xs)
но это дает мне странные результаты, например, когда я использую его как этот:
mean [2,4,6]
это дает мне результат: 1.41176
где это должно быть: 4
почему?
я попробовал другую вещь:
mean :: [Double] -> Double
mean list = (summ list) / (count list)
where count [] = 0
count (x:xs) = 1 + count xs
summ [] = 0
summ (x:xs) = x + summ xs
но у меня есть ошибка, когда я пытался загрузить файл в GHC.
ошибка:
parse error on input 'count'
Failed, modules loaded: none
снова, что я делаю неправильно?
наконец, я попробовал этого (который успешно выполнился):
mean :: [Double] -> Double
count [] = 0
count (x:xs) = 1 + count xs
summ [] = 0
summ (x:xs) = x + summ xs
mean list = summ list / count list
это совпадает с выше одного (с, 'где' ключевое слово), но это успешно выполняется только здесь, а не в выше одного.
почему?
большое спасибо.
p.s.
я узнаю из книги - Реальный мир, который Haskell и осуществление отсюда - (прокрутите его вниз :-))
благодаря Вам всем. это - странная вещь. второй пример также работает на меня также, когда я скопировал его отсюда и протестировал его. я не знаю, почему это вчера не работало на меня :-)
но я все еще не понимаю, почему первый не работает. я думаю, что это должно быть похожим на это
(2 + mean [4,6]) / (1 + mean [4,6])
(4 + mean [6 ]) / (1 + mean [ 6])
(6 + mean [ ]) / (1 + mean [ ])
таким образом, теперь это похоже на это
(6 + 0 ) / (1 + 0 ) -- last recursion
(4 + (6 + 0) ) / (1 + (1 + 0) )
(2 + (4 + (6 + 0))) / (1 + (1 + (1 + 0))
таким образом, теперь это должно быть: 12 / 3
не так ли?
что я не понимаю?
спасибо :-).
Вы получаете неправильные ответы при первой попытке, так как используете неправильную формулу. Мусор внутрь, мусор наружу. (Другие рассмотрели это.)
Вероятно, Вы получаете ошибку при разборе, потому что в некоторых строках используются пробелы, а в других - табуляции. Или вы используете все табуляции, но с нестандартной шириной табуляции.
Здесь не используется и не требуется отступ, поэтому вопрос с пробелами -v- табуляции не возникает.
Ваша первая попытка оценивается так:
6 / 1
4 + 6 / 1 + 6
2 + (10/7) / 1 + (10/7)
, что не то, что вы хотели.
Вторая попытка в порядке.
пусть будет среднее x = сумма (x) / изIntegral(length(x))
среднее [2.0, 4.0, 6.0]
Конечно, это должно быть улучшено (пустой список, работает для удвоений...)
.]Haskell: Самый красивый императивный язык[
] [import Control.Monad.ST
import Data.STRef
import Control.Monad
mean xs = s / l
where (s,l) = runST $ do{
acc <- newSTRef (0,0);
forM_ xs $ \x -> do{
modifySTRef acc $ \(a,b) -> (x+a,1+b)
};
readSTRef acc }
] Правильно:
import Data.List (foldl')
mean :: Fractional a => [a] -> a
mean = uncurry (/) . foldl' (\(s, n) x -> (s + x, n + 1)) (0, 0)
mean [2,4,6] = uncurry (/) $ foldl' (...) (0, 0) [2,4,6]
= uncurry (/) $ foldl' (...) (2, 1) [4,6]
= uncurry (/) $ foldl' (...) (6, 2) [6]
= uncurry (/) $ foldl' (...) (12, 3) []
= uncurry (/) (12, 3)
= 12 / 3
= 4
Неправильно:
mean [] = 0
mean (x:xs) = (x + mean xs) / (1 + mean xs)
mean [6] = mean (6 : [])
= (6 + mean []) / (1 + mean [])
= (6 + 0) / (1 + 0)
= 6
mean [4,6] = mean (4 : [6])
= (4 + mean [6]) / (1 + mean [6])
= (4 + 6) / (1 + 6)
= 10/7
mean [2,4,6] = mean (2 : [4,6])
= (2 + mean [4,6]) + (1 + mean [4,6])
= (2 + 10/7) / (1 + 10/7)
= 24/17
Предупреждение: непроверенный код впереди. В вашем определении означает
, вы должны точно нести и бегущую сумму, и бегущую длину, и, как отмечали другие, вы этого не делаете. Должно сработать что-то вроде следующего:
mean0 sum len [] = sum / len
mean0 sum len (x:xs) = mean0 (sum+x) (len+1) xs
Это определение проходит вдоль двух аккумуляторов , по одному для текущей суммы и длины пробега, которые обновляются по мере того, как вы повторяетесь по списку. Когда у функции, наконец, заканчивается список для обработки (базовый случай), она просто делает необходимый расчет.
Чтобы использовать mean0
, просто пишите
mean0 0 0 [2, 4, 6]
Как видите, это немного раздражает, предоставлять начальные значения для аккумуляторов, так что обычно предоставлять обертку как
mean xs = mean0 0 0 xs
Теперь, вы пишите mean [2, 4, 6]
так, как вы хотели.
скажем, мы определяем
naivemean l = sum l / fromIntegral (length l)
, у него есть пара серьезных ограничений. Во-первых, определение не покрывает списки INT
:
*Main> naivemean ([1] :: [Int])
<interactive>:1:0:
No instance for (Fractional Int)
arising from a use of `naivemean' at <interactive>:1:0-21
Possible fix: add an instance declaration for (Fractional Int)
In the expression: naivemean ([1] :: [Int])
In the definition of `it': it = naivemean ([1] :: [Int])
Второе, он дует стек для больших списков:
*Main> naivemean [1..1000000]
*** Exception: stack overflow
также делает два пропуска, один для SUM
и Один для длины
, по поводу списка, когда будет делать один проход.
Мы можем исправить все три проблемы с
{-# LANGUAGE BangPatterns #-}
mean :: (Real a, Fractional b) => [a] -> b
mean = go (toRational 0) 0
where
go !s !l [] = fromRational s / fromIntegral l
go s l (x:xs) = go (s+.x) (l+1) xs
s +. x = s + toRational x
шаблонами взрыва Сила строгих оценок отмеченных параметров. Без челков, код выше, также взорвет стек при данном длинном списке, но по другой причине: ленивая оценка l
, например, генерирует длинную нерешенную цепочку формы
0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + ...
в этом случае. Ленивая оценка создает больше работы в виде выделения всех приостановленных вычислений, чем было бы просто увеличивать счетчик на каждой итерации.
Как новичок, из Фрации
и , вероятно, тоже запутается
. Рассмотрим тип функции разделения:
*Main> :t (/)
(/) :: (Fractional a) => a -> a -> a
, что означает, что деление определяется для любых двух значений того же типа, который является экземпляром дробных . INT
не является одним из тех типов:
*Main> (1::Int) / (2::Int)
<interactive>:1:0:
No instance for (Fractional Int)
arising from a use of `/' at <interactive>:1:0-18
Possible fix: add an instance declaration for (Fractional Int)
In the expression: (1 :: Int) / (2 :: Int)
In the definition of `it': it = (1 :: Int) / (2 :: Int)
Определение означает
должен покрыть все [INT]
, [FLOAT]
и [Двойной]
[ДВИЖЕНИЕ]
, но без рациональных битов (и без аннотации типа), тип выведенного в означает
*Main> :t mean
mean :: [Double] -> Double
из-за разделения по длине списка Отказ
Оказывается, INT
, ,
,
, и Двойной
представляют собой экземпляры типекласс Real
, и любой реальный
может быть преобразован в Rational
*Main> :t toRational
toRational :: (Real a) => a -> Rational
и Rational
, может быть преобразован в диактива
:
*Main> :t fromRational
fromRational :: (Fractional a) => Rational -> a
Наконец, для больших списков также есть вероятность того, что мы могли бы Переполнение машины двойной, но Rational
дает нам произвольную точность.
Если у вас есть фон на языках, таких как C или Java, который автоматически продвигает типы для обработки этих случаев, вы обнаружите, что эта особая негибкость системы типа Haskell сбивает с толку и разочарованию. Боюсь, тебе просто нужно научиться справляться с этим.
Сделав все это, теперь мы можем
*Main> mean ([1..1000000] :: [Int])
500000.5
или
*Main> mean ([1..1000000] :: [Double])
500000.5