2012-01-03 2 views
6

В следующем обобщенном коде:По умолчанию способ выполнения кода в Haskell

nat = [1..xmax] 
xmax = *insert arbitrary Integral value here* 

setA = [2*x | x <- nat] 
setB = [3*x | x <- nat] 

setC = [4*x | x <- nat] 
setD = [5*x | x <- nat] 

setOne = setA `f` setB 
setTwo = setC `f` setD 

setAll = setOne ++ setTwo 

setAllSorted = quicksort setAll 

(обратите внимание, что «е» обозначает функцию типа

f :: Integral a => [a] -> [a] -> [a] 

, что это не просто ++)

Как Haskell обрабатывает попытку печати setAllSorted?

Получает значения для setA и setB, вычисляет setOne, а затем сохраняет значения для setOne только в памяти (до вычисления всего остального)?

Или Haskell хранит все в памяти до тех пор, пока не получит значение для setAllSorted?

Если последнее имеет значение, то как бы я указал (используя main, do функции и все, что другие вещи IO), что он делает вместо этого?

Могу ли я сообщить программе, в которой нужно собирать и собирать мусор? Если да, то как мне это сделать?

+1

Haskell не определяет, как ваш код выполняется вообще, только то, что должен быть результатом; этот вопрос по своей сути специфичен для реализации. – ehird

ответ

9

Глава setAllSorted обязательно должна быть меньше или равна каждому элементу в хвосте. Поэтому, чтобы определить головку, необходимо вычислить все setOne и setTwo. Кроме того, поскольку все наборы являются постоянными аппликативными формами, я считаю, что они не будут собирать мусор после вычисления. Сами цифры, скорее всего, будут разделяться между наборами, но узлы cons, которые склеивают их вместе, скорее всего, не будут (ваша удача с некоторыми будет зависеть от определения f).

+2

Несмотря на то, что они являются CAF, их можно собирать, если компилятор может определить, что они больше не ссылаются после печати. Если программа «main = print setAllSorted», есть хорошая вероятность, что GHC (с оптимизацией) будет мусором собирать части, которые больше не нужны. Однако это только постоянное снижение пиковой памяти. –

+0

означает, что «постоянный фактор» означает, что это даст большее сокращение для больших объемов данных? То есть, означает ли это, что уменьшение пиковой памяти прямо пропорционально количеству вычисляемых данных и, следовательно, сборку мусора? –

7

Из-за лени, Haskell оценивает вещи по требованию. Вы можете думать о печати, сделанной в конце, как «вытягивание» элементов из списка setAllSorted, и это может повлечь за собой другие вещи.

То есть, работает этот код он идет что-то вроде этого:

  1. печать сначала вычисляет первый элемент setAllSorted.
  2. Поскольку это происходит из процедуры сортировки, для этого потребуются все элементы setAll. (Так как наименьший элемент может быть последним).
  3. Для оценки первого элемента из setAll необходимо оценить первый элемент из setOne.
  4. Оценка первого элемента setOne зависит от того, как реализовано f. Это может потребовать оценки всех или всех из setA и setB.
  5. После того, как мы закончим печать, первый элемент setAllSorted, setAll будет полностью оценен. Больше нет ссылок на setOne, setTwo и на более мелкие наборы, поэтому все они теперь имеют право на сбор мусора. Первый элемент setAllSorted также может быть восстановлен.

Таким образом, в теории, этот код будет держать setAll в памяти большую часть времени, в то время как setAllSorted, setOne и setTwo, вероятно, только занимают постоянное количество пространства в любое время.В зависимости от реализации f, то же самое может быть справедливо для небольших наборов.

Смежные вопросы