LINUX.ORG.RU

Вышла Scala 2.10

 


1

3

Объявлено о выходе новой версии языка программирования Scala 2.10.

Основные нововведения:

  • классы-значения (value classes) — новый механизм, позволяющий уменьшить расходы на выделение памяти;
  • неявные модификаторы (implicit classes) теперь относятся к определению классов и призваны упростить расширения для других типов;
  • интерполяция строк (string interpolation) — новый механизм создания строк;
  • Futures и Promises призваны упростить создание многопоточного кода;
  • библиотека Akka Actors теперь является частью языка;
  • наконец-то в состав языка добавлена поддержка макросов.

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

>>> Подробности

★★★★★

Проверено: maxcom ()
Последнее исправление: mono (всего исправлений: 2)

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

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

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

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

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

ФП можно так понимать -

Можно, конечно, и это главная проблема теорката, на которую еще Маклейн обращал внимание. Мы что угодно можем понимать как объекты, стрелки, и т.п. - вопрос состоит в том, насколько это содержательно? Какую конкретно пользу приносит тот факт, что мы понимаем типы как объекты, каррированные функции как стрелки и так далее? Что это нам дает? Какие-то практические результаты? или позволяет делать более простым способом какие-то выводы, которые другими способами получить сложно? Если мы не можем сразу ответить на эти вопросы утвердительно и подтвердить свою точку зрения примерами (а для теорката в CS - не можем), то, следуя Маклейну, мы не должны применять теоркат в данной конкретной области знаний. Потому что мы можем точно так же заменить «объекты» «сепульками» а стрелки «сепулькариями» - и ничего не изменится, выходит. То есь применния теорката в данном случае - это просто замена имен формальным аргументов в ф-и, что, учитывая альфа-эквивалентность, не имеет никакого смысла.

anonymous
()
Ответ на: комментарий от quasimoto
(foreach [x seq]
  (some-macro тут "x" нет)
  ;; раскрывается в код с "x"
  )

Ты понял, что написал?

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

Пойми, макросы не просто «вводят магические символы...», а вводят новую конструкцию со своей логикой. Самое интересное, что тебе не надо знать про «магические» действия самого макроса. Посмотри на разворачивание кода со множеством вложенных вызовов макросов - тебе будет гарантирован бутгурд. Если посмотреть на геренируемый код с точки зрения ассемблера, то будгурд будет больше. В том то и дело, что абстракции позволяют просто решать сложные задачи, не вникая, во время решения этой задачи в нижележащий (читай, после разворачивания) код. Это основы понимания программирования. Это основы, которые не даны джавабыдлокодерам, которые даже не понимают, что ОО не решает проблем сокрытия логики и не помогает писать высокоуровневый код. Вникать в детали реализации нужно только при создании макроса, dsl-а или, например, нового языка.

Например, в С++ есть this : ClassType*, но нет Self == ClassType как в Scala...

Ты застрял на одном месте. Раз не понимаешь, то просто зазубри: МЕХАНИЗМ МАКРОСОВ ОРТОГОНАЛЕН НЕГЕНЕРЯЩЕМУ КОД ВОЗМОЖНОСТЯМ ЯЗЫКА.

Или (опять сишные) макросы для дебага - они могут делать goto error, throw InitializationFailed, или вовсе вызывать деструктор класса (и тогда, опять, должны как-то узнать как называется класс - нужен Self / Super).

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

Пример с Self это явно третий случай, с простыми debug макросами - первый. Разные анафорические макросы - второй. Всё это примеры негигиенических макросов.

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

(foreach [x seq] (print x))

Как просто, правда?

forM_ seq $ \x -> print x == forM_ seq print == mapM_ print seq == thisMapper seq where thisMapper = mapM_ print
seq foreach { x => print(x) } == seq foreach print

OMG! Что это? Аналог вышеприведенного кода на лиспе для foreach?

Ага, ерунда, а сделать на фвп ниасилил.

Тебе уже говорили, что map тут достаточно, с сахаром для блоков - ещё лучше.

map он для другого. map возвращает лист - это его идиоматичное использование. А то что у тебе мап вернет список nil-ов, а результатом его выполнения будет побочные эффекты объесняет твою любовь забивать гвозди приборами с нежной оптикой. Еще к тому же ты передаешь в мап функцию, а я просто кусок программы в скопе тела. Чуешь разницу? Вот это пример того, как с помощью макроса вводится абстракция, с помощью которой задача решается наиболее естественным образом.

А так я _тебя_ спрашивал - что думаешь по этому поводу? То есть «полноценные» макросы в статических и не гомоиконных языках это как бы проблема (то есть проблема в их удобной реализации, люди вон тезисы на эту тему пишут).

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

Интересно другое - зачем ты спрашиваешь? Ты никогда макросов не видел?

Вопрос возник из-за того, что по твоим постам иногда кажется, что ты не понимаешь суть макросов.

Пока что я вижу только forech, SQL в s-выражениях и пересказы

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

и пересказы проповедей Хикки про то какое негодное классическое ООП,

Ты в курсе про что идет речь? Если нет послушай суть http://www.infoq.com/presentations/Value-Values

как хороши мультиметоды

Да, хороши, т.к. позволяют осуществлять диспетчеризацию не только по типу, но и по любому значению, по любым данным, включая коллекции. А в ОО это просто обрубок.

и как хороши pesistent shared контейнеры

Еще как хороши. Они позволяют писать чистый дешевый с точки зрения памяти фп код. Например, если ты меняешь или добавляешь только один элемент в коллекции (множество, мап, лист, вектор), то тебе приходится или делать это мутабельно или создавать копию оригинала с изменениями. Persistent data structures это решает.

нормальные небоксированные мутабельные структуры данных с in-place обновлением и кастомными механизмами inter task синхронизации не нужны, как я понимаю

Для некоторых алгоритмов они очень нужны. В clojure ты можешь заюзать стандартные мутабельные коллекции джавы и в императивном оптимальном виде реализовать необходимый императивный алгоритм. Все зависит от задачи.

ФП можно так понимать - типы как объекты,

Ой-ли! В хаскеле типы это контракты.

HOFs как экспоненциалы,

Это ничего не меняет. И так все понятно. А как быть с побочными эффектами? В хаскеле жопа с этим. Монады это хорошо, но с ними не получится работать как с обыкновенными функциями, т.е. нельзя будет использовать всю мощь фп, т.к. монадах результат всегда спрятан в конструкторе M <тип>, где реальный результат может быть спрятан в коллекции, а может в недрах функции, да еще может еще быть не еще вычисленным. Ты не можешь использовать стандартные фвп (fold..., filter, map, etc) при работе с монадами. А в лиспе, включая clojure, побочные эффекты возможны. Более того, в clojure есть STM. Если ты бы удосужился посмотреть/почитать по STM в clojure, ты прозрел, и не писал про «HOFs как экспоненциалы».

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

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

Кто так делает? Haskell

Хаскель это хорошо. Но создатель clojure не гнался за чистотой концепций. Он создал лаконичный мощный язык, взяв лучшее из других языков и добавив современные идеи, о которых только пишут/мечтают функциональщики. Как может хаскель вообще соревноваться с clojure, у которого jvm, крутое java interoperability, persistent data structures, STM, lisp, homoiconicity и пр. + все возможности хорошего фп языка?

А можно не принимать такой номенклатуры, ограничиваясь look ma, lambdas, closures and HOFs!

Не надо себя ограничивать. Надо развиваться.

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

Насчёт eDSL и ФВП - тут просто грань между «eDSL» и библиотечным кодом слишком неясная.

Это вещи ортогональные. eDSL реализуется в виде библиотечного кода.

Класс с интерфейсом это может быть eDSL?

Нет

Построение SQL удобными функциями скрывающими обычный string builder? HTML на комбинаторах вокруг writer monad?

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

means of elements, means of combinations и means of abstractions

И чего ты прицепился к абсолютно произвольным словам абсолютно произвольной книжки?

Потому что это фундаментальная вещь. Это мощь создаваемого слоя (dsl-а). Я неустанно буду для вопрошающий приводить пример из SICP-а http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec_2.2.4.

Или ты это тоже не можешь показать?

Нет. Опять же, это очевидно - объяснять что такое индуктивные типы, какие есть варианты

Или ты это тоже не можешь показать?

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

Я тебя просил не объяснять очевидные вещи, а показать, как реализуется «means of elements, means of combinations и means of abstractions», хотя бы на простых примерах. Ты любишь на конкретные вопросы отвечать о совсем другом общими понятиями. Странно.

Выучи какой-нибудь ML/Haskell, почитай TAPL, ATTAPL, Practical Foundations for Programming Languages, Software Foundations (also - http://alexott.net/ru/fp/books). Это если ближе к практике и ЯП, а не к теории.

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

Общие вещи

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

Я не про разбираться. Ты приводишь вещи не в тему. Что не говорит о том, что это не интересно.

Макры всем этим вещам ортогональны.

Ты не знаешь что такое макросы, выходит.

По твоему выходит так. По моему, наоборот. Дилемма.

Я тебе конкретный вопрос задал, а ты мне вопросом отвечаешь?

Ну то есть нормально с тобой поговорить нельзя? Вопрос задать, например?

Или я не понял, что ты уже про другое вопрос задаешь, или ты так задаешь вопросы. Одно из трех.

Уже после третьего-четвёртого звена в цепочке уже вон как колотит, но не понятно с чего.

Просто реакция на троллинг - меняется форма общения. Сердце бьется спокойно размеренно, дыхание ровное.

А конкретные примеры есть по ссылкам, да и вообще, «У каждого дебила-кодера на пэхэпэ есть мнение о программировании на ЯП в целом» - то есть всё и так должно быть известно чтобы можно было высказать это самое мнение.

По разному бывает. Зависит от «мнения».

путая edsl c не edsl-ами

Тут везде в моих постах у eDSL есть e, у DSL - нет, не мои проблемы.

По идее здесь вообще про DSL без «e» речи не было.

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

Все правильно он говорит, не можешь. Надо специальные костыли типа mapM_ и т.п.

А все потому что хаскель изначально сломан - в силу того что сломана теория категорий.

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

Все правильно он говорит, не можешь.

Но ведь это полнейшая чушь. Любая монада является функтором по определению:

fmap ab ma = ma >>= (return . ab)
anonymous
()
Ответ на: комментарий от anonymous

Это мечтах твоих она является функтором. А в хаскеле - не является, потому что он сломан.

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

Пойми, макросы не просто «вводят магические символы...», а вводят новую конструкцию со своей логикой.

Это понятно, я говорил что бывают гигиенические макросы которые

  1. вводят конструкции не изменяющие скоп раскрытия и
  2. завязываясь на скоп определения

и не гигиенические - отличие в основном в том, что первые проще отлаживать и сложнее получить ошибки связанные с именами. В CL принято достигать 1) за счёт разных gensym/with-unique-names и 2) за счёт того что макрос раскрывается в символы из определённых пакетов которым можно сделать lock (my-unless из википедии не будет работать) и отключить его обратно (чтобы хакнуть my-unless), если этого не делать, то как раз начнутся не гигиенические макросы с магическими именами в скопе, иногда - намеренно. В Clojure так же - ручной # для уникальных имён и тот факт, что имена в макросах разрешаются по пакетам (будет clojure.core/not для not, например).

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

Зависит от макросов и специальных форм, например loop + when:

(sb-cltl2:macroexpand-all '(loop :for a :in '(1 nil 2 nil 3) :when a :do (princ a)))

(BLOCK NIL
  (LET ((A NIL) (#:LOOP-LIST-791 '(1 NIL 2 NIL 3)))
    (DECLARE (TYPE LIST #:LOOP-LIST-791))
    (TAGBODY
     SB-LOOP::NEXT-LOOP
      (SETQ A (CAR #:LOOP-LIST-791))
      (SETQ #:LOOP-LIST-791 (CDR #:LOOP-LIST-791))
      (IF A
          (PRINC A))
      (IF (ENDP #:LOOP-LIST-791)
          (PROGN (GO SB-LOOP::END-LOOP))
          NIL)
      (GO SB-LOOP::NEXT-LOOP)
     SB-LOOP::END-LOOP)))

= tagbody + if, которые компилируются тривиально. Про то что многие другие макросы вроде do или with* раскрываются тривиально я уже говорил. То есть, особо страшно быть не должно - либо понятные вещи, либо кишки реализации.

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

Как раз джавакодеру понятно, что скрывать реализацию от интерфейса и комбинировать полученное нужно с помощью паттернов GoF и иже с ними, а не с помощью макросов и нагромождения макро-eDSLей. Единственное что он не может - это вводить произвольные синтаксические конструкции, поэтому мучается с XML. В Scala можно с ним мучиться гораздо меньше, и за счёт более развитого ООП, и за счёт функциональщины, при этом нагородить eDSLей на ADT/HOFs тоже уже вполне возможно. Ну и макросы появились в сабжевом релизе, да.

У Норвига есть на эту тему - http://norvig.com/design-patterns - разные языковые фичи для разных паттернов, макросы только для interpretor, compiler и syntactic abstraction.

МЕХАНИЗМ МАКРОСОВ ОРТОГОНАЛЕН НЕГЕНЕРЯЩЕМУ КОД ВОЗМОЖНОСТЯМ ЯЗЫКА

И? Self нету, я хочу его сгенерировать с помощью ортогональных языку макросов (сишных, да). Если бы был - не хотел бы вообще (и про макросы бы не вспомнил в данном конкретном случае).

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

В случае простых применений про которые шла речь они мало чем отличаются.

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

Недоинструменты это кто? Негигиенических макросы про которые я говорил? Или С++ который у меня втесался?

Это называется плохое проектирование языка.

Ну до Clojure ему в этом ещё далеко %) В смысле, если clojure это такой навороченный python с макросами и т.д. и т.п., тогда с ним всё ОК, конечно, только тогда с C++ вообще нет смысла даже сравнивать - разного назначения языки.

Что это?

Пять вариантов на хаскеле и два на скале (== означает, «или можно так написать - »). Все варианты короче и проще, так как используют исключительно функции. forM_ seq print или mapM_ print seq или seq forech print же явно проще чем (foreach [x seq] (print)), нет? Если нужен x, то forM_ с лямбдой - forM_ seq $ \x -> do { print x; ... }, или на скале - seq foreach { x => ... и тут вообще свободный блок, без всяких танцев с IO ... }.

Вообще, если говорить про кастомные итерации, то в хаскеле я примерно так делал - вводится достаточный интерфейс для потоков:

class Stream s where
  streamFirst :: s e -> e
  streamRest :: s e -> s e
  streamIsEmpty :: s e -> Bool

например ленивые списки:

instance Stream [] where
  streamFirst = head
  streamRest = tail
  streamIsEmpty = null

какое-нибудь обобщение итерации по ним:

class Stepper f where
  apply :: Stream s => f s a e -> s e -> a -> (s e -> a -> a) -> a

и пишется необходимая функция итерации в общих терминах:

loop :: (Stream s, Stepper f) => s e -> a -> f s a e -> a
{-# INLINE loop #-}
loop stream acc stepper = go stream acc where
  go stream acc | streamIsEmpty stream = acc
                | otherwise = apply stepper stream acc go

после этого можно сделать простейший ленивый вариант:

newtype RightStepper s a e = RightStepper (e -> s e -> a -> a)

lazy :: (e -> s e -> a -> a) -> RightStepper s a e
lazy = RightStepper

instance Stepper RightStepper where
  {-# INLINE apply #-}
  apply (RightStepper stepper) stream acc go =
    stepper (streamFirst stream) (streamRest stream) (go (streamRest stream) acc)

так что

foreach :: Monad m => [e] -> (e -> m ()) -> m ()
foreach xs f = loop xs (return ()) $ lazy $
  \e _ a -> f e >> a

testLazyIO :: IO ()
testLazyIO = foreach ([1 .. 1000000] :: [Int]) $
  \e -> when (even e) $ do
    print e
    printf "%d * %d = %d\n" e e (e * e)

будет работать нормально и компактно по памяти.

Или можно ввести расширяемый строгий вариант:

data LoopControl s a
  = Yield a
  | Transform (s -> s) !a

newtype LeftStepper s a e = LeftStepper (e -> s e -> a -> LoopControl (s e) a)

strict :: (e -> s e -> a -> LoopControl (s e) a) -> LeftStepper s a e
strict = LeftStepper

instance Stepper LeftStepper where
  {-# INLINE apply #-}
  apply (LeftStepper stepper) stream acc go =
    case stepper (streamFirst stream) (streamRest stream) acc of
      Yield acc' -> acc'
      Transform transform acc' -> go (transform stream) acc'

который умеет возвращать значения на произвольной итерации, пропускать значения произвольными трансформациями, look-ahead и, соответственно, подциклы. Пишутся разные

class Next t where
  next :: t

instance Stream s => Next (a -> LoopControl (s e) a) where
  next = Transform streamRest

и т.п. yield, with, etc комбинаторы.

testStrictLoop :: IO ()
testStrictLoop = do
  n <- fmap (read . head) getArgs
  print $ loop [1 .. n] 0 $ strict $
    \e _ a -> next (e + a)

при этом тоже работает нормально и компактно по памяти - числа берутся из ленивого генератора, но складываются строго, так что санки не накапливаются. next и т.п. можно сделать общими для ленивого и строго варианта, так что выбор будет осуществятся один раз выбором strict или lazy.

Какие-то другие вещи можно доделывать в том же духе. Например, простейший конкурентный for:

forP :: [t] -> (t -> IO a) -> IO ()
forP xs f = mapM (async . f) xs >>= mapM_ wait

(используется пакет async, async использует механизм лёгких тредов a la Erlang в GHC и его же STM) и дальше можно расширить язык (чтобы не сказать eDSL) LoopControl конструкторами для форков, джоинов, сообщений (с транспортом через STM, опять же), либо, более правильно, делать этот язык отдельным и монадическим, потом сочетать с LoopControl.

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

map он для другого

Нет. mapM_ :: Monad m => (a -> m b) -> [a] -> m () и forM_ :: Monad m => [a] -> (a -> m b) -> m () как раз для этого, они делают map (тут - именно настоящий map о котором ты говоришь, то есть map :: (a -> b) -> [a] -> [ b ]) для effectful кода переданного как функция, выполняют полученный список действий (sequence_ :: Monad m => [m a] -> m ()) и опускают результат, никаких списков они не возвращают, дважды список не проходят, так как это ленивый конвейер с list fusion (пройти бесконечный список дважды он явно не сможет, то есть работает иначе).

Чуешь разницу?

Да. Передавать функцию, лямбду или блок которые полноценные (проверенные, я бы сказал) выражения (expressions) всяко лучше чем передавать непонятный «кусок программы» (опять же, история с shadowing, гигиеной, с тем чтобы макрос вёл себя всегда хорошо - в случае с foreach это, конечно, так, он тоже проверенный).

Если нет послушай суть http://www.infoq.com/presentations/Value-Values

Смотрел, мне больше понравилась более ранняя http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey (если не путаю).

хороши, т.к. позволяют

Вот, кстати, показательно. А кому-то «хороши» = «запрещают», «бьют по рукам».

А паттерн матчинг (+ guards) по типам и значениям мог бы дать то что дают кложуровские мультиметоды?

В хаскеле типы это контракты.

В хаскеле они точно _не_ контракты.

Это ничего не меняет

Да, тут анонимус рядом сказал, что это чисто символическое переименование - просто категорное выражение того факта, что функции могут принимать функции и возвращать функции, в TK функции это стрелки из объектов-типов в объекты-типы, например id : a -> a или (+ 1) : Int -> Int, так что сами стрелки-функции чтобы быть first class должны быть объектами-типам, такие и называются «экспоненциалы», например (.) : (b -> c) -> ((a -> b) -> (a -> c))), это записывается ещё как Hom(b, c) -> Hom(Hom(a, b), Hom(a, c)).

Интересно начинается дальше, то есть

А как быть с побочными эффектами?

в такого рода вещах - «HOFs как экспоненциалы» тут уже совсем ни при чём.

В хаскеле жопа с этим.

Значит всё это как и многое другое святым духом работает. Как yesod, например, работает?

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

Монада это тип, например тип «список» это функтор и монада, тип «функция» - тоже монада, но в остальном монады как типы это явно не функции. _С помощью_ обыкновенных функций с ними, конечно, можно работать, используя и «всю мощь фп» тоже.

результат всегда спрятан в конструкторе M <тип>

Ну monadic >>= f где f это просто функция принимающая <тип>, или f <$> monadic, или (catch (f (run monadic)) ...) для не IO.

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

Достать из коллекции? Кроме того, коллекция, скорее всего, тоже монада, так что трансформеры во все поля.

а может в недрах функции

Это как? Функции можно применять.

да еще может еще быть не еще вычисленным

Это от программиста зависит - хаскель не только нестрогий, но и строгий, то есть нужно делать выбор. Выше в коде я сделал у LoopControl второй аргумент Transform строгим и всегда вычисляемым наперёд.

Ты не можешь использовать стандартные фвп (fold..., filter, map, etc) при работе с монадами

Это не «стандартные фвп», это ФВП для списков (или коллекций, если обобщать) - если есть где-то списки, то вполне можно их использовать:

test = foldr (\e a -> print e >> a) (return ()) [1, 2, 3]

ну и нужно различать монады и IO. Анонимус тоже не различает, а между тем sequence это просто foldr (потому что списки), mapM - sequence от обычной map (тоже). И, обратно, mapM и т.п. это просто map и т.п. в монаде Identity, то есть они - обобщение, а не нечто непонятное сбоку.

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

Единственное что «нельзя» для многих монад это m a -> a, что абсолютно логично до тех пор пока мы считаем ссылочную-непрозрачность и частичность функций чем-то нехорошим. Но run :: m a -> a тоже написать можно, потом ловить исключения для всего кроме IO.

Ещё необходимость оборачивать вещи в конструкторы (в трансформерах, например) может не нравиться, хотя newtype всё равно ничего не стоит в рантайме, но делает вещи (уровни монадического стека, например) различимыми.

А в лиспе, включая clojure, побочные эффекты возможны.

В хаскеле они тоже возможны.

Более того, в clojure есть STM.

Вот в одном из своих выступлений Хикки упоминал STM хаскеля, мол, у них оно так, но вы не путайте - у нас своё доморощенное STM, потом помахал ручкой хаскелистам (TVar ему не нравится).

Если ты бы удосужился посмотреть/почитать по STM в clojure, ты прозрел, и не писал про «HOFs как экспоненциалы».

А при чём тут «HOFs как экспоненциалы»? STM это совсем другой уровень, они тут ни при чём, повторю.

но приводить аналогии с теорией категорий и длинный списки очевидных вещей

Тогда расскажи в чём фишка ко-свободных ко-монад?

Наверно, можно подождать http://nescala.org/2013/talks#31.

ничего не показывает/доказывает

Ничего. Хотя если начать с простого - например, каррированные функции, часто можно видеть, как «стратегия» едущая через «декораторы» с «адаптерами» заменяется банальными применениями и композициями таких функций (например). А против того, что ((->) a) это монада (называется reader/environment) не попрёшь - так оно устроено, ну и дальше все эти используемые вещи так и называются - «монады» и т.п., примерно как в GoF придумывают свою терминологию (оснований-то нет) тут используют свою + частично из теории категорий, теории типов, алгебры и т.п. (есть основания). В принципе, и под ООП можно попробовать подвести такие основания, хотя проще, наверное, использовать сложившуюся терминологию.

добавив современные идеи, о которых только пишут/мечтают функциональщики

Думаю, не все о таком мечтают. Начать с динамической типизации хотя бы. А что там за современные идеи? Явно не Теория Типов. А та же composable STM была реализована в хаскеле за два года до появления Clojure. То есть существует уже 8 лет.

jvm, крутое java interoperability

Это плюс? У Scalы вот тоже это есть, но не всегда это плюс - для десктопных приложений не очень, для веба не плохо, но иногда напрягает неповоротливый процесс разработки (IDEA + play + REPL + browser + ...).

persistent data structures

TVar & ко в монаде STM тоже персистентены. То есть данные нужно либо копировать, либо осилить нормальное STM для полностью мутируемых данных.

STM

При чём тут хаскель, казалось бы.

lisp, homoiconicity

Как может хаскель вообще соревноваться с clojure

И не говори :)

+ все возможности хорошего фп языка?

Читай, look ma, lambdas, closures and HOFs!?

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

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec_2.2.4

Ну вот как раз - на хаскеле бы выглядело как парочка data («elements» и «combinations»), парочка функций («combinations» и «interpretation»), денотационная семантика («abstractions») это, например, тесты на quickcheck или формальная верификация. Но трудно назвать такое eDSL - функции, API, тесты, слишком просто, короче.

Зачем?

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

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

Возможно, хотя OCaml и Haskell вполне можно использовать. Ещё Scala близка к некоторым их (MLей) идеям, но в ней и своих много.

Или я не понял, что ты уже про другое вопрос задаешь, или ты так задаешь вопросы.

Там у меня было про deriving как средство генерации top-level. Например для варианта набора структур:

data DataType
  = Con1 ...
  | Con2 ...
  deriving ( Read, Show, Eq, Ord, Typeable, Data )

derive makeBinary ''DataType

автоматически получается - парсер, принтер, операции сравнения, порядка, рефлексия, обобщённые свёртки и отображения, код сериализации и десериализации, могут быть и другие инстансы - http://hackage.haskell.org/package/derive. Если deriving после data это часть языка и реализуется GHC, то derive это «макрос» который пишет соответствующий код сериализации / десериализации. Не очень часто, но и не очень редко можно такое встретить (happstack и yesod используют, например).

Если это «не то», потому что не гомоиконично - вот в лиспе я не нашёл подобных средств, хотя он и гомоиконичен, то есть в нём такой код будет выглядеть предельно просто:

;; TODO: написать реализацию ADT (на макросах) и десятки форм обобщённого deriving (тоже).

Дальше я спрашивал, что есть «то» - но ты уже выше ответил про своё мнение о TH и Nemerle.

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

Пойми, макросы не просто «вводят магические символы...», а вводят новую
конструкцию со своей логикой.

Это понятно, я говорил что бывают гигиенические макросы которые ... и не
гигиенические - отличие в основном в том,

Я тебе про Фому, а ты мне про Ерему. Опять ты мне про известные вещи. Или ты хотел что-то спросить и порассуждать? Если что, в clojure, в отличии от коммон лиспа, макросы гигиенические.

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

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

Зависит от макросов и специальных форм, например loop + when: ... Про то
что многие другие макросы вроде do или with* раскрываются тривиально я
уже говорил. То есть, особо страшно быть не должно - либо понятные вещи,
либо кишки реализации.

Ты не читаешь, что я тебе пишу. Речь не про страшно. Ты когда используешь конструкцию высокоуровневого языка, ты же не смотришь каждый раз, какой машинный/ассемблерный код он генерит? Ты оперируешь абстракцией, которую предоставляет тебе язык программирования (конечно, знать принцип действия ты должен, чтобы не было эффекта «маляра Шлемиля»). Так и с макрами: они реализуют абстракцию, и ты ей пользуешься, не проверяя каждый раз сгенерированный ими код.

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

Как раз джавакодеру понятно, что скрывать реализацию от интерфейса

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

(defn get-next-work-days [count]
   (take count (filter work-day?
                      (iterate (partial add-day 1)
                               (tomorrow)))))

И мне не нужно знать что-то про lazy-seq, recur, nth и пр. Я работаю с более высокоуровневой абстракцией: у меня есть источник, генерящий поток последовательности дат с завтрашнего дня, мне нужно из всех рабочих дней этого потока взять первые «count» дней. Вот пример сокрытия нижележащего слоя, а в той же джаве сокрытие логики просто курам на смех. Посмотри на код внутри методов - каменный век.

и комбинировать полученное нужно с помощью паттернов GoF и иже с ними,

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

а не с помощью макросов и нагромождения макро-eDSLей ...

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

МЕХАНИЗМ МАКРОСОВ ОРТОГОНАЛЕН НЕГЕНЕРЯЩЕМУ КОД ВОЗМОЖНОСТЯМ ЯЗЫКА

И? Self нету,

Накуа self нужен не в ОО языке?

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

Ты болеешь?

Если бы был - не хотел бы вообще (и про макросы бы не вспомнил в данном
конкретном случае).

Мне, например, похрен до self-а. Для чего он тебе вне ООП?

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

В случае простых применений про которые шла речь они мало чем отличаются.

Если для тебя работа c nested collections с self-evaluated объектами и символами «мало чем отличается» от работы со строками, то это диагноз.

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

Недоинструменты это кто? Негигиенических макросы про которые я говорил?
Или С++ который у меня втесался?

Тебе к доктору. Какие негигиенические макры? Ты какое-то сишное макроговно привел. Потом пытался что-то там объяснить. Про это объяснение и был коммент.

Это называется плохое проектирование языка.

Ну до Clojure ему в этом ещё далеко %) В смысле, если clojure это такой
навороченный python с макросами и т.д. и т.п., тогда с ним всё ОК,

Тебя в голову ранили? Болезный, какой питон?

конечно, только тогда с C++ вообще нет смысла даже сравнивать - разного
назначения языки.

Какое назначение у clojure и С++?

Пять вариантов на хаскеле и два на скале (== означает, «или можно так
написать - »). Все варианты короче и проще, так как используют
исключительно функции. forM_ seq print или mapM_ print seq или seq
forech print же явно проще чем (foreach [x seq] (print)), нет? Если
нужен x, то forM_ с лямбдой - forM_ seq $ \x -> do { print x; ... },

Вот теперь мы проверим аналогичность твоего forM_. Напиши аналоги этих двух кусочков кода на хаскеле с forM_:

(doseq [[x y] '[[1 a] 
                [2 b] 
                [3 c]]]
  (println x "," y))

результат

1 , a
2 , b
3 , c
(doseq [x [1 2]
        y '(a b)]
  (println x "," y))

результат

1 , a
1 , b
2 , a
2 , b

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

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

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

Значит всё это как и многое другое святым духом работает. Как yesod, например, работает?

С точки зрения хаскеля - это некорректный вопрос. Программа на хаскеле генерирует вычисление (со стрелками монадами и прочим, да), а как работает само это вычисление - уже вопрос не к хаскелю, там нету стрелок и монад :)

Монада это тип

Ну такого я от тебя не ожидал. монада - это тайпкласс, какой же она тип?

Это от программиста зависит - хаскель не только нестрогий, но и строгий

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

ну и нужно различать монады и IO.

Как их можно различать, если IO - монада?

В хаскеле они тоже возможны.

Нет, невозможны. Разве хаскель - не чистый язык?

Тогда расскажи в чём фишка ко-свободных ко-монад?

а ни в чем :))

Читай, look ma, lambdas, closures and HOFs!?

Именно. А какие еще могут быть возможности?

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

Если это «не то», потому что не гомоиконично - вот в лиспе я не нашёл подобных средств, хотя он и гомоиконичен

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

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

и не гигиенические - отличие в основном в том, что первые проще отлаживать и сложнее получить ошибки связанные с именами. В CL принято достигать 1) за счёт разных gensym/with-unique-names и 2) за счёт того что макрос раскрывается в символы из определённых пакетов которым можно сделать lock (my-unless из википедии не будет работать) и отключить его обратно (чтобы хакнуть my-unless), если этого не делать, то как раз начнутся не гигиенические макросы с магическими именами в скопе, иногда - намеренно. В Clojure так же - ручной # для уникальных имён и тот факт, что имена в макросах разрешаются по пакетам (будет clojure.core/not для not, например).

Можно вводить «магические символы» безопасно и не нарушая гигиену, да. я уже выше говорил об этом.

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

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec_2.2.4

Ну вот как раз - на хаскеле бы выглядело как парочка...

Я не спрашивал тебя, как это должно выглядеть в хаскеле. Это к тому, что, судя по вопросу «И чего ты прицепился к абсолютно произвольным словам абсолютно произвольной книжки?», ты не понимаешь, что означают «means of elements, means of combinations и means of abstractions» при разработке eDSL-а. Вот я и привел тебе пример из учебника, где это наглядно продемонстрировано.

Зачем?

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

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

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

Возможно, хотя OCaml и Haskell вполне можно использовать.

Зачем мне «возможно практичный» язык?

Ещё Scala близка к некоторым их (MLей) идеям, но в ней и своих много.

Зачем мне близость к каким-то идеям, если они не позволяют коротко и ясно решать задачи? Куда ни копни твой хаскель, который «очень близок» к идеям, шаг влево, шак вправо от чистой фп парадигмы идет сплошная жопа.

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

Там у меня было про deriving как средство генерации top-level. Например для варианта набора структур:

data DataType
  = Con1 ...
  | Con2 ...
  deriving ( Read, Show, Eq, Ord, Typeable, Data )

derive makeBinary ''DataType

автоматически получается - парсер, принтер, операции сравнения, порядка, рефлексия, обобщённые свёртки и отображения, код сериализации и десериализации, могут быть и другие инстансы - http://hackage.haskell.org/package/derive.

Судя по http://www.haskell.org/onlinereport/derived.html, в deriving есть ограничение «Derived instances are possible only for classes known to the compiler: those defined in either the Prelude or a standard library.». Т.е. этот список расширить нельзя?

Если deriving после data это часть языка и реализуется GHC, то derive это «макрос» который пишет соответствующий код сериализации / десериализации.

Этот макрос является частью языка или ты можешь реализовать свой deriving макрос?

Если это «не то», потому что не гомоиконично - вот в лиспе я не нашёл подобных средств, хотя он и гомоиконичен, то есть в нём такой код будет выглядеть предельно просто:

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

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

map он для другого

Нет. mapM_ :: Monad m => (a -> m b) -> [a] -> m () и forM_ :: Monad m => [a] -> (a -> m b) -> m () как раз для этого, они делают map (тут - именно настоящий map о котором ты говоришь, то есть map :: (a -> b) -> [a] -> [ b ])

Т.е. все-таки пришлось писать отдельный мап для монад?

Чуешь разницу?

Да. Передавать функцию, лямбду или блок которые полноценные (проверенные, я бы сказал) выражения (expressions) всяко лучше чем передавать непонятный «кусок программы»

Чем не понятно тело foreach? Просто так сказал?

Если нет послушай суть http://www.infoq.com/presentations/Value-Values

Смотрел, мне больше понравилась более ранняя http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey (если не путаю).

Я тебе скинул линк на выступление на конкретную крутую тему, а ты мне про «понравилось другое выступление» и это «если ты не путаешь». Не страдай муйней, посмотри, потом можно будет про ООП поговорить.

хороши, т.к. позволяют

Вот, кстати, показательно. А кому-то «хороши» = «запрещают», «бьют по рукам».

Ага, ответил сам себе. В оригинале было было про позволяет проводить диспетчеризацию более гибко. Ты же булькнул в лужу в ответ про булькнул в лужу про «запрещают» и «бьют по рукам».

Это ничего не меняет

Да, тут анонимус рядом сказал, что это чисто символическое переименование - просто категорное выражение того факта, что функции могут принимать функции и возвращать функции, в TK функции это стрелки из объектов-типов в объекты-типы, например id : a -> a или (+ 1) : Int -> Int, так что сами стрелки-функции чтобы быть first class должны быть объектами-типам, такие и называются «экспоненциалы», например (.) : (b -> c) -> ((a -> b) -> (a -> c))), это записывается ещё как Hom(b, c) -> Hom(Hom(a, b), Hom(a, c)).
Интересно начинается дальше, то есть

А как быть с побочными эффектами?

в такого рода вещах - «HOFs как экспоненциалы» тут уже совсем ни при чём.

Повторю, это ничего не меняет. Ты сам завел тему про «экспоненциалы» и теперь сам с собой споришь.

В хаскеле жопа с этим.

Значит всё это как и многое другое святым духом работает. Как yesod, например, работает?

Хорошо, работает через жопу.

Ты не можешь использовать стандартные фвп (fold..., filter, map, etc) при работе с монадами

Это не «стандартные фвп», это ФВП для списков (или коллекций, если обобщать) - если есть где-то списки, то вполне можно их использовать:
test = foldr (\e a -> print e >> a) (return ()) [1, 2, 3]

Вот видишь, сам же привел аргументы в пользу моего тезиса. Тебе нужно заворачивать в return начальное значение, также интересен результат fold-а. Я в clojure могу написать так:

(reduce (fn [res x] 
          (println x) 
          (+ res x)) 
        [1 2 3])

У меня будет нормальный ответ «6», никаких заворачиваний в return, да еще и побочный эффект сработает в виде вывода на stdout значений элементов коллекции. Сможешь привести аналог на хаскеле?

ну и нужно различать монады и IO

Согласен с анонимусом. Ты уж определись, IO монада или нет.

А в лиспе, включая clojure, побочные эффекты возможны.

В хаскеле они тоже возможны.

Ага, уже видели как.

Более того, в clojure есть STM.

Вот в одном из своих выступлений Хикки упоминал STM хаскеля, мол, у них оно так, но вы не путайте - у нас своё доморощенное STM, потом помахал ручкой хаскелистам (TVar ему не нравится).

Еще бы понравились. Почитал http://book.realworldhaskell.org/read/software-transactional-memory.html, посмеялся, особенно про ручной retry.

В clojure есть механизм снэпшота MVCC для ненужности retry при чтении. Также в clojure есть commute для уменьшения retry. Еще есть несколько типов работы с STM через refs, atoms, agents. По сравнению с нагромождениями в заскеле работа в clojure с STM выглядит просто, лаконично, прозрачно и удобно.

но приводить аналогии с теорией категорий и длинный списки очевидных вещей

Тогда расскажи в чём фишка ко-свободных ко-монад?

Повторю, раз не въезжаешь. ФП не обязано быть чистым, как в хаскеле, ФП не обязано быть типизированным как в хаскеле. Есть масса нечистых фп языков, в их числе и clojure, которые не используют так понятийный аппарат теории категорий. Теперь понятно, про что был мой ответ?

А против того, что ((->) a) это монада (называется reader/environment) не попрёшь - так оно устроено, ну и дальше все эти используемые вещи так и называются - «монады» и т.п., примерно как в GoF придумывают свою терминологию (оснований-то нет) тут используют свою + частично из теории категорий, теории типов, алгебры и т.п. (есть основания).

Это какой нужно иметь моск, чтобы проводить аналогии вводимых бандой четырех для классификации быдлокода терминов с вводимым понятийным аппаратом из теории категорий в хаскель. Блеск. Пизшы есчо.

В принципе, и под ООП можно попробовать подвести такие основания, хотя проще, наверное, использовать сложившуюся терминологию.

Подводи. Разрешаю.

добавив современные идеи, о которых только пишут/мечтают функциональщики

Думаю, не все о таком мечтают.

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

Начать с динамической типизации хотя бы.

Ну начни. Какие претензии к динамической типизации?

А что там за современные идеи? Явно не Теория Типов. А та же composable STM была реализована в хаскеле за два года до появления Clojure.

Спасибо, глянул http://book.realworldhaskell.org/read/software-transactional-memory.html. Жри такое гавно сам.

То есть существует уже 8 лет.

Это не жизнь. Это не жить (с) Стругацкие

persistent data structures

TVar & ко в монаде STM тоже персистентены. То есть данные нужно либо копировать, либо осилить нормальное STM для полностью мутируемых данных.

Ну не позорься так. В clojure когда я добавляю элемент в вектор (conj v :new-elem), то у меня будет уже два вектора: исходный v и новый, реюзающие все елементы, кроме добавленного. Если я изменяю значение у ключа в мапе (assoc m :key10 :new-value), то у меня будет два мапа, реюзающие все пары мапа, кроме пары с ключом :key10. Покажи мне аналог в хаскеле?

STM

При чём тут хаскель, казалось бы.

Как выяснилось, не причем.

lisp, homoiconicity
Как может хаскель вообще соревноваться с clojure

И не говори :)

Не буду. Ты все равно не врубаешься.

+ все возможности хорошего фп языка?

Читай, look ma, lambdas, closures and HOFs!?

Вот именно, это тоже включено.

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

А паттерн матчинг (+ guards) по типам и значениям мог бы дать то что дают кложуровские мультиметоды?

Ну, давай, изобрази петтерн матчингом, например, вот этот вариант:

(defmulti q-lame (fn [elevator passengers floor]
                   (if (< (apply + (map :weight passengers))
                          (:max-weight elevator))
                     :normal
                     :overload)))

(defmethod q-lame :overload [_ _ floor]
  {:error :overload
   :result nil})

(defmethod q-lame :normal [elevator passengers floor]
  {:error :ok
   :result {:elevator (assoc elevator :floor floor)
            :passengers passengers}})
Ritmik
()
Ответ на: комментарий от anonymous

монада - это тайпкласс, какой же она тип?

Классы типов их инстанцирование, как читать?

Типы List, Maybe, (a, _), (_, b), Either a _, Either _ b, r -> _ и т.д. - функторы и монады.

То что называется Monad : (M : (Type -> Type)) -> ... (Monad :: (* -> *) -> Constraint у GHC, например) это не монада, это интерфейс (typeclass, constraint, структура, запись, чистый абстрактный класс, концепт, trait, ...) для типа-монады M.

Как их можно различать, если IO - монада?

Как различать кроликов и млекопитающих?

В catch (a >>= b >> c) ... a, b и c - вполне IO, хотя и комбинируются с помощью общего интерфейса.

Нет, невозможны. Разве хаскель - не чистый язык?

Нет, вычисления нестрогие по умолчанию, строгие по требованию, чистые по умолчанию, эффектные в IO. Что касается

а как работает само это вычисление - уже вопрос не к хаскелю

К хаскелю, конечно, вопрос. Кому нужен putStrLn который не будет писать в stdout? И семантика (точнее, обе - small- и big- step) IO термов должна быть более-менее разумной. То же самое про строгость и ленивость - «сломано» оно потому что equational законы могут нарушаться или восстанавливаться обратно, но для хаскеля они просто воображаемые вещи - quickcheck и то большее значение имеет, то есть если ожидать от хаскеля, например, типы-как-утверждения и программы-как-доказательства - сломано, иначе - нет (лисп же не сломан, хотя UTLC как логику нельзя использовать).

А какие еще могут быть возможности?

Ну история же почти столетней давности (~1930) - типизация, там, всякая и т.п.

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

Или ты хотел что-то спросить и порассуждать?

Вообще - да. Ну и аллергия на макросы сказывается :(

Накуа self нужен не в ОО языке?

class Foo {

    typedef Foo Self;

    // &Self::method
    // ...

};

и C++ - ОО язык, в том числе.

Например, в коде для бизнес логике я пишу

Ну это как раз ФП, например на хаскеле:

getNextWorkDays n = take n . filter (day isWork) . map (day (+ 1))

или в духе ООП-как-посылка-сообщений + элементы ФП (передача функций, карринг), например скала:

def getNextWorkDays(count: Int) = tomorrow map (_.addDay(1)) filter (_.isWork()) take count

или

def getNextWorkDays(count: Int): List[Day] => List[Day] = _ map (_.addDay(1)) filter (_.isWork()) take count

То есть ОО/ФП как средства декомпозиции, о чём я и говорил.

Напиши аналоги этих двух кусочков кода на хаскеле с forM_

foreach != doseq. Второе всё-таки сложнее (тут ещё можно про loop или iterate из CL вспомнить), но да - нет проблем написать такую функцию doseq, разве я уже не писал про это в примере про loop?

Первое:

forM_ [(1 :: Int, "a"), (2, "b"), (3, "c")] $ \(x, y) -> printf "%d, %s\n" x y

Второе:

forM_ [1, 2] $ \x -> forM_ ["a", "b"] $ \y -> putStrLn $ show x ++ ", " ++ y

или

for2M_ :: Monad m => [a] -> [b] -> (a -> b -> m ()) -> m ()
for2M_ xs ys f = forM_ xs $ forM_ ys . f

и

for2M_ [1, 2] ["a", "b"] $ \x y -> putStrLn $ show x ++ ", " ++ y

наконец

class DoSeq seq iter | seq -> iter where
  doseq :: seq -> iter

instance Monad m => DoSeq [a] ((a -> m ()) -> m ()) where
  doseq = forM_

instance (Monad m) => DoSeq ([a], [b]) ((a -> b -> m ()) -> m ()) where
  doseq (xs, ys) f = forM_ xs $ forM_ ys . f

так что

doseq [(1 :: Int, "a"), (2, "b"), (3, "c")] $ \(x, y) -> printf "%d, %s\n" x y

и

doseq ([1, 2], ["a", "b"]) $ \x y -> putStrLn $ show x ++ ", " ++ y

ну и так далее - смотря что нужно, если итерации становятся совсем специальными, то пора задуматься о том чтобы отобразить вещи на ADT и им сделать удобные комбинаторы-ФВП.

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

Т.е. этот список расширить нельзя?

Этот - нет. Точнее, только для простейших случаев с newtype там можно дописывать что угодно.

Этот макрос является частью языка или ты можешь реализовать свой deriving макрос?

А тут - можно, в том и поинт. То есть это «почти макросы», но очень ограниченная их форма которая (у меня) не вызывает никаких вопросов а, наоборот, очень понятна.

Каких средств?

Например - ты написал кучу («размеченное объединение» / «вариант») структур, возможно рекурсивных, в которые сложным образом агрегируются другие варианты, вложенные структуры, строки, числа и т.п. - не будем про обобщённую свёртку (Data.Data), хочется просто чтобы автоматически написался оптимальный код сериализации / десериализации данного типа в / из бинарного представления, чтобы потом гонять значения этого типа по сети (ZMQ, например, хаскельный биндинг работает с ByteString, а binary в него сворачивает / разворачивает, derive пишет binary, так что цена - работать с ByteString или c Binary t => t где инстансы Binary часто получаются на халяву). То же самое про JSON - хочется читать / писать нативные данные как JSON, и про родное текстовое представление нативных данных - хочется видеть как они устроены, читать и писать это представление (типа s-выражений, только не только для списков), и про ORM persistent хранение нативных данных в БД. Такого рода вещи.

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

Т.е. все-таки пришлось писать отдельный мап для монад?

Тебе нужно заворачивать в return начальное значение, также интересен результат fold-а.

А как ты хочешь? То есть как предлагаешь делать в чистом языке? Именно в хаскеле можно сделать общий map и для монад и просто (через класс типов - выше class DoSeq на эту тему). А вообще - можно на уровне системы типов различать обычные и эффектные типы, делать хорошие преобразования между ними и автоматически лифтить функции в сторону хороших преобразований.

Всё абсолютно логично - тут либо мы изначально делаем язык с чистым уровнем, либо нет. В хаскеле вычисления вне IO чистые, внутри - лифтятся. Всё. А если это не нравится - хаскель вместе с чистотой сразу отправляется куда подальше.

У меня будет нормальный ответ «6», никаких заворачиваний в return, да еще и побочный эффект сработает в виде вывода на stdout значений элементов коллекции. Сможешь привести аналог на хаскеле?

Это конкретно называется Debug.Trace из base.

Чем не понятно тело foreach?

Простейший foreach ещё ничего, но просто никто на этом не останавливается - начинаются разные loop с iterate.

посмотри

Смотрел [2].

Теперь понятно, про что был мой ответ?

Так я не отрицаю, что это очень узкий взгляд на ФП, фактически, это ФП + чистота = плюшки + логические ограничения = плюшки + «матан» = плюшки.

я добавляю элемент в вектор ... у меня будет уже два вектора: исходный v и новый

Если я изменяю значение у ключа в мапе ... у меня будет два мапа

Покажи мне аналог в хаскеле?

Так делать не нужно - смысл в атомарных комбинируемых транзакциях с семантикой суть которой непосредственно в мутации структуры данных, то есть мы хотим так оградить себя от проблем возникающих в конкурентных программах шарящих данные - осилим сделать это на одном экземпляре структуры данных - хорошо, нет - ну, тоже реализация STM с той же семантикой, конечно. Когда Хикки говорит, что он хочет понимать под изменением что-то вроде state monad - (big-step) семантика изменения от этого не меняется, просто железо хуже утилизируется если делать буквально, поэтому ему приходится мудрить с написанием разделяемых коллекций на Java.

Кстати, то что persistent тормозит относительно transistent это нормально - TVar тоже будет тормозить относительно IORef, но с последним проще отстрелить себе ноги.

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

Чем отличается от функции q-lame [elevator passengers floor] которая по условию в if вызывает либо функцию q-lame-overload [elevator passengers floor], либо функцию q-lame-normal [elevator passengers floor]?

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

Типы List, Maybe, (a, _), (_, b), Either a _, Either _ b, r -> _ и т.д. - функторы и монады.

Ну так инстансы монад/функторов - это типы, а вот сами монады и функторы - тайпклассы, а не типы. Фишка же в том, что List тот же - это в хаскеле никакой не функтор.

Как различать кроликов и млекопитающих?

Не знаю. А как?

Нет, вычисления нестрогие по умолчанию, строгие по требованию, чистые по умолчанию, эффектные в IO.

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

И семантика (точнее, обе - small- и big- step) IO термов должна быть более-менее разумной.

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

(лисп же не сломан, хотя UTLC как логику нельзя использовать).

Лисп на чистоту и не претендует.

Ну история же почти столетней давности (~1930) - типизация, там, всякая и т.п.

Типы - такая же история. Современность - это макросы. Можно ли привести какой-нибудь случай, в котором нам могут понадобиться типы, если у нас есть макросы?

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

Такого рода вещи.

Ясно. Задача как раз заточена под макросы лиспа. А можно узнать как ее на АДТ можно решить, без макросов?

не будем про обобщённую свёртку

Почему не будем? Это же ни чем не отличается от генерации кода сереализации/десереализации. Более того - любое нормальное решение будет предполагать расширяемость дерайвинга - то есть добавить обобщенные свертки и т.п. (как кстати и стандартные комбинаторы типов) должен уметь сам пользователь, легко и просто. Надеюсь, такие элементарные вещи приведенный в пример дерайвинг умеет делать? А то если нет - то получается бесполезный неюзабельный костыль, и говорить о нем нечего тогда.

ЗЫ: на самом деле это еще один пример хаскельной сломанности - если бы пары и объединения (и другие комбинаторы типов) были полноценными типами (как это и должно быть в полноценном ЯП), то никакого дерайвинга не было бы нужно. Достаточно было бы написать реализацию соответствующих тайпклассов (сверкти, сереализации етк.) для примитивных типов и для соответствующих комбинаторов.

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

Или ты хотел что-то спросить и порассуждать?

Вообще - да. Ну и аллергия на макросы сказывается :(

Что да? Аллергия сказывается на желание спросить или порассуждать? Мда. Кстати, у тебя «аллергия» из-за непонимания и маленькой практики работы с макросами. Иначе бы ты смог объяснить технически недостатки макров, по причине которых ты в определенных случаях не используешь их. А ты напротив, весь тред пускался в абстрактные рассуждения, подменял мои высказывания и уходил от прямых вопросов. Что еще остается, как не объяснить все своей «аллергией».

Накуа self нужен не в ОО языке?

class Foo {

    typedef Foo Self;

    // &Self::method
    // ...

};

и C++ - ОО язык, в том числе.

Ты слепой? Еще раз спрошу. Накуа self нужен не в ОО языке?

Ну это как раз ФП, например на хаскеле:...
... например скала:...
То есть ОО/ФП как средства декомпозиции, о чём я и говорил.

Мой пример был на твой бредовый пост

Как раз джавакодеру понятно, что скрывать реализацию от интерфейса

Т.е. ты написал бред про «джавакодера» и когда я тебе ответил, решил подменить начальную свою мысль. Ну все как обычно.

foreach != doseq

doseq является реализацией foreach в clojure. Обоснуй уже хоть что-нибудь, а не пиши свои больные фантазии.

Первое:...
forM_ [(1 :: Int, «a»), (2, «b»), (3, «c»)] $ \(x, y) -> printf «%d, %s\n» x y

Как у тебя x и y, являясь двумя раздельными формальными параметрами лямбды инициализируются от конкретной пары?

Второе:... и наконец...так что ... и ...

И везде у тебя идет вложенные forM_ «forM_...$forM_». Поздравляю тебя с быдлокодом. Вместо

(doseq [x [1 2]
        y '(a b)]
  (println x "," y))

такое городить. А если переменных foreach-а больше 2-х? Пойми, foreach как и любой другая подобная конструкция позволяет работать с реализуемой ею абстракцией, как будто она является частью языка. Ты же пишешь «аналогии», которые должны генерироваться из введенной конструкции автоматически, а не руками, как ты это делаешь.

ну и так далее - смотря что нужно, если итерации становятся совсем специальными, то пора задуматься о том чтобы отобразить вещи на ADT и им сделать удобные комбинаторы-ФВП.

Ага, «удобные» звучит очень убедительно после твоих примеров.

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

Т.е. этот список расширить нельзя?

Этот - нет. Точнее, только для простейших случаев с newtype там можно дописывать что угодно.

Ну и слава богу, хоть что-то можно.

Этот макрос является частью языка или ты можешь реализовать свой deriving макрос?

А тут - можно, в том и поинт. То есть это «почти макросы», но очень ограниченная их форма которая (у меня) не вызывает никаких вопросов

Тогда какого лешего ты «очень ограниченные» «почти макросы» сравниваешь с полноценными макросами?

а, наоборот, очень понятна.

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

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

Открою тебе тайну: проблем с сериализацией у меня никаких нет. Но об это ни кому. Тссс.

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

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

А как ты хочешь?

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

То есть как предлагаешь делать в чистом языке?

Ты с умным видом влез в разговор со своими фантазиями, после чего отмазываешься фразами «как предлагаешь делать в чистом языке?». Я предлагаю, тебе в теме про лисп не заикаться про хаскель, если тебе нечего сказать по конкретно обсуждаемой теме.

А если это не нравится - хаскель вместе с чистотой сразу отправляется куда подальше.

Я это сразу понимал, а тебе сделал этот вывод на 16-й странице. Поздравляю.

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

(reduce (fn [res x] 
          (println x) 
          (+ res x)) 
        [1 2 3])

У меня будет нормальный ответ «6», никаких заворачиваний в return, да еще и побочный эффект сработает в виде вывода на stdout значений элементов коллекции. Сможешь привести аналог на хаскеле?

Это конкретно называется Debug.Trace из base.

Т.е. ты написать аналогичный код на хаскеле сам не можешь. Так?

Чем не понятно тело foreach?

Простейший foreach ещё ничего, но просто никто на этом не останавливается - начинаются разные loop с iterate.

Не уходи от темы. Что значит «еще ничего»? Или ты к телу foreach уже претензий не имеешь и отказываешься от своих слов?

Ок. Теперь ты хочешь поговорить про loop и iterate?

http://clojuredocs.org/clojure_core/clojure.core/loop http://clojuredocs.org/clojure_core/clojure.core/iterate

Что в их телах непонятного? Или ты про коммно лисповые? А там что непонятно?

Повторю, раз не въезжаешь. ФП не обязано быть чистым, как в хаскеле, ФП не обязано быть типизированным как в хаскеле. Есть масса нечистых фп языков, в их числе и clojure, которые не используют так понятийный аппарат теории категорий. Теперь понятно, про что был мой ответ?

Так я не отрицаю, что это очень узкий взгляд на ФП, фактически, это ФП + чистота = плюшки + логические ограничения = плюшки + «матан» = плюшки.

Что за плюшки? Ты написал фигню а не равенство. Опиши словами.

persistent data structures

TVar & ко в монаде STM тоже персистентены. То есть данные нужно либо копировать, либо осилить нормальное STM для полностью мутируемых данных.

Ну не позорься так. В clojure когда я добавляю элемент в вектор (conj v :new-elem), то у меня будет уже два вектора: исходный v и новый, реюзающие все елементы, кроме добавленного. Если я изменяю значение у ключа в мапе (assoc m :key10 :new-value), то у меня будет два мапа, реюзающие все пары мапа, кроме пары с ключом :key10. Покажи мне аналог в хаскеле?

Так делать не нужно

Промолчал бы, не заметили, правда? Ты не можешь даже хоть как-то аргументировать свое «не нужно». Если у тебя в языке этого нет, то конечно оно «не нужно».

Ты не врубаешься, это то что реально нужно в функциональном языке. Самое смешное, что это реализовано в каком-то clojure, а не в чисто функциоанальном языке хаскеле. Вот это самое интересное.

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

Ты явно не понимаешь, для чего persistent data structure и как оно работает в clojure. Не позорься, пожалуйста, дальше. Что ты там посмотрел? Ты не понимаешь концепции работы с изменяемыми данными в виде независимых сущностей state, identity и values. Значения никогда, читай еще раз, НИКОГДА не изменяются. Это фундаментальное понимание. Меняется state у identity. Механизм управления таким изменением реализован в языке. Работа с изменяемыми данными в хаскеле как я увидел, просто примитивное громоздкое уродство по сравнению с STM clojure, не говоря, что в clojure, благодаря persistent data structure, возможна эффективная работа с иммутабельными данными.

Когда Хикки говорит, что он хочет понимать под изменением что-то вроде state monad

Грамотой владеешь? Открой мануал по refs, atoms и agents в clojure и посмотри принцип работы и примеры. Потом уже пытайся что-то сказать.

Кстати, то что persistent тормозит относительно transistent это нормально

Что там у тебя тормозит? Не мямли, а напиши конкретно с примерами.

TVar тоже будет тормозить относительно IORef, но с последним проще отстрелить себе ноги.

Ага. По мне, так лучше вообще застрелиться, чем так мучиться.

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

Чем отличается от функции q-lame [elevator passengers floor] которая по условию в if вызывает либо функцию q-lame-overload [elevator passengers floor], либо функцию q-lame-normal [elevator passengers floor]?

К чему пример не важно. Это ответ на твой вопрос

А паттерн матчинг (+ guards) по типам и значениям мог бы дать то что дают кложуровские мультиметоды?

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

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

инстансы монад/функторов - это типы, а вот сами монады и функторы - тайпклассы, а не типы

Вот с точки зрения ТК это просто бред, раз уж мы используем слова «функтор» и «монада». Ещё раз - Классы типов их инстанцирование, как читать?, там же ссылка на «When is an abstract data type a functor?», там же пример про то какого рода функтором является List - это эндофунктор на категории типов и классов эквивалентности функций. Языковая сущность class Functor :: (* -> *) -> Constraint (которая в новых GHCях уже частично интернализирована) это не «функтор» и не «монада» - какими их свойствами она обладает? Она является «proper классом» всех типов вида Pi (F : Type -> Type). Pi (A : Type). Pi (B : Type). (A -> B) -> (F A -> F B) - совсем другая сущность (хотя, возможно что она тоже функтор, но уже в другом смысле - что только не функтор, на самом деле, просто List как функтор это весьма специальный функтор, да и полезный - map для списков и соответствующие теоремы).

List тот же - это в хаскеле никакой не функтор

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

А как?

Не, не кролики - утки :) IO это opaque type который mainable, catchable, используется, собственно, в IO функциях из System.IO и т.п. То есть он и набор примитивных функций с ним должны операционно крякать определённым образом, но это выходит за рамки репорта, да.

То, где они есть - это уже не хаскель, это расширение хаскеля

Это не так важно, в принципе, пусть будет Haskell + STG + ... (у GHC много разных подсистем - общей семантики нигде нет, но отдельные куски разбросаны по пейперам - что-то ищется по operational + semantics + haskell + (stg | lazy i/o | stm)).

которое нарушает обратную совместимость

Как только мы дадим ИО семантику хаскель станет грязным

Не нарушает и чистым пока runIO :: IO a -> a будет оставаться недостижимым в языке, но написать что это такое на данном конкретном вычислителе можно, как и свойства её описать.

На эту тему можно публикации Wouter Swierstra посмотреть - там у него run это, грубо говоря, IO a -> Memory -> a * Memory (для ЪIO можно считать, что какой-то кусок Memory это DMA, например, тогда volatile должно как-то сказаться на свойствах run). При этом язык который пишет IO a может быть не в состоянии сделать себе IO a -> a.

Лисп на чистоту и не претендует.

Я не могу говорить за Haskell который обычно и представляют как «pure functional lazy language», но лично для меня Haskell/GHC как инструмент это язык который не претендует на чистоту - он претендует на более-менее строгое выделение нечистоты в отдельный слой монадического стека.

Типы - такая же история.

Вне ЯП типы это всё ещё современность (от Рассела и до Аводея с Воеводским).

Да и в ЯП тоже.

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

Если это волшебные макросы которые могут обеспечить всё что может обеспечить хороший компилятор, причём без code walkera - то есть удобный дебаг, сообщения по существу, связывание с синтаксическими единицами произвольной мета-информации, её распространение, проверку типов уровня унификации Милнера, прочие статические проверки, тогда вопрос только в том почему пока что люди просто пишут одни языки на других языках (и сами языки на самих себе), а не используют общую «мета-систему без тормозов» в которой можно реализовывать «тормоза» как синтаксические расширения. Пока что такая «мета-система» это не какой-то язык, а просто, хм, реальность с набором несвязных инструментов.

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

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

А можно узнать как ее на АДТ можно решить, без макросов?

Это как раз пример когда нужно что-то вроде макросов - во-первых, нужно узнать у языка про то как устроен ADT (с помощью рефлексии), во-вторых - сгенерировать на основе этой информации какой-то код. Без первого и второго вообще ничего кроме внешнего DSL не получится (типа protobuf), с первым ещё можно нагенерировать текста, но это компиляция в два явных прохода. Со вторым, то есть со staged компилятором + рефлексия такое получается проще всего. Где-то в CL это будет MOP + макросы, в хаскеле - SYB + TH, в скале - рефлеския + макросы.

Почему не будем?

Потому что SYB это стандартная фича GHC - можно писать deriving для Typeable, Data, Generic. А вот более специфичные вещи - свои TH функции, при этом информацию об ADT можно узнавать с помощью той же рефлексии SYB.

Достаточно было бы написать реализацию соответствующих тайпклассов (сверкти, сереализации етк.) для примитивных типов и для соответствующих комбинаторов.

Кодировать data суммами и произведениями не очень-то удобно, разве что сделать их подтипами таких сумм произведений, но это можно делать явно с помощью Generic:

Prelude> :m + GHC.Generics
Prelude GHC.Generics> data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Generic
Prelude GHC.Generics> let x = from (undefined :: Tree Int)
Prelude GHC.Generics> :t x
x :: D1
       D1Tree
       (C1 C1_0Tree (S1 NoSelector (Rec0 Int))
        :+: C1
              C1_1Tree
              (S1 NoSelector (Rec0 (Tree Int))
               :*: S1 NoSelector (Rec0 (Tree Int))))
       x

есть пакеты которые пишут свёртки и т.п. для такого представления, так что и для всех Generics, но я их не использовал, так что не знаю насколько это удобно.

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

Что да?

Вот давай не будем играть в русский язык, ок? Обычное «да», мол, «да, желание порассуждать, ты прав» (потому что макросы же).

Накуа self нужен не в ОО языке?

А зачем ты задаёшь такой вопрос? Я говорил про Self в C++ и макросы там же. Откуда взялся «не ОО язык»?

Про то зачем ещё может быть нужен self можешь посмотреть в скале (DI, cake pattern).

Т.е. ты написал бред про «джавакодера» и когда я тебе ответил, решил подменить начальную свою мысль.

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

doseq является реализацией foreach в clojure

Как минимум там есть ещё параллельная итерация.

Как у тебя x и y, являясь двумя раздельными формальными параметрами лямбды инициализируются от конкретной пары?

В смысле? map (\(x, y) -> x + y) [(1, 2), (3, 4)] == [3,7].

И везде у тебя идет вложенные forM_ «forM_...$forM_»

Нет, у меня было

doseq [(1, "a"),          -- первая пара
       (2, "b"),          -- вторая
       (3, "c")] $        -- третья
  \(x, y) -> do           -- для каждой пары x - первый элемент, y - второй
    printf "%d, %s\n" x y -- используем их в do-блоке

doseq ([1, 2],            -- первый список
       ["a", "b"]) $      -- второй
  \x y -> do              -- на каждой итерации x - элемент первого списка
                          --                    y - соотвествующий второго
                          -- и опять используем
    putStrLn $ show x ++ ", " ++ y

А если переменных foreach-а больше 2-х?

Добавить ещё инстансов DoSeq.

Ты же пишешь «аналогии»

Ну да, тут разница между ФВП и foreach всё равно еле различима, в этом было исходное замечание.

Тогда какого лешего ты «очень ограниченные» «почти макросы» сравниваешь с полноценными макросами?

Не было такого - у меня было три пункта про виды макросов, и примером к третьему (генерация top-lelvels, aka бойлерплейт) были «формы deriving в хаскеле», что тебе не понравилось (оно «не то»).

Правильно, приходится жрать, что дают создатели языка, в отличии от.

Именно. Если на чаши весов бросить много «плюшек» с одной стороны и «макросы», «лисп» и «гомоиконичность» с другой, то плюшки перевешивают. Кстати, даже в CL они перевешивают.

Я предлагаю, тебе в теме про лисп не заикаться про хаскель

Тема про релиз Scala.

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

То есть ты хочешь чтобы можно было сделать IO a -> a или вообще обойтись без IO (то есть не следит за ссылочной прозрачностью)?

Т.е. ты написать аналогичный код на хаскеле сам не можешь. Так?

Опять ты просишь меня писать факториалы, из документации должно быть понятно

foldl' (\res x -> traceShow x (res + x)) 0 [1, 2, 3]

но это хак, если хочется IO - нужно брать IO. Это располагает к тому чтобы сразу отделить чистые функции от кода с эффектами.

Или ты к телу foreach уже претензий не имеешь

Претензии в том, что пишется макрос там где хватило бы функций/методов. Передача функции это всегда внятно, передача sexpa макросу - в меньшей степени, семантика больше не является стандартной, она зависит от реализации макроса.

Или ты про коммно лисповые? А там что непонятно?

Да. Они ещё в меньшей степени очевидны, это уже полностью DSL с которым нужно разбираться.

Ты написал фигню а не равенство.

ФП + чистота (equational reasoning) + логические ограничения (proof carrying) + использование понятий из абстрактных областей математики (ТК, алгебра, теория типов). Что не понятно?

Что там у тебя тормозит?

Я ссылку на transistent приводил - http://clojure.org/transients

Возможно я что-то делаю не так, но возьмём инициализацию большого персистентного массива:

user=> (defn vrange [n]
  (loop [i 0 v []]
    (if (< i n)
      (recur (inc i) (conj v i))
      v)))
#'user/vrange
user=> (time (def v2 (vrange 3000000)))
"Elapsed time: 2111.040958 msecs"
#'user/v2
user=> (time (def v2 (vrange 3000000)))
"Elapsed time: 3333.515217 msecs"
#'user/v2
user=> (time (def v2 (vrange 3000000)))
"Elapsed time: 2308.884348 msecs"
#'user/v2
user=> (time (def v2 (vrange 3000000)))
"Elapsed time: 2951.917638 msecs"

это в REPL.

Теперь сделаем то же в хаскельном STM - самым тупым образом, то есть с atomically на каждый чих (чтобы было аналогично вызовам conj):

import Control.Applicative
import Control.Monad

import Data.Array.IO
import Control.Concurrent.STM

import System.Environment

-- * Интерфейс полегче.

type MyArr = TVar (IOUArray Int Int)

myArr :: Int -> IO MyArr
myArr n = newArray_ (0, n - 1) >>= newTVarIO

(?) :: MyArr -> Int -> IO Int
arrRef ? i = readTVarIO arrRef >>= flip readArray i

(!) :: MyArr -> Int -> Int -> IO ()
(arrRef ! i) x = readTVarIO arrRef >>= \arr -> writeArray arr i x

-- * Тест.

main :: IO ()
main = do
  n <- read . head <$> getArgs
  arr <- myArr n
  let loop i = when (i < n) $ (arr ! i) i >> loop (i + 1)
  loop 0
  forM_ [0 .. n `div` 1000] $ (?) arr >=> print

{-

  Получается

$ ghc -O2 stm.hs
$ \time ./stm 3000000
...
0.06user 0.02system 0:00.10elapsed 85%CPU (0avgtext+0avgdata 25608maxresident)k
0inputs+0outputs (0major+6456minor)pagefaults 0swaps
$ time ./stm 3000000
...
./stm 3000000  0,06s user 0,03s system 87% cpu 0,108 total
$ echo $((2000 / (1000 * 0.06))) 
33.333333333333336

-}

Значения никогда, читай еще раз, НИКОГДА не изменяются. Это фундаментальное понимание. Меняется state у identity. Механизм управления таким изменением реализован в языке.

Про values - верно. «state у identity» - в наивном представлении это просто ссылка на объект, STM предполагает, что с этой ссылкой можно работать с помощью атомарных комбинируемых операций.

Пока что я не понимаю зачем нужно в STM делать versioning данных, то есть почему её нельзя сделать просто как продвинутый способ работы с расшаренными данными который 1) даёт возможность не писать ручных локов, 2) исключает возможность дедлоков 3) помимо простых ссылок реализует ещё какой-то набор «персистентных» контейнеров - каналы, очереди т.п.

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

Получается

Немного не так - так работают обычные массивы в TVar (массивы вне TVar - ещё лучше). То есть это на тему transistent. Чтобы сделать настоящий аналог conj и persistent нужно

import GHC.Conc.Sync

(!) :: MyArr -> Int -> Int -> IO ()
(arrRef ! i) x = atomically $ readTVar arrRef >>= \arr -> unsafeIOToSTM $ writeArray arr i x

тогда будет

$ time ./stm 3000000
...
./stm 3000000  0,23s user 0,03s system 95% cpu 0,279 total
$ \time ./stm 3000000
...
0.23user 0.03system 0:00.32elapsed 81%CPU (0avgtext+0avgdata 25616maxresident)k
0inputs+0outputs (0major+6459minor)pagefaults 0swaps
$ echo $((2000 / (1000 * 0.23)))  
8.695652173913043
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Вот с точки зрения ТК это просто бред

Естественно. Любые утверждения внутри хаскеля с точки зрения ТК - это бред. Т.к. хаскель не имеет онтошения к ТК, в нем все фундаментально сломано и не может быть починено. Хаскель чересчур «грязен» в этом смысле, слишком далек он теоретико-категорных концепций.

там же пример про то какого рода функтором является List - это эндофунктор на категории типов и классов эквивалентности функций.

Проблема в том, что List - это _не_ функтор. И уж потому не эндофунктор :)

Мы его просто называем функтором, потому что это удобно, но реально теоретико-категорным функтором он не являетсЯя т.к. не соответствует определению функтора. Он функтор в том же смысле, в каком множеством является множество всех множеств. Ну то есть в некоторой «наивной» версии теорката, исключительно которая и используется в околохаскельных рассуждениях.

Это не интересно - до определённых границ это функтор.

Он ни в каких границах не функтор :)

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

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

но это выходит за рамки репорта, да.

О чем и речь. В рамках хаскеля само понятия «кряканья» функции не является осмысленным. В хаскеле ф-и не обладают поведением, а значит и специфицировать его нельзя. Потому что нельзя специфицировать невыразимую в рамках теории сущность.

Это не так важно, в принципе, пусть будет Haskell + STG

Это не будет хаскель + что-либо. Потому что как только мы добавим семантику IO оно перестает быть хаскелем (противоречит семантике хаскеля).

Не нарушает и чистым пока runIO :: IO a -> a будет оставаться недостижимым в языке, но написать что это такое на данном конкретном вычислителе можно, как и свойства её описать.

Это не важно. Важно что хаскель не может существовать когда существует семантика у IO. Они взаимопротиворечивы. Либо - кино, либо - мороженое.

но лично для меня Haskell/GHC как инструмент это язык который не претендует на чистоту - он претендует на более-менее строгое выделение нечистоты в отдельный слой монадического стека.

Это и есть чистота. По крайней мере всюду выше я говорил именно о такой чистоте.

Вне ЯП типы это всё ещё современность (от Рассела и до Аводея с Воеводским).

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

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

Как раз потому, что макросы, в отличии от систем типов, это _актуальное_ направление в исследованиях. Как только начнут писать - оно актуальным уже не будет :)

Пока что мы видим, что практика к этой точке монотонно стремится. То есть описанная ситуация - это предел текущих трендов развития, и мы к ней, рано или поздно, но придем. Это на данный момент не вызывает ни малейшего сомнения.

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

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

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

Это как раз пример когда нужно что-то вроде макросов

То етсь как минимум один юзкейс макросов мы нашли.

Кодировать data суммами и произведениями не очень-то

Погоди, data и так кодируются суммами и произведениями. Более того - никто не знает, как их можно кодировать по-другому. Так что неясно о чем ты.

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

Да. Они ещё в меньшей степени очевидны, это уже полностью DSL с которым нужно разбираться.

Ты говоришь так, как будто с полноценной библиотекой для итерирования разбираться надо меньше, чем с аналогичным DSL. практика показывает, что наоборот - больше.

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

Претензии в том, что пишется макрос там где хватило бы функций/методов.

Зададим вопрос по-другому. Зачем использовать функцию/метод, если можно поступить проще и написать макрос?

Передача функции это всегда внятно, передача sexpa макросу - в меньшей степени

Но ведь это неправда.

семантика больше не является стандартной, она зависит от реализации макроса.

Семантика ф-и, в которую ты что-то передал, тоже не является стандартной, она зависит от реализации функции.

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

Естественно

Тут нужно разобраться откуда растут ноги у терминологии.

AlgDT определённого вида это функторы. List как ADT - функтор. Если в хаскеле [] :: * -> * это, скажем, не настоящий «fuzzy functor» - всё равно какие-то основания считать хаскельные данные хорошими ADT и, соответственно, функторами есть, даже если это карточный домик.

А вот класс типов «Functor» хоть и проговаривается как «функтор» - функтором не является уже ни в каком смысле.

То есть. Некоторые хорошие ADT - функторы, ломаемые ADT - не функторы, но можно продолжать называть их функторами и полагать, что при определённых условиях (никто не начнёт делать seq, исключений, зависающих программ, unsafe* и т.д. и т.п.) функторные законы будут выполняться. То что называется Functor это класс типов и уже не функтор даже отдалённо. В этом смысле лучшими названиями для классов типов бы были IsFunctor, IsMonad, IsMonoid и т.п.

Проблема в том, что List - это _не_ функтор.

Он ни в каких границах не функтор

Тогда вопрос. Там по ссылке есть код на агде где доказывается что Data.List.List это EndoFunctor на Agdask. Этот List из агды - функтор?

Вот акт веры в то что на хаскеле можно писать правильные ADT (благо, будет очень похоже на агду) ничем не отличается от акта веры в то что можно писать строгие и тотальные алгоритмы на любом ЯП.

Они взаимопротиворечивы

Можно дать объяснение почему?

Теории типов

Теория типов понимается как теория типов?

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

В исследовании чего? А то homotopy type theory и univalent foundations тоже можно считать исследованиями связанными с теорией типов.

Как раз потому, что макросы, в отличии от систем типов, это _актуальное_ направление в исследованиях.

Какие-нибудь ссылки?

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

Кто-то озвучивал эту позицию? Я видел видео про использование cake pattern в компиляторе, но про макросы ничего такого именно по части scalac не слышал.

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

Погоди, data и так кодируются суммами и произведениями. Более того - никто не знает, как их можно кодировать по-другому. Так что неясно о чем ты.

GADTs и зависимые записи - не кодируются. А так я про «пейсать программы» - data как variantы tuplов это неудобно.

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

семантика больше не является стандартной, она зависит от реализации макроса.

Семантика ф-и, в которую ты что-то передал, тоже не является стандартной, она зависит от реализации функции.

Моё слово «семантика» более конкретно в данном случае, это про «чёрточки» - в лямбда исчислении, например, нужно знать про аппликации и абстракции, и всё. А макросы могут добавлять произвольные семантические правила («чёрточки») в общую картину.

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

AlgDT определённого вида это функторы. List как ADT - функтор.

Конечно же, нет. Откуда вообще пошло это заблуждение?

То есть. Некоторые хорошие ADT - функторы

Да нет. АДТ - не функторы.

Тогда вопрос. Там по ссылке есть код на агде где доказывается что Data.List.List это EndoFunctor на Agdask. Этот List из агды - функтор?

Нет, конечно же. Отображение на типах не может быть функтором, никак.

Можно дать объяснение почему?

Не знаю. По построению, видимо.

В исследовании чего?

СS-related, конечно же.

Какие-нибудь ссылки?

На что?

Кто-то озвучивал эту позицию?

Это же, по-моему, была основная причина по которой макросы решили-таки в скалу впилить. Сейчас-то они, естественно, не используются, т.к. их только впилили.

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

GADTs и зависимые записи - не кодируются.

При чем тут GADT, если речь шла про ADT? ADT - это по определению то и только то, что кодируется суммами и произведениями. Тем более что такое GADT вне контекста хаскеля вообще неясно.

А так я про «пейсать программы» - data как variantы tuplов это неудобно.

А какие есть альтернативы? Везде только как варианты туплов же.

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

Моё слово «семантика» более конкретно в данном случае, это про «чёрточки» - в лямбда исчислении, например, нужно знать про аппликации и абстракции, и всё. А макросы могут добавлять произвольные семантические правила («чёрточки») в общую картину.

Давай будем тогда более последовательны - определение функции это _и есть_ введение нового семантического правила. На этом факте просто никто не делает акцент, потому что нам совершенно очевидно, что определять функции надо уметь и без этого никак. И это такая мелочь, что всем пофиг. Но вот в случае макрос этот факт (то, что введению любой именованной сущности добавляет в семантику правило) вдруг вытаскивают и начинают с ним носиться как с корзиной полной яиц. Хотя на деле ничего не изменилось и применение именованной функции семантически не сложнее применения макроса.

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

Что да?

Вот давай не будем играть в русский язык, ок?

Мне приходится так отвечать из-за твоей манеры отвечать невпопад.

Накуа self нужен не в ОО языке?

А зачем ты задаёшь такой вопрос? Я говорил про Self в C++ и макросы там же. Откуда взялся «не ОО язык»?

Оттуда, что я говорил про лисп, а ты про хаскель. С++ с его говромакросами я сразу тебе сказал не приводить.

Т.е. ты написал бред про «джавакодера» и когда я тебе ответил, решил подменить начальную свою мысль.

Нет, про джавакодера всё в силе - я говорю что он использует своё куцее ОО как средство декомпозиции,

Хорошо.

ты пишешь в пример код который этому не противоречит - вот со скальной (не куцей ОО / ФП) библиотекой коллекций такой код тоже прекрасно пишется.

Принципиально можно написать. Но дьявол в мелочах (с) не мое. Что доказывают твои примеры и ссылки в сравнении с моими.

doseq является реализацией foreach в clojure

Как минимум там есть ещё параллельная итерация.

«Как минимум» это для красного словца? Давай уже попунктно, что там не foreach. И что такое «параллельная итерация»?

Как у тебя x и y, являясь двумя раздельными формальными параметрами лямбды инициализируются от конкретной пары?

В смысле? map (\(x, y) -> x + y) [(1, 2), (3, 4)] == [3,7].

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

И везде у тебя идет вложенные forM_ «forM_...$forM_»

Нет, у меня было...

Вот твой код

forM_ [(1 :: Int, "a"), (2, "b"), (3, "c")] $ \(x, y) -> printf "%d, %s\n" x y
forM_ [1, 2] $ \x -> forM_ ["a", "b"] $ \y -> putStrLn $ show x ++ ", " ++ y
for2M_ :: Monad m => [a] -> [b] -> (a -> b -> m ()) -> m ()
for2M_ xs ys f = forM_ xs $ forM_ ys . f
for2M_ [1, 2] ["a", "b"] $ \x y -> putStrLn $ show x ++ ", " ++ y
instance (Monad m) => DoSeq ([a], [b]) ((a -> b -> m ()) -> m ()) where
  doseq (xs, ys) f = forM_ xs $ forM_ ys . f
Т.е. у тебя везде вложенные forM_ «forM_...$forM_»

Ты же пишешь «аналогии»

Ну да, тут разница между ФВП и foreach всё равно еле различима, в этом было исходное замечание.

Странное сравнение «ФВП и foreach». Ты имел в виде «реализация логики foreach с помощью чисто ФВП»?

Кстати. У тебя не получилось чисто ФВП все сделать. Ты еще приплел сюда монады и получил в конечном итоге не функции. Так что уже это пипец какой-то. А убогость своей аналогии ты в упор не видишь: то тебе тело foreach странное, то ты не понимаешь абстракции, введенной foreach-ем, то у тебя быдлокод с вложенными forM_ не быдлокод, то у тебя вообще аллергия на макросы. Короче, все с тобой ясно, деятель.

Тогда какого лешего ты «очень ограниченные» «почти макросы» сравниваешь с полноценными макросами?

Не было такого

Если не сравниваешь, то нафиг вообще это приплетать в тред?

были «формы deriving в хаскеле», что тебе не понравилось (оно «не то»).

Ну дык, это действительно не то.

Правильно, приходится жрать, что дают создатели языка, в отличии от.

Именно. Если на чаши весов бросить много «плюшек» с одной стороны и «макросы», «лисп» и «гомоиконичность» с другой, то плюшки перевешивают.

Потому что ты это сказал, да? Пойми, если язык мощьный, как лисп, то ты можешь сам расширять его до нужного тебе уровня, вводить какие угодно свои плюшки. А не ждать, пока боги соизволят что-то там добавить. Вот ты и используешь такие встроенные плюшки, что у тебя получается такой уродский громадный код, который ты не можешь уменьшить. В лиспе ты язык затачиваешь под задачу, чтобы решение на полученном языке было простым и понятным. Готовые плюшки это хорошо, а лучше самому создавать такие плюшки. Учись летать, а не бегать на подпорках, готовых плюшках и костылях.

Кстати, даже в CL они перевешивают.

Например, не нравится loop, не пользуйся. В чем проблема?

Я предлагаю, тебе в теме про лисп не заикаться про хаскель

Тема про релиз Scala.

Тема бранча была связана с лиспом, а не со скалой. Это ты влез с офтопиком в тред.

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

То есть ты хочешь чтобы можно было сделать IO a -> a или вообще обойтись без IO (то есть не следит за ссылочной прозрачностью)?

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

Т.е. ты написать аналогичный код на хаскеле сам не можешь. Так?

(reduce (fn [res x] 
          (println x) 
          (+ res x)) 
        [1 2 3])

Опять ты просишь меня писать факториалы, из документации должно быть понятно

foldl' (\res x -> traceShow x (res + x)) 0 [1, 2, 3]

Хосспади, какое убожество. А если я еще пишу не только в stdout, но еще и в лог, да еще и изменяю внешнее ко скопу состояние

(reduce (fn [res x] 
          (println x)
          (logger/debug "x = " x)
          (swap! col conj x)
          (+ res x)) 
        [1 2 3])

Ты это уже не осилишь?

Или ты к телу foreach уже претензий не имеешь

Претензии в том, что пишется макрос там где хватило бы функций/методов.

Не спрыгивай. Вот что ты писал

Передавать функцию, лямбду или блок которые полноценные (проверенные, я бы сказал) выражения (expressions) всяко лучше чем передавать непонятный «кусок программы»

Значит, мы выяснили, что ты просто так в лужу пузырьки про непонятное тело foreach-а булькнул. А теперь перевел, мол говоришь про «пишется макрос там где хватило бы функций/методов. ». Молодца.

Возможно я что-то делаю не так, но возьмём инициализацию большого персистентного массива:
... «Elapsed time: 3333.515217 msecs»

Странно, но на моей машине на работе время выполнения около 400 msecs. Завязывай так привирать про тормознутость. Я тебе скажу больше, при работе с большими объемами данных надо работать или лениво, или на низком уровне, например, напрямую с джава объектами типа array.

Теперь сделаем то же в хаскельном STM - самым тупым образом, то есть с atomically на каждый чих (чтобы было аналогично вызовам conj):

И что ты доказал? Что на хаскеле выполнилось быстрее? Я бы даже на нем не писал сложную работу с большими данными. Например,

(defn arr-range [n]
  (let [#^longs arr (make-array Long/TYPE n)]
    (dotimes [i n]
      (aset #^longs arr i i))
    arr))

(time (def a (arr-range 3000000)))
"Elapsed time: 2.777 msecs"

Если написать на чистой джаве, то еще быстрее. А вызвать вычисление джава класса и получить результат из clojure легко.

Значения никогда, читай еще раз, НИКОГДА не изменяются. Это фундаментальное понимание. Меняется state у identity. Механизм управления таким изменением реализован в языке.

Про values - верно. «state у identity» - в наивном представлении это просто ссылка на объект,

Посмотри реализацию ref-ов и какое у них «наивное» представление, наивный.

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

Не надо мне это писать, или ты для себя конспектируешь?

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

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

Нет, не произойдет. Просто у него не ф-я 2 формалаьных параметров, \(x, y) - это функция принимающая двуместный тапл. И там список таплов на вход этому форичу идет.

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

Конечно же, нет.

http://en.wikipedia.org/wiki/Initial_algebra. List как тип (конструктор типа) это эндофунктор на Type, то есть List : Type -> Type с сигнатурой 1 + A * _, сам ADT получается отсюда уникально как начальная алгебра для данного эндофунктора.

АДТ - не функторы.

Ещё - открываем «Basic Category Theory for Computer Scientists» и ищем в индексе functor -> List.

Update: и ещё - http://ncatlab.org/nlab/show/initial algebra of an endofunctor.

Нет, конечно же. Отображение на типах не может быть функтором, никак.

Нет, конечно. Вот же перед глазами весь код начиная с категорий и далее до функторов, эндофункторов, категории Type, эндофункторов на ней и доказательства что List это такой эндофунктор. Функторные законы доказаны тоже, прошу заметить (экстенсионально, правда).

Не знаю. По построению, видимо.

Ага, а вопрос был «почему» слитно. Ну ладно.

На что?

«макросы, в отличии от систем типов, это _актуальное_ направление в исследованиях» - на эти самые актуальные исследования.

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

Тем более что такое GADT вне контекста хаскеля вообще неясно.

Это частный случай индуктивных типов.

А какие есть альтернативы?

Речь была про что - что в хаскеле data не сделаны как :* и :+. Это денотационно оно изоморфно, а в нотации удобнее работать именно с data. Ну типа как кодировать все структуры данных s-выражениями это не удобно.

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

И что такое «параллельная итерация»?

Это я перепутал - наоборот последовательная, как в твоём втором примере с doseq, но параллельная, когда «параллельно» осуществляется проход по нескольким коллекциям, тоже бывает нужна (в хаскеле называется zipWith).

Вот твой код

Это всё разные варианты. Нужно взять что-то одно - например класс DoSeq и его инстансы. Как выглядят эти инстансы - не интересно, понятно что последовательный doseq для нескольких коллекций будет работать как вложенные циклы - и в clojure (в реализации doseq), и в haskell (там где у меня forM_ от forM_). Интересен интерфейс в виде функции doseq и её примеров использования - выше два таких примера, на них и нужно смотреть.

Ты имел в виде «реализация логики foreach с помощью чисто ФВП»?

Ну да, foreach это обычная ФВП. В скальной библиотеке коллекций она так и называется.

Ты еще приплел сюда монады и получил в конечном итоге не функции.

То что forM_ и прочие используют монадический интерфейс никак не делает их «не функциями» - они тоже обычные функции.

Я там, разве что, приплёл класс типов с зависимостью для перегрузки функции doseq.

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

Там один параметр как 2-tuple, работает за счёт того, что в параметрах лямбды можно делать паттерн-матчинг по переданных значениям, поэтому иногда удобнее вместо лямбды передавать локальную функцию из let/where написанную с pattern matchingом.

Ты это уже не осилишь?

Пусть будет

foldM (
  \res x -> do
    print ...
    log ...
    set something ...
    etc ...
    return (res + x)
  ) 0 [1, 2, 3]

foldM != fold* - можно их обобщить, но это не особо нужно.

Хосспади, какое убожество.

Это ещё что, вот если ещё log доставать из reader и писать в ReaderT IO.

непонятное тело foreach-а

Ну там же free variable в body - wtf?

Странно, но на моей машине

Нужно тестировать оба варианта (clojure и ghc -O2) и делить.

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

List как тип (конструктор типа) это эндофунктор на Type

Это не эндофунктор. Более того - это не функтор. Объяснить, почему не функтор - задание тебе на дом. Подсказка: для этого достаточно прочитать определение функтора.

Ещё - открываем «Basic Category Theory for Computer Scientists» и ищем в индексе functor -> List.

Еще раз - открываем определение функтора (обычного функтора в теоркате) и смотрим, почему АДТ - не функтор.

Нет, конечно. Вот же перед глазами весь код начиная с категорий и далее до функторов, эндофункторов, категории Type, эндофункторов на ней и доказательства что List это такой эндофунктор. Функторные законы доказаны тоже, прошу заметить (экстенсионально, правда).

Зачем код, я не понимаю? Вот перед тобой есть определение функтора, и есть некий объект (АДТ), который не удовлетворяет этому определению. При чем очевидным образом не удовлетворяет - то есть еще до начала проверки функториальных законов.

Ага, а вопрос был «почему» слитно. Ну ладно.

Потому что семантика хаскеля так определен. Этот ответ больше устроит?

«макросы, в отличии от систем типов, это _актуальное_ направление в исследованиях» - на эти самые актуальные исследования.

Тебя забанили в гугле?

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

Это частный случай индуктивных типов.

Ну допустим. Стандартный пример из GADT (с типизацией простенького интерпретатора) можно записать в нотации индуктивных типов?

Речь была про что - что в хаскеле data не сделаны как :* и :+.

А как же они сделали? В смысле да, там вместо значков + и * другие значки. Но это ничего не меняет, потому что значки всегда можно поменять.

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