LINUX.ORG.RU

нубвопросы по потокам и io

 , , ,


0

1

Я наконец-то дочитал пару ламмерский введений по хаскелю. И тут же решил посмотреть что там с гринлетами и прочими модными плюшками. В итоге, я так понял, популярны два подхода:

1) CHP http://www.cs.kent.ac.uk/projects/ofa/chp/tutorial.pdf (жалкие 22 страницы туториала)

2) Concurrent Haskell http://research.microsoft.com/en-us/um/people/simonpj/papers/marktoberdorf/ma... (всего лишь 46 страниц туториал)

Вторую доку я дочитал до конца (хотя понимание происходящего потерял гораздо раньше).

Так вот то что в C делается for (int v=0, i=1; i<=n; i++) { v = v+i ; }; return v на хаскеле выглядело вот так (это из второй доки):

count :: Int -> IO Int
count n = do { r <- newIORef 0;
               loop r 1 }
        where
            loop :: IORef Int -> Int -> IO Int
            loop r i | i>n        = readIORef r
                     | otherwise  = do { v <- readIORef r;
                                         writeIORef r (v+i);
                                         loop r (i+1) }

В первой доке код чуток менее кривой, но... В общем, все эти монады для (сетевого) io мне показались страшными костылями. Это я чего-то не понимаю или в хаскеле concurrency в зачаточном состоянии?

Второй вопрос что меня мучает это большие структуры данных. Вот мне, допустим, надо в большом дереве пару узлов поменять. Такое реально сделать в хаскеле без особых костылей? Или он просто не расчитан на такое?

Спрашиваю потому что хочу понять для себя добивать ли хаскель или уже одним глазом в сторону эрланга начинать смотреть.

★★★★★

Последнее исправление: CYB3R (всего исправлений: 1)

Чето не совсем понимаю твои вопросы: какая связь между concurrency и приведенным кодом? В хаскеле треды дешевые и есть STM, — не назвал бы это зачаточным состоянием. Монады неизбежны, потому что тебе куда-то надо возвращать результаты вычислений, а чистый код этого не умеет. Если правильно помню, все эти деревья и прочее в хаскеле persistent, так что пару узлов поменять выходит достаточно дешево. Продолжать или нет это up to you. Что ты хочешь написать?

nokachi
()

Давненько уже смотрел набегами оба языка и для себя сделал вывод, что все касается потоков, распределенности в эрланге все очень просто и удобно, особенно за счет OTP (и в рятли в ближайшем будущем будет, что то аналогичного уровня).

Чтобы понять как будет выглядить io в эрланге достаточно глянуть https://docs.google.com/document/pub?id=1_DWEh4cuEgBAFo3oKyAhNEPtXILR16WWOEQn...

- не «for (int v=0, i=1; i<=n; i++) { v = v+i ; }; return v » конечно но без монад (хотя гдето есть либа реализующая монады на эрланге )

Но у эрланга один главный недостаток в том, что это он не универсален - например какуйнибудь обработку теста в кодировках отличных от latin, utf будет несподручно там делать.

strobe
()

Вот мне, допустим, надо в большом дереве пару узлов поменять. Такое реально сделать в хаскеле без особых костылей?

Вроде конкретно с этим проблем особых нет, правда если не держать дерево где-то еще. Разумеется с произвольным доступом могут быть заморочки: для того же pure-кода потребуются что-нибудь вроде зипперов.

линк немного в тему http://stackoverflow.com/questions/4597262/complex-data-structures-in-haskell...

anonymous
()

Хаскелист из меня такой же как и ты. Еще даже не все туториалы дочитал. Лезу со своими ответами для того, чтобы самому разобраться, стоит ли это свеч.

Процитированный пример суммирования [1..n] предназначен для иллюстрации последовательного выполнения операций. Сравнивать его с реализацией на Си не имеет смысла потому, что эта задача решается в функциональном стиле в две простых и понятных строчки. А пример на Си приведен для понимания человеком, привыкшем к императивному стилю.

Пару узлов в дереве не меняют. Делают новое дерево. Красивые картинки с оценкой производительности заявляют, что Хаскель очень даже молодец. Производительность - это главная причина, по которой я обратил внимание на Хаскель. Производительность программиста, конечно же. На другой стороне весов - производительность программы. А по середине ты со своей уникальной задачей - выбираешь.

fopen ★★
()

вообще ничего не понял.

а). В haskell есть green threads, есть 2 их реализации -threaded и без, -threaded пока работает далеко не идеально, но работает. Возможно создавать также нативные треды и треды привязанные к конкретному процу, runtime умеет eventfd, и проч бонусы

б). цикл на haskell выглядит так

forM_ [a..b] $ action

причем для foldable и traversable структур можно и индекс не вводить

в). ты не привёл в своём посте монады, тем более сетевые, я не понимаю на основе, чего ты делаешь вывод. Если что в haskell есть enumetee, conduit, pipe, которые очень хорошо подходят для потокового IO (но я думаю пока их трогать рано)

г). связь IO и concurrency я не уловил... при работе на всех сокеты

д). взять и поменять, зависит от типа структуры, можно, напрямую, можно линзами воспользоваться, можно использовать IORef и мутабельную структуру, можно STM и иметь мутабельную транзакционную структуру с объединяемыми (composable) операциями.

е). менять haskell на erlang смысла нет, только если тебе работу на erlang не предлагают :)

qnikst ★★★★★
()

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

1. Haskell - язык чистый. Потому все побочные эффекты должны быть явно прописаны в сигнатуре любой функции. В простейшем случае просто добавляем IO, но здесь могут быть и другие монады, да и, вообще, не только монады. В монаде же IO действительно можно работать со ссылками IORef.

Иногда такое явное разделение хорошо, а иногда - не очень. Хорошо, потому что побочные эффекты явно приходят через liftIO, и их можно как-то обработать локально, например, повесить обработку ошибок на liftIO в своей монаде. Плохо, потому что приходится тащить IO или его аналог в императивные части кода.

2. Хотя можно создать в IO аналоги практически всех структур данных, существующих в других языках, хаскелисты не любят этот подход. Предпочитают по возможности использовать персистентные структуры данных, когда данные используются повторно и, как правило, без IO на основе только чистого кода.

Канонический пример: вставка новой ассоциации в дерево. Мы просто перестраиваем ствол дерева, а это всего-то несколько пар для сбалансированного дерева из тысяч элементов (количество таких пар меняется по логарифму от числа элементов). Выполняется достаточно эффективно.

Другой пример из «обычного» программирования: метод String.substring() из Java тоже не копирует всю строку, а просто использует ее повторно, но с другими индексами. Короче, идея такая же лежит во многих структурах данных в Haskell. И что важно, получается, что здесь мы обходимся без побочных эффектов.

Когда это не работает, то можно прибегнуть уже к IO. Иногда даже делают двойников: чистую иммутабельную структуру и похожую мутабельную, но уже через IO. Например, так сделаны массивы.

Что касается много-поточности, то в Haskell используются легковесные «зеленые» потоки в двух режимах (компиляция со -threaded и без), но тут тебе уже написали.

dave ★★★★★
()

Код вообще не в тему, абсолютно.

Попробуй для начала прочитать про par и стратегии.

Miguel ★★★★★
()

понял, я лох. всем спасибо.

Пойду дальше грызть штангу...

true_admin ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.