[Haskell] Ленивость и строгость
От: jpx http://sourceforge.net/projects/sqlg2
Дата: 09.03.09 17:25
Оценка:
Не флейма ради, а для прояснения некоторых моментов — по мотивам недавнего обсуждения. Кое-что уже было здесь: http://www.rsdn.ru/forum/message/3045739.1.aspx
Автор: Vintik_69
Дата: 03.08.08
, но хочется еще.

Тут приводился исвестный пример вычисления среднего значения в списке, захотелось его допилить:
-- Попытка 1:
mysum :: [Integer] -> Integer
mysum xs = sum' xs 0
 where 
  sum' [] acc = acc
  sum' (x:xs) acc = sum' xs (acc + x)

mean1 :: [Integer] -> Double
mean1 xs = fromIntegral (mysum xs) / fromIntegral (length xs)

-- Попытка 2:
mean2 :: [Integer] -> Double
mean2 xs = fromIntegral s / fromIntegral l
 where
  (s, l) = mean' xs 0 0
  mean' :: [Integer] -> Integer -> Integer -> (Integer, Integer)
  mean' [] accSum accLen = (accSum, accLen) -- ((,) $! accSum) $! accLen
  mean' (x:xs) accSum accLen = mean' xs (accSum + x) (accLen + 1)

-- Пробуем:
n = 10000000
list = [1..n]

--main = putStrLn $ show $ mysum list
--main = putStrLn $ show $ mean1 list
main = putStrLn $ show $ mean2 list


Замечания и вопросы:

  1. Как компилятор (с опцией -O) понимает, что функция mysum — строгая? Я несколько раз встречал упоминания о том, что '+' — строгий, но непонятно, откуда это — в Haskell Report я ничего не нашел. Можно ли всегда на это полагаться или это фича GHC?

  2. Почему mean1 жрет память в объеме O(N), понятно — см. http://cgi.cse.unsw.edu.au/~dons/blog/2008/05/16, хотя если при таком тривиальном изменении программы приходится смотреть на Core Haskell, это неуютно как-то.

  3. Можно ли как-то заставить работать mean2 без использования лишней памяти, не прибегая к хакам вроде $! или seq?

  4. Правильно ли я понимаю, что stack space overflow выдается из-за того, что начинает вычисляться отложенное вычисление (...((0+1)+2)+...+N), а не из-за того, что компилятор не сделал tail-call optimization?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.