2016-11-14 4 views
0

Я пытаюсь понять, как работает параллелизм в Haskell, и я нашел следующий пример в Control.Parallel docs.Рекурсия и параллелизм в Haskell

import Control.Parallel 

-- Equation for the upper hemisphere of the unit circle 

circle :: Double -> Double 
circle x = sqrt (abs(1 - x^2)) 

-- Calculate the area of a right-handed Riemann rectangle 

area :: Double -> Double -> Double 
area x1 x2 = (x2 - x1) * circle x2 

-- Recursively add the areas of the Riemann rectangles 

parEstimate :: [Double] -> Double 
parEstimate (x:[]) = 0 
parEstimate (x:y:[]) = area x y 
parEstimate (x:y:xs) = 
smaller `par` (larger `pseq` smaller + larger) 
    where smaller = area x y 
     larger = parEstimate (y:xs) 

Но я не мог найти объяснение того, как работает эта рекурсия: parEstimate (х: у: Xs), вызывают все примеры, которые я нашел содержит только два аргумента. Вот почему я не могу узнать, как запустить эту функцию. Вот как я это делаю:

main = print (parEstimate [1.0, 2.0]) 

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

+0

Я бы сказал, что вы слишком задумываетесь об этом. Выполняет ли ваш 'main' проверку типа, запускает и печатает результат, как вы ожидали из примера? Если так, все в порядке. – duplode

+0

«@duplode мой код компилируется отлично, но я не могу понять, правильно ли работает мой вывод. Но главная проблема в том, что мне нужно вычислять определенный интеграл, поэтому без понимания этого кода это кажется трудным. –

+0

Все, что вы делаете, это печать результат, поэтому вывод точно такой же, как в примере кода в документации. Что касается шаблона '(x: y: xs), то единственная разница между этим и' (x: xs) 'заключается в том, что вы также давая имя - 'y' - ко второму элементу списка (в дополнение к первому элементу -' x' - и к хвосту - 'xs'), чтобы вы могли также ссылаться на него в правой части '='. Естественно, это работает только в том случае, если в списке есть как минимум два элемента. – duplode

ответ

3

Рекурсия, по сути, является простой схемой рекурсии fold; если бы это было чисто последовательным, вы можете написать его как

seqEstimate :: [Double] -> Double 
seqEstimate (x:[]) = 0 
seqEstimate (x:y:[]) = area x y 
seqEstimate (x:y:xs) = smaller + larger 
    where smaller = area x y 
      larger = seqEstimate (y:xs) 

(На самом деле, вы, вероятно, просто использовать zipWith вместо:. seqEstimate xs = sum (zipWith area xs (tail xs)))

распараллеливаемый похожа. На этот раз, однако, par используется для обозначения того, что левая часть (smaller) может быть оценена параллельно с правой стороной (pseq larger (smaller + larger)). Независимо от того, хочет ли этот компилятор сделать это, и независимо от того, завершится ли smaller до или после larger, сумма smaller + larger будет правильно рассчитана.

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