Хаскелл - Сборка мусора не исправляет достаточное пространство

Я делаю программу, чтобы суммировать все нечетные числа до n:

oddSum' n result | n==0 = result
                 | otherwise = oddSum' (n-1) ((mod n 2)*(n)+result)

oddSum n = oddSum' n 0

Я получаю два erros для для моих исходных данных (я поместил их ниже), я использую хвостовую рекурсию итак, почему переполнение стека происходит? (отметьте: я использую Объятия на Ubuntu),

oddSum 20000 ОШИБКА - переполнение стека Контроля

oddSum 100000 ОШИБКА - Сборка мусора не исправляет достаточное пространство

6
Попытайтесь собрать его с ghc-O , его строгость, анализатор мог бы обнаружить тот oddSum' строго во втором аргументе, и вставьте необходимое seq ' s самостоятельно.
добавлено автор Joachim Breitner, источник

2 ответы

Во-первых, не используйте Объятия, это не поддерживается. С оптимизацией возможностей GHC что-то вроде этого, был бы собран к трудной эффективной петле (все еще, ваш код не будет прекрасен).

Нестрогие сумматоры всегда представляют угрозу создания огромного thunks. Одно решение состояло бы в том, чтобы сделать его строгим:

{-# LANGUAGE BangPatterns   #-}

oddSum' n !acc | n==0       = acc
               | otherwise  = oddSum' (n-1) $ (n`mod`2)*n + acc

Конечно, это едва идиоматично; явно написание рекурсивных функций хвоста тяжело и несколько осужденное в Хаскелле. Большинство вещей этого вида может приятно быть сделано с библиотечными функциями, как

oddSum n = sum [1, 3 .. n]

... который, к сожалению, не работает достоверно в постоянном космосе, также. Это действительно работает со строгой версией сгиба (какой сумма является просто специализацией),

import Data.List
oddSum n = foldl' (+) 0 [1, 3 .. n]
8
добавлено
Объятия isn' t поддержанный, но Объятия работы . It' s не детская коляска и it' s быстро, чтобы собрать (это даже замечает, когда я отредактировал свой файл, таким образом, я don' t должен : r ). It' s ограниченный Хаскеллом 98 и doesn' t поддерживают расширения GHC, но it' s большой для изучения на, частично потому что сообщения об ошибках намного более четкие, особенно это дает ошибку типа, где ghc говорит, что вы, чтобы пойти пишете декларацию случая.
добавлено автор AndrewC, источник
Используя Объятия с ограниченным стеком/кучей обнаружил важное недоразумение, которое OP имел об оценке в Хаскелле, где ghc-O2 , возможно, скрыл его. Нам нравится узнавать, что мы сделали что-то не так как можно скорее, don' t мы? ghc-O2 во время кодирования медленнее, чем : r (в ghci или объятиях), менее интерактивная, и преждевременная оптимизация.
добавлено автор AndrewC, источник
BTW, я думаю, используя $! более хорошо, чем скороговорки удара. oddSum' n acc | n == 0 = acc тогда | иначе = oddSum' (n-1) $! (ультрасовременный n 2) *n + acc
добавлено автор AndrewC, источник
Я думал о выполнении его со списками, но выбрал свое собственное внедрение как способ учиться и не быть также иждивенцем уже осуществленных функций. I' m в моем university' s компьютерная лаборатория, у этого только есть Объятия и stundets can' t устанавливают что-либо (i' m использующий ghc дома).
добавлено автор user1493813, источник
 oddSum 3
 oddSum 2 ((2 mod 2)*2 + 3)
 oddSum 1 ((1 mod 2)*1 + ((2 mod 2)*2 + 3))

Вы строите огромный thunk в результат переменная. Как только вы оцениваете это, все вычисления должны быть сделаны сразу, и затем переполнения стека, потому что, чтобы выполнить дополнение, например, сначала необходимо оценить операнды и операнды дополнений в операндах.

Если, otoh, thunk становится слишком большим, вы получаете переполнение кучи.

Попытайтесь использовать

result `seq` ((mod n 2) * n + result)

в рекурсии.

8
добавлено
нет, это won' t, пока компилятор не видит, что стоимость на самом деле необходима в функции. Например, если вы заменяете иначе с результат> = 0 тогда, это вызовет код, произведенный, чтобы оценить результат в каждой рекурсии. (Но я не советую делать так, это - уловка, которая ослабляет удобочитаемость и также can' t быть примененным везде.)
добавлено автор Ingo, источник
Спасибо! я думал, что, помещая круглые скобки в ультрасовременный n 2, делая его (ультрасовременный n 2) буду вынуждать его быть оцененным.
добавлено автор user1493813, источник
Я вижу, спасибо очень много!
добавлено автор user1493813, источник
Haskell
Haskell
910 участник(ов)

https://combot.org/chat/-1001043143583 Ссылки на полезные ресурсы: https://ruhaskell.org/links.html ;