LINUX.ORG.RU

Glasgow Haskell Compiler 9.4.1

 , ,


3

4

Привет, ЛОР!

7 августа вышла новая версия Glasgow Haskell Compiler 9.4.1. На данный момент GHC является самым активно развиваемым компилятором для Haskell.

Среди изменений:

  • Полностью переписана поддержка ОС Windows. GHC перешёл на использование утилит из LLVM вместо MinGW.
  • Новый синтаксис \cases, аналогичный \case из LambdaCase, и позволяющий проводить сравнение с образцом более чем одного аргумента.
  • Улучшения в инфраструктуре плагинов компилятора: добавлены новый тип defaulting plugins и возможность для плагинов переписывать семейства типов.
  • Новый режим профилирования кода -fprof-late. Этот режим гораздо меньше конфликтует с различными оптимизациями кода, применяемыми компилятором.
  • Новые оптимизации кода и улучшенный анализ производительности кода компилятором.
  • Частично переписан код вывода ошибок сборки. Теперь возможен вывод ошибок и предупреждений в структурированной форме, что позволит улучшить взаимодействие со сторонними программами, такими как IDE и редакторы.
  • Улучшение поддержки проектов, состоящих из множества отдельных пакетов.
  • Возвращена поддержка «глубокого подчинения» (deep subsumption), которая была удалена в GHC 9.0.
  • Значительные улучшения в скорости сборки и потреблении памяти компилятором.

В дополнении к этому, вышла новая версия в ветке 9.2 – GHC 9.2.4, в которой также возвращена поддержка deep subsumption и исправлены многие баги.

Компилятор распространяется по модифицированной лицензии BSD.

>>> Release Notes

★★★★★

Проверено: hobbit ()

Ответ на: комментарий от theNamelessOne

Вот да. Но лулзы начинаются, когда можно выполнить произвольные вычисления на сервере. Я видел доклад на CCC от какой-то девки в костюме — кстати, замечу, что девушка с большой грудью в костюме-тройке может выглядеть просто бесподобно! — которая как раз презентовала эксплоитацию Тьюринг-полных API через создание херни в памяти на сервере. Подробностей не помню, надо искать, но суть в том, что такие штуки сами по себе не то чтобы опасны, но в сочетании например с удаленной дырой позволяют гораздо проще сконструировать шеллкод или байт-код для выполнения.

Если не лень, покопайся на media.ccc.de где-то за 2017 или 2018 годы.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Ну Writer же ну.

  1. (- Что 42? - А что Writer?)

Но вообще, допустим, ты хочешь Writer. Допустим, в случае невалидного ввода ты будешь писать сообщение. А в pure ты что класть-то будешь?

Поясню на примере. Пусть есть вот такой кодец:

data Sex
  = Male
  | Female
  deriving (Eq, Show)

validateSex :: String -> Writer [String] Sex
validateSex = \case
  "male" -> 
    pure Male
  "female" -> 
    pure Female
  _other -> do
    tell ["go away you fag!"]
    pure _

В дырку что пихать?

Laz ★★★★★ ()
Ответ на: комментарий от hateyoufeel

Мне образование позволяет и «Теорию категория для работающего математика» читать, что и делаю. Медленно только получается. Но монады на С++ — интересно, надо посмотреть. Лямды там — типичный синтаксический сахар, интересно как монады получаются. А хотя... Объект с конструктором — не монада ли?

gns ★★★★★ ()
Ответ на: комментарий от AndreyKl

Ну в этом смысле и фортран не забыли. Я тут надысь суточные нормы сухого корма под вес моей собаки фортраном интерполировал, ибо есть хорошая библиотека численных методов. Из Окамла же не получился Elixir и прочие руби на рельсах ( зачеркнуто) OTP.

gns ★★★★★ ()
Последнее исправление: gns (всего исправлений: 1)
Ответ на: комментарий от gns

Объект с конструктором — не монада ли?

ну, если законы выполняются - монада, если не выполняются - не монада. кмк, обычно - далеко не монада, а там не знаю, наверное смотря как рассматривать.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от gns

да, кстати, один физик сообщал мне ещё до 2010 года, когда я был студентом 2го курса кажется, что он только на фортране программирует, если приходится. удивился я тогда ибо думал что кроме с++ жизни нет. упоминал тоже библиотеки численных методов тот физик по моему.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от AndreyKl

Ну вот есть такое слово — NAG Library :) Кстати, С-шная версия у них тоже есть, но фортран параллелит сам и лучше, если что всерьез считать надо. Да и расчетную математику на фортране писать тупо быстрее и многим привычнее.

gns ★★★★★ ()

Почему для написания прикладного софта общего назначения Haskell так непопулярен?

Я вот только pandoc могу вспомнить из того, что многие используют и хвалят.

EXL ★★★★★ ()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от Laz

Завернуть Male | Female в Maybe и возвращать Nothing?

gns ★★★★★ ()
Ответ на: комментарий от gns

про Окамл забыли

Да не, вроде недавно хайповали с reasonml. Как мне кажется, окамл непопулярен ещё из-за несколько упоротого синтаксиса. Не зря все его исправляют. Хотя лично мне было норм писать хеловорлды на окамле, а на сабже я завалился на первом же примере, так как не смог правильно расставить отступы.

bread ()
Ответ на: комментарий от EXL

Сложно писать и написанное выполняется в среднем медленнее, чем императивщина. Функциональные языки вообще не очень популярны для написания софта общего назначения. Ну и еще ведутся ожесточенные споры про «не надо тащить ленивые языки в продакшн», но это небольшая религиозная война внутри клана функциональщиков, туда лезть не надо. Pandoc — хороший пример задачи преобразования текста с одной структурой в текст с другой структурой. Вообще, задачи типа разбора XML, валидации XML об DTD, или написания стайлшитов для какого-то маркапа для преобразования в печатный формат — это хорошая задача для хаскелля и ему подобных языков, но таких задач довольно мало.

gns ★★★★★ ()
Ответ на: комментарий от bread

Ну вот если все занимаются исправлением языка вместо того, что бы его использовать, то что-то не так с языком :)

gns ★★★★★ ()
Ответ на: комментарий от gns

ну уж прямо, как будто пост 10 летней давности читаю. для всего фп подходит, а правило «компилируется - значит работает» хоть и не 100% верное, но очень помогает разработке. Но таки соглашусь - ленивость нужна только тогда когда нужна, а в остальных случаях скорее мешает (т.е. нужна там где бесконечные структуры данных/корекурсия/коиндукция/как оно там правильно называется).

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от gns

Ну вот если все занимаются исправлением языка вместо того, что бы его использовать, то что-то не так с языком :)

Его используют довольно активно, на сколько я знаю. И доделывают активно. Кмк, тут нет противоречия.

AndreyKl ★★★★★ ()
Ответ на: комментарий от AndreyKl

Любой полный по Тьюрингу язык подходит для любой задачи :) Остальное  — вопрос удобства и устройства мозгов разработчика. Синтаксические анализаторы на хаскелле хорошо пишутся (см. Parsec), а графические приложения не особо хорошо. получается громоздко и не очень наглядно.

А ленивость даже не то что бы мешает, просто не всегда понятно, когда и в каком порядке будет выполнено вычисление. Ну можно монаду сконструировать для гарантии последовательного выполнения, но это в каком-то смысле читерство и «влезание в кишки». Все эти хаскелевские comprehensions типа evens = [0,2,..] — это дословно синтаксический сахар для evens = do ... return. Получается громоздко и полученный код трудно сопровождать.

gns ★★★★★ ()
Ответ на: комментарий от AndreyKl

Ну используют, вот, говорят, треды прикрутили совсем недавно. «Теперь заживем!» :)

gns ★★★★★ ()
Ответ на: комментарий от hateyoufeel

Если ты используешь stack, тебе не нужен ghcup. Stack подтягивает ghc автоматом.

ghcup все равно может быть полезен. через него удобно ставить/компилировать под новые версии hls.

ну и ставить/обновлять stack через ghcup тоже можно. т.е. это такая единая точка для установки хаскелевого окружения.

aiive ()
Ответ на: комментарий от aiive

Вообще, это вроде сам stack умеет, но тут я не скажу точно. У меня он, ghc, hls и прочий тулинг никсом ставятся.

hateyoufeel ★★★★★ ()
Ответ на: комментарий от gns

Любой полный по Тьюрингу язык подходит для любой задачи :) Остальное — вопрос удобства и устройства мозгов разработчика.

Да чтоб тебе на Malbolge программировать с таким подходом!

hateyoufeel ★★★★★ ()
Ответ на: комментарий от gns

Любой полный по Тьюрингу язык подходит для любой задачи :)

Хочется упомянуть что слышал в лекциях Москвина (в интернете) мысль, которая так проста что даже обидно стало когда я её услышал (потому что сам недотумкал), так что вот: в промежутке между тьюринг-неполными ЯП (но пакман-полными по меткому выраженю Бреди, который автор Idris) и тьюринг-полными ИНТЕРЕСНЫХ ПРОГРАММ НЕТ. Просто потому что нет разницы для нашей вселенной «повторить бесконечное число раз» или «повторить число раз большее числа этих повторов умещающихся во времени жизни вселенной» или даже «повторить большее число раз чем умещается во времени жизни вычислительной системы». Т.е. по сути нет никакой разницы с т.з. практических возможностей между языками которые ТП и неТП. Живите теперь с этим.

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

Ну, смотря с чем сравнивать. Скажем в ООП много что получается громоздко и ненаглядно да ещё и чётри как запутано из-за наследования. И это не просто трудно, а очень трудно сопровождать, особенно если написано не слишком опытным человеком (среднего опыта явно недостаточно). Но большинство оопшников ничего, делают это. Так что надуманная проблема, по моему.

По моему, настоящая проблема - это порог вхождения. Штука в том что с ООП может работать и опытный и малоопытный человек: он просто городит иерархию классов, которая компилируется и вроде бы работает. Но как только это доходит до использования, вот тут и выясняется опытный был разработчк или опытного таки надо искать.

А с ФП типизированным вроде хаскеля ситуация такая: если ты недостаточно опытен то 1) ты его хрен напишешь 2) оно не скомпилируется. Ну и многие просто убегают обратно в ООП, потому что «там бы уже работало» (хотя это большой вопрос что бы у него там работало).

Вот и получается, что хотя производительность труда вероятно выше на хаскеле (моя гипотеза), но разработчиков тут меньше.

И да, возвращаясь к теме ленивости, ещё раз: она просто не оттуда. Хаскель не был практическим языком, это был экспериментальный язык. И они решили «а пусть всё будет ленивым». И да, это было очень круто, поглядеть как это будет. Ну так вот, теперь мы знаем - ленивость нужна только там где нужна. А в остальных случаях удобнее если вычисления энергичные. По этой причине я думаю ленивость хаскеля нужно рассматривать как недостаток.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 8)
Ответ на: комментарий от hateyoufeel

Ну не вижу противоречий. на Malbolge программировать можно, но неудобно. Равно как на Брейнфаке и прочем Вайтспейсе.

gns ★★★★★ ()
Последнее исправление: gns (всего исправлений: 1)
Ответ на: комментарий от AndreyKl

но пакман-полными

А простите мою серость, а что такое пакман-полные языки? И вообще чота я не осилил эти многабукаф. Чот ты очень умное сказал.

Скажем в ООП много что получается громоздко и ненаглядно да ещё и чётри как запутано из-за наследования.

Дык если знаешь условный Qt (juce, wxwindows, MFC, etc...), то перекрыть нужные методы не представляет труда. Довольно наглядно получается.

> от и получается, что хотя производительность труда вероятно выше на хаскеле (моя гипотеза),

Сформулировать мысль на Хаскелле получается короче, но формулировку будешь искать дольше. Час думать — пять минут писать. В целом, производительность может и ниже, но код короче. Ну порог вхождения — это да., есть такая проблема.

gns ★★★★★ ()
Ответ на: комментарий от Laz

Не очень понимаю, как тебе в таком варианте Applicative поможет. Но всё же. Вот тебе примерный кусок:

type Errors = [String]

whenNothing :: Monad m => Maybe a -> m b -> m b
whenNothing Nothing f = f
whenNothing _ _ = return ()

validateInput :: InputData -> Either Errors OutputData
validateInput InputData{..} =
  case runWriter f of
    (Just v, []) -> Right v
    (_, errs) -> Left errs
  where
    f = do
      let v1 = readMaybe input1
      whenNothing v1 $
        tell "Failed to parse input1"
      let v2 = readMaybe input2
      whenNothing v2 $
        tell "Failed to parse input2"
      ...
      return (OutputData <$> v1 <*> v2 ...)

Я такое довольно часто вижу, только вместо Maybe там другой комбинатор с конкретными ошибками и т.д.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от gns

А простите мою серость, а что такое пакман-полные языки?

Те которые поддерживают рекурсию равноценную примитивной рекурсии из теории общерекурсивных функций. Т.е. те на которых можно написать игру вроде «pacman».

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

И вообще чота я не осилил эти многабукаф. Чот ты очень умное сказал.

Искренне жаль (можно попробовать перечитать, предложения большие, но вряд ли займёт больше трёх минут у тебя, кмк).

Сформулировать мысль на Хаскелле получается короче, но формулировку будешь искать дольше. Час думать — пять минут писать.
В целом, производительность может и ниже, но код короче.

Может быть и так. Хотя я склоняюсь к тому что это решается опытом. Потом быстрее начинаешь писать это всё.

Ну порог вхождения — это да., есть такая проблема.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 4)
Ответ на: комментарий от gns

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

Да, кстати, нет. Декларативно описать интерфейс на каком-нибудь [e]DSL и накидать коллбэков – это не то чтобы проблема. Графических приложений на хацкелле нет ровно потому же, почему их нет на большинстве других языков: потому что гуёвых библиотек примерно три с половиной и все на C/C++. Просто никто не парится и все пишут вебговно на JS+Electron.

Хотя я делал гуй на Haskell+QML и выходило довольно неплохо.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от gns

Все эти хаскелевские comprehensions типа evens = [0,2,..] — это дословно синтаксический сахар для evens = do … return. Получается громоздко и полученный код трудно сопровождать.

Эээ… не. Ты путаешь что-то. [0, 2, ..] – это сахар для enumFromThen. Comprehensions тут вообще не при делах.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 2)
Ответ на: комментарий от AndreyKl

Те которые поддерживают рекурсию равноценную примитивной рекурсии из теории общерекурсивных функций. Т.е. те на которых можно написать игру вроде «pacman».

Так я как раз и пошел листать индекс в книжке Роджерса и чота заморочился. Думал, что я чего-то пропустил в жизни. Ну тогда понятно, что если у тебя есть только примитивно-рекурсивные функции, то ничего сложнее индукции не напишешь. Перехода по условию у тебя нет. Чота я подумал, что Пакман тут фамилия. Черча знаю, Тьюринга тоже, А кто такой Пакман даже не догадываюсь. :)

gns ★★★★★ ()
Ответ на: комментарий от gns

Ну тогда понятно, что если у тебя есть только примитивно-рекурсивные функции, то ничего сложнее индукции не напишешь.

да, ну так вот, я и говорю - всё напишешь. (да, условная конструкция есть у нас, только переходов по типу goto/while нету).

Черча знаю, Тьюринга тоже, А кто такой Пакман даже не догадываюсь. :)

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

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 3)
Ответ на: комментарий от gns

Ну есть же биндинги в gtk, например. И чота-какта…

Есть, а толку? GTK – чисто линуксовый тулкит, в последнее время часто прибитый к гному гвоздями. Под макос или венду софт на нём запаришься собирать.

hateyoufeel ★★★★★ ()
Ответ на: комментарий от hateyoufeel

Ну вот кто тут путает так только SPJ его разберет. Я вот не уверен, что для всех этих актульно-бесконечных списков GHC сразу генерит вычислительную процедуру. Есть у меня подозрение, что у них сначала там какой-то промежуточный код образуется с do-синтаксисом, из которого потом генерится вычислительная процедура с меткой. Есть хорошая статья про то, как SPJ и компания дошли до жизни такой — https://www.microsoft.com/en-us/research/wp-content/uploads/1992/04/spineless...

gns ★★★★★ ()
Ответ на: комментарий от gns

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

Так и есть. Только без do-синтаксиса. Промежуточный код называется Core, и это такой Haskell, только в нём проставлены все типы, а из синтаксиса только let..in и case..of.

Есть хорошая статья про то, как SPJ и компания дошли до жизни такой — https://www.microsoft.com/en-us/research/wp-content/uploads/1992/04/spineless

Это статья не о том совершенно. STG – это промежуточное представление кода во время компиляции сейчас.

Вот тебе примерная схема:

                                                                           +---------+
                                                         LLVM backend /--->| LLVM IR |--\
                                                                      |    +---------+  | LLVM
                                                                      |                 v
 +------------+ Desugar  +------+ STGify  +-----+ CodeGen  +-----+    |  NCG    +----------+
 | Parse tree |--------->| Core |-------->| STG |--------->| C-- |----+-------->| Assembly |
 +------------+          +------+         +-----+          +-----+    |         +----------+
                                                                      |            ^
                                                                      |     +---+  | GCC
                                                            C backend \---->| C |--/
                                                                            +---+

Взято отсюда: https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/compiler/generated-code

Как видишь, промежуточных представлений внутри GHC вообще три: Core, STG и C–. Хотя Cmm – это такой LLVM IR, только с сишным синтаксисом. Я прозреваю, что если бы LLVM был раньше (или GHC появился бы позже), то с Cmm никто бы не запаривался, и STG компилировали бы прямо в LLVM IR.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от gns

Ну вот как бы да. Из адекватных тулкитов для GUI остался только Qt. А т.к. биндинги к самому Qt делать для других языков из-за C++ – лютый геморрой, то выходит только QML.

hateyoufeel ★★★★★ ()
Ответ на: комментарий от hateyoufeel

Ну есть еще Juce, но это нишевая штука и вообще про музыку и midi. На нем всякие программные синтезаторы и прочий музыкальный софт народ ваяяет. Куда там биндинги торчат я даже не знаю. Миди. Dsp и прочий реалтайм — это не про хаскель.

gns ★★★★★ ()
Ответ на: комментарий от gns

Миди. Dsp и прочий реалтайм — это не про хаскель.

Кстати, нет. Soft real-time на хацкелле вполне можно делать. Плюс, есть куча штук, которые используют хацкелл для создания и расширения eDSL, который потом компилится во что-то низкоуровневое.

Вот тебе компилятор из хацкелла в Verilog и VHDL: https://clash-lang.org/

Но да, такой подход сложнее, чем писать на какой-нибудь сишечке, но и профита можно больше срубить. Лисперы кстати тоже таким промышляют.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 2)
Ответ на: комментарий от hateyoufeel

Ну да, я что-то такое и ожидал. У тебя там с типами бардак, но общая суть ясна - Validator a b = Writer a (Maybe b). И композить это всё руками потом. Жуть..

Но изначально речь шла о том, чего такого могут аппликативы, чего не могут монады. Я тут подготовил кусочек кода.

{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}

data Validate a b
  = Invalid a
  | Valid b
  deriving (Eq, Show, Functor)

instance Monoid a => Applicative (Validate a) where
  pure = Valid
  Invalid l <*> Invalid r = Invalid (l <> r)
  Invalid l <*> Valid _ = Invalid l
  Valid _ <*> Invalid r = Invalid r
  Valid f <*> Valid a = Valid (f a)
  
runValidate :: Validate a b -> Either a b
runValidate = \case
  Invalid a -> Left a
  Valid a -> Right a


data Sex
  = Male
  | Female
  deriving (Eq, Show)

data Form
  = MkForm
    { formSex :: String
    , formWants :: String
    }
  deriving (Eq, Show)

data User
  = MkUser
    { userSex :: Sex
    , userWants :: Sex
    }
  deriving (Eq, Show)


validateSex :: String -> Validate [String] Sex
validateSex = \case
  "male" -> 
    pure Male
  "female" -> 
    pure Female
  other -> 
    Invalid ["invalid value: " <> other]

validateUserForm :: Form -> Validate [String] User
validateUserForm MkForm{..} = do
  userSex <- validateSex formSex
  userWants <- validateSex formWants
  pure MkUser{..}


goodForm :: Form
goodForm = MkForm "male" "female"

badForm :: Form
badForm = MkForm "nbaaaq++" "monkey"

main :: IO ()
main = do
  print (runValidate $ validateUserForm goodForm)
  print (runValidate $ validateUserForm badForm)

http://tpcg.io/_J7BS7I

Идея такая, что Validate валидирует вообще все поля и собирает все возможные ошибки. Если написать для Validate корректный инстанс монады, то валидатор будет завершаться после первой же ошибки.

Laz ★★★★★ ()
Ответ на: комментарий от Laz

У тебя там с типами бардак

Я с телефона писал :3

Я тут подготовил кусочек кода.

Ну да, я так и думал, что ты ApplicativeDo возьмёшь. Тут как бы без вариантов.

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

Если написать для Validate корректный инстанс монады, то валидатор будет завершаться после первой же ошибки.

Не, не будет. Там всё ещё Applicative пойдёт, если у компилятора нет причин вставить Monad. Сам проверь:

instance Semigroup a => Monad (Validate a) where
  Valid v >>= f = f v
  Invalid e >>= _ = Invalid e
$ ./ado
Right (MkUser {userSex = Male, userWants = Female})
Left ["invalid value: nbaaaq++","invalid value: monkey"]
hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 4)
Ответ на: комментарий от Laz

Или вот, скажем, запустить несколько параллельных вычислений в монаде не выйдет, а в аппликативе - пожалуйста.

Че, правда что ли?

Любую ассоциативность можно заюзать под параллельные вычисления [update: можно не в смысле «всегда можно», а в смысле «иногда можно»].

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

a-- ()
Последнее исправление: a-- (всего исправлений: 3)
Ответ на: комментарий от hateyoufeel

А т.к. биндинги к самому Qt делать для других языков из-за C++ – лютый геморрой, то выходит только QML.

Ой, беда-беда... а подожди, а как же pyqt?

a-- ()
Ответ на: комментарий от hateyoufeel

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

Я об этом и написал в самом начале - монада моделирует вычисления, где последующие шаги зависят от предыдущих. У аппликатива зависимости нет, поэтому вычислено будет всё, да ещё и в неопределённом порядке.

Не, не будет. Там всё ещё Applicative пойдёт, если у компилятора нет причин вставить Monad.

Ключевое слово - корректный. В твоём случае <*> не равно ap. То, что компилятор такие вещи не видит, наверное, не очень хорошо. С другой стороны, эта особенность используется в haxl (хотя, это Марлоу, ему можно).

Laz ★★★★★ ()
Ответ на: комментарий от a--

Ага, >>=>=>) ассоциативно, а ассоциативность даёт параллелизм. Но прикол в том, что аргументы у них - функции вида a -> m b, у которых всё самое интересное спрятано за стрелкой. Чтобы «запустить» вычисление, в функцию нужно передать аргумент, который можно получить только выполнив предыдущее вычисление. Отсюда и получается, что все вычисления (и их эффекты) следуют строго друг за другом.

Laz ★★★★★ ()
Ответ на: комментарий от Laz

Ключевое слово - корректный. В твоём случае <*> не равно ap. То, что компилятор такие вещи не видит, наверное, не очень хорошо. С другой стороны, эта особенность используется в haxl (хотя, это Марлоу, ему можно).

Оба этих инстанса корректны сами по себе. То, что они не стыкуются для Invalid, это конечно проблема, но не сильно страшная. Про Haxl я в курсе.

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

Зависит от монады. Если это не IO и подобное, то ты можешь параллелить вычисления слева и справа от >>, если они действительно независимы. GHC даже вроде умеет разбивать вычисления на независимые цепочки.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 2)
Ответ на: комментарий от Laz

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

Это, похоже, чисто хаскелевская придумка, которая не имеет ничего общего с реальным положением дел.

Давай рассмотрим максимально простой случай, где монада = id:

b=f₁(f₂(f₃(f₄(a))))
Эта хрень параллелится на
g = λd: f₁(f₂(d))
c = f₃(f₄(a))
b = g(c)
Вообще говоря мы не умеем компактно считать g. Но в некоторых случаях вполне можем. Если например каждое fᵢ = λx: x~qᵢ где ~ опять-таки ассоциативная операция, то g = λd: (d~q₂)~q₁ ≡ λd: d~(q₂~q₁) вполне себе вычисляется.

В общем случае будет интересней, но возможности параллелизации опять могут быть. Можно рассмотреть монаду MayBe, натуральные числа qᵢ и операцию x~y которая (после лифтинга) дает Just(x+y), но при x+y>1000 дает Nothing. Вроде монада, я ничего не упустил?

Чуть подробнее:

T = множество натуральных чисел
M T = { Nothing, Just(1), ... , Just(1000) }
fᵢ = λx: x+qᵢ где qᵢ натуральные

unit(x) = Just(x) если x≤1000 иначе Nothing
bind(Just(x),fᵢ) = Just(x+qᵢ) если x+qᵢ≤1000 иначе Nothing
bind(Nothing,fᵢ) = Nothing

Там опять же можно параллелизовать так как написано выше.

a-- ()
Последнее исправление: a-- (всего исправлений: 4)
Ответ на: комментарий от a--

Недоподнял немножко, на самом деле так:

fᵢ = λx: Just(x+qᵢ) если x+qᵢ≤1000 иначе Nothing, qᵢ натуральные

Еще пусть для удобства обозначений

Fᵢ = λx: Just(x+i ) если x+i ≤1000 иначе Nothing, i  натуральные

Ну и параллелим очевидным образом:

b = F₁(F₂₂(F₃(F₄₄(999))))  <--- тут конечно че-то вставить надо, но мысль ясна
g = F₂₃  
c = Nothing
b = Nothing

a-- ()
Последнее исправление: a-- (всего исправлений: 2)
Ответ на: комментарий от a--

Вот вроде без нарушения типизации, с нетривиальной монадой — и можно очевидно параллелить:

Just(x).bind(fᵣ)          = Just(x+r)     if x+r    ≤1000 else Nothing
Just(x).bind(fᵣ).bind(fₛ) = Just(x+r+s)   if x+r+s  ≤1000 else Nothing
Just(x).bind(fᵣ). ...     = Just(x+r+...) if x+r+...≤1000 else Nothing

Nothing.bind(fᵣ)          = Nothing
Nothing.bind(fᵣ).bind(fₛ) = Nothing
Nothing.bind(fᵣ). ...     = Nothing

a-- ()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.