rapture
10.06.2011 15:32 unknown
-- функция суммирования элементов целочисленного списка.
sumList :: [Integer] → Integer
sumList [] = 0
sumList (x:s) = x + sumList s
Подозрительно — откуда эта хрень знает, что под x понимается первый элемент списка, а под s — остаток? Почему бы не предположить, что такой хренью нельзя сложить [1,1,1] и [1,1,1] и получить [2,2,2]? Хотя тогда конструктор выглядел бы как [[Integer]] → [Integer], наверное... Эта какая-то полная поебень, похожее на вычисление вывода: ты даешь языку два предиката, а он тебе — вывод. Или один предикат и вывод, а он тебе второй...
Это хаскель, ёба! Он думает за тебя, а потом ты думаешь, что же всё-таки думает по поводу твоего кода первотег.
(x:s) — это конструктор списка, собирающий его из головы и хвоста, по нему проводится паттерн-матчинг. сложить два списка нельзя хотя бы потому, что функция принимает один список. сложение двух списков будет выглядеть как sumLists = zipWith (+)
"Prelude> :type (:)" — вот отсюда
:i [] тогда уж
Да, это первичней :)
> сложить два списка нельзя хотя бы потому, что функция принимает один список
> Хотя тогда конструктор выглядел бы как [[Integer]] → [Integer],
> сложение двух списков будет выглядеть как sumLists = zipWith (+)
Этот ответ не отвечает на вопрос "почему хаскель делает именнно так, а не этак", потому что вынуждает смотреть логику работы zipWith :)
Иными словами — можно ли sumList (x:s) = x + sumList s на процессоре распаралелить как zipWith[x...k][k...s] ?
параллелизация не меняет семантику функции. функция типа (Num a) => [a] → a от разноса по потокам не превратится в функцию типа (Num a) => [a] → [a] → [a]. если вопрос заключается в том, можно ли распараллелить суммирование списка в Haskell, то ответ — да, но автоматически компилятор этого делать не станет (к счастью)
Почему отсутствие автоматического распаралеливания — к счастью?
потому что думать должен программист, а не компилятор. стратегия параллелизации должна выбираться осмысленно
т.е. в таком случае при использовании императивного языка (например, с) программист думает, как будут процессором исполняться его инструкции, а как они будут паралелиться — будет думать компилятор, а при использовании функционального (haskell) он сначала думает, как будет язык представлять функциональное описание в обычных императивных инструкциях, а потом уже как эти инструкции будут исполняться процессором, а потом уже как компилятору сказать так, чтобы он императивное представление паралельного выполнения инструкций воспринял на командах функционального представления? Как-то это... странно, я думал, всегда стремятся вынести на плечи компилятор как можно больше.
не кури это больше. много тебе gcc по потокам пораскидывает без каких-нибудь pthreads?
и ты что, правда не видишь разницы между императивным заданием того, какая инструкция в каком потоке будет выполнена, и декларативным заданием стратегии параллелизации? смотри: http://www.haskell.org/ghc/docs/6.10.2/h... и ещё смотри: http://www.haskell.org/haskellwiki/GHC/D...
Почему сразу потоки? Развороты циклов, if-ов и пр. Хотя, наверное, хаскель тоже это делает, а контроль типов помогает понимать, что именно нужно вернуть и сложить... Хотя интересно будет сравнить поведение, если руки дойдут. http://akoub.narod.ru/funcbook/chapter1/... говорят, что вычисление n'ого ряда фибоначи происходит быстрее, если использовать побочную функцию. Интересно, в данном случае C'шечка оптимизирует во второй вариант или нет.
поставь себе ghc-core и посмотри, что именно делает ghc. к параллелизации это, впрочем, отношения не имеет