1. Haskell / Говнокод #9598

    −92

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    -- | The unit datatype @()@ has one non-undefined member, the nullary
    -- constructor @()@.
    data () = () deriving Generic
    
    data (,) a b = (,) a b
    . . .
    data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
     = (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
        -- deriving Generic
    {- Manuel says: Including one more declaration gives a segmentation fault.
    . . .

    *тяжелый вздох*

    http://www.haskell.org/ghc/docs/latest/html/libraries/ghc-prim-0.2.0.0/src/GHC-Tuple.html#%28%29

    Запостил: wvxvw, 03 Марта 2012

    Комментарии (64) RSS

    • Кстати, после того как запостил, в течение 1 минуты Firefox вывалился с segfault'ом :)
      Ответить
      • А как бы вы написали?
        Ответить
        • Я бы просто не хотел оказаться в ситуации, когда мне это нужно было писать :)
          Ответить
          • Если не базовая библиотека, то все равно смысла окостыливать выше 7 нет (zip/unzip из Data.List, в 7.0/7.2). Если очень хочется, можно хак в виде template haskell использовать.

            По идее, теоретически можно было сделать (a,b,...) сахаром для Tuple <нумерал-черча> a b ...
            Ответить
            • ХЗ, я только начинаю разбираться с языком. В приницпе, много интересных вещей, но синтаксис и "условности" иногда просто такие, что и в горячечном бреду не представится.
              Я это говорю к тому, что зачем эти типы вообще нужны? Почему нельзя было сделать как-то так, чтобы кортежи создавались по факту их создания, или какой-нибудь общий тип "Tuple #" где вместо # подставляется число. Очевидно же, что такой подход ни к чему хорошему не приведет.
              Ответить

              • >но синтаксис и "условности"
                >синтаксис

                А что не так в синтксисе?
                Ответить
                • Синтаксис. Вот, старожилы не дадут соврать - я обычно не выражаюсь, но если без формальностей, на простом Русском языке, то это называется "уебищный". Такое впечатление, что названия выбирались последовательными подбрасываниями кубика. Проследить какую-то логику в названиях функций - вообще нет никакой возможности. За каким-то лешим форматирование кода влияет на интерпритацию, и при этом у пробельных элементов в зависимости от контекста могут быть множество разных, вообще никак нe связанных значений. Это может быть конец выражения, может быть применение фунцкии, может быть параметризированый тип, может быть комбинация конструкторов, ну или просто разделитель между другими синтаксическими частями.
                  Та же история с |, та же история с (), та же история с запятыми. Глядя на небольшой фрагмент программы вообще нельзя с уверенностью сказать, что там написано.
                  Есть много конструкций которые абсолютно ничего не добавляя дублируют одна другую - зачем, не понятно. Например, do вместо >>= - нет абсолютно никакого смысла в существовании do. let и where.
                  Зачем нужен "альтернативный синтаксис" с фигурными скобками?
                  Зачем нужна возможность писать инфиксные операторы как префиксные?
                  Куча ключевых слов неопределенного назначения.
                  Куча разных разновидностей нуллов... но это уже к синтаксису не относится.
                  Ответить
                  • > Проследить какую-то логику в названиях функций - вообще нет никакой возможности.
                    Иногда хромает: можно перепутать объект с субъектом, но ф-ии разнесены по модулям, и пусть не всегда, но прослеживается общая линия. Все же ситуация намного лучше, чем в случае того же Лиспа. И да, это еще не синтаксис.

                    > Та же история с |, та же история с (), та же история с запятыми.
                    Не очень понятно, из проблем с синтаксисом припоминяется лишь недостаточно гибкое обращение к структурам. Немного запутанный let (в do он свой) и так по мелочи.

                    > do вместо >>= - нет абсолютно никакого смысла в существовании do
                    Это не вместо, do - сахарок для >>=. Если много "императивного", то через bind сложно.

                    > let и where
                    Немного разная семантика let - отдельное выражение, where - можно сказать часть "case" (например он виден во всех альтернативах в guard-e). В зависимости от того, насколько ф-ия привязана к контексту, выгоднее let, where или top-level declaration.

                    > Зачем нужен "альтернативный синтаксис" с фигурными скобками?
                    Обычный синтаксис - сахар для фигурного. Фигурный более надежен, есть же генерация входа (тот же template haskell).

                    > Зачем нужна возможность писать инфиксные операторы как префиксные?
                    Top-level functions хотя бы: как иначе передать в map / filter.

                    > Куча ключевых слов неопределенного назначения.
                    Слов порядка 20, что меньше Python и C, не говоря уж о крестах (... и Perl :)

                    > Куча разных разновидностей нуллов...
                    Не очень понял? Один же: ().

                    // ps... Большинсво вопросов по синтаксису снялось бы прочтением пары глав из haskell2010 report (там не так много читать: помимо всего в репорт включили стандарные либы и прочий блекджек).
                    Ответить
                    • Та не... putStr / getLine - за каким нужно было экономить 3 символа? Почему не getLn тогда? Почему-то же putStrLn - тут Line нужно было соркатить до Ln, а в getLine - нет? В этом нет логики, просто первое, что пришло в голову - так и назвали.

                      Цитирую документацию:
                      The "pipe" is used in several places
                      
                          * Data type definitions, "or" 
                      
                      data Maybe a = Just a | Nothing
                      
                          * List comprehensions, "where" 
                      
                      squares = [a*a | a <- [1..]]
                      
                          * Guards, "when" 
                      
                      safeTail x | null x    = []
                                 | otherwise = tail x
                      
                          * Functional dependencies, "where"

                      Вот нафига так делать? По сравнению, Перл выглядит прям образцом читабельности.
                      Вы вообще не поняли в чем проблема - я не знаю, что такое гибкость / о чем вы вообще говорите. Есть проблема зависимости значения символов от контекста, в котором они употребляются. Это даже не столько проблема в программировании, сколько в лингвистике. Не знаю, как по-русски называется, по-английски - garden path. Типичный пример: flies like banana. Можно интерпретировать как "летает как банан", а можно "мухи любят бананы".

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

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

                      Я насчитал как минимум 4: (), [], False, undefined - возможно какие-то мне еще просто не попадались пока.
                      Ответить
                      • > Та не... putStr / getLine - за каким нужно было экономить 3 символа? Почему не getLn тогда? Почему-то же putStrLn
                        Аналогия не совсем прямая, хотя лично я бы не отказался от putLine заместо putStrLn. Но это частный случай, в целом лучше.

                        > Цитирую документацию:
                        Так много где, одно дело лексики, другое синтаксиса. Для вас "." не проблема случайно (это ведь и разделитель в дробных и композиция), или "-", как и разность, так и negate?

                        > Вот нафига так делать? По сравнению, Перл выглядит прям образцом читабельности.
                        Вы вообще не поняли в чем проблема - я не знаю, что такое гибкость / о чем вы вообще говорите.
                        ЧСВ таки мешает осилить смысл фраз? (*)

                        > Есть проблема зависимости значения символов от контекста, в котором они употребляются.
                        Лексику с синтаксисом мешать не надо, пожалуйста. Подобное есть почти везде.

                        > Хаскелл, наоборот - логика в синтаксисе отсутсвует. И понимание программы сводится к угадыванию.
                        Смотря как писать, возможность создания операторов легко может привести к APL-like коду. Но ваш аргумент явно субъективен, мне, например, проще парсить хаскель.

                        > Вы не правильно поняли, эти вопросы риторические, т.как на них нелзя вразумительно ответить.
                        Очень по существу, могу лишь сослаться на (*).

                        > Просто тот, кро придумал эти правила не подумал / имел плохое представление о лингвистике / плохо спланировал.
                        Вроде к синтаксису прикладывали руку специалисти по денотационной семантике.

                        > Я насчитал как минимум 4: (), [], False, undefined
                        Что за бред? undefined - вообще не в тему, это как заглушка. Как вы определили, что []/False - NULL?
                        Ответить
                        • То, что - используется в друх разных контекстах - да, проблема, точно такая же, как и описаная выше. Естественно, что чем больше в языке таких проблем, тем он хуже. В Лиспе точка используется для создания "неправильных" списков и для чисел с плавающей запятой. Для дробных не исползьзуется, если под дробными подразумевались рациональные. И да, конечно, это недостаток. Лучше бы не использовалась. Более того, если вы спросите практически любого "лиспера", то вам скажут, что неправильные списки лучше избегать, и что это недостаток. Ну, или он будет вроде вас, с пеной у рта доказывать "что все ок".

                          Я не говорю про возможности - это уже ответственность того, кто создает. Можно спорить о том, что некоторые языки что-то на уровне синтаксиса запрещают и т.п. Но смысл то в том, что куча абсурдных вещей уже создана и существует в стандартных библиотеках.
                          А вы прям так сразу, как аргументы заканчиваются на личности переходите? Чем одна пустая группа "∅" от другой пустой гуппы "∅" отличается? Кантор бы заплакал глядя на такое :)
                          Ответить
                          • > То, что - используется в друх разных контекстах - да, проблема, точно такая же, как и описаная выше.
                            Подходящих ascii символов не так много (и эстетически желательно чтоб они не смотрелись чужеродно).

                            > В Лиспе точка используется для создания "неправильных" списков и для чисел с плавающей запятой.
                            Она и имелась ввиду, неточно высказался. Ну и лисп - случай особый, про иногда излишнюю однороднось вы сами заметили.

                            > Ну, или он будет вроде вас, с пеной у рта доказывать "что все ок".
                            Не преувеличивайте :), я не говорю, что все хорошо (например меня выбешивает, что map = fmap = liftA = liftM, сволочи). Но приведенные претензии кажутся чересчур надуманными. Если встречаешься с чем-то, что лучше остального (в определенных аспектах) - планка повышается, и падение становится более больным.

                            > А вы прям так сразу, как аргументы заканчиваются на личности переходите?
                            У меня все ходы записаны (с)... Вы же сказали, что я ничерта не понял (не дословно) =).

                            > Чем одна пустая группа "∅" от другой пустой гуппы "∅" отличается?
                            То есть False уже отпадает? Просто когда в сигнатуре пишут, например, a -> [b] - читаем что ф-ия возвращает список, _возможно_ пустой. А когда a -> IO () - ничего не возвращает (NULL), но может совершать какое IO-действие (патч Бармина наложить). А группы-то разные: в первом случае условно [] - ∅ для [a], во втором () - вся группа. С точки зрения типов разница есть, хотя, возможно, не все логично.
                            Ответить
                            • False = ∅, как говорят англичане, for all intents and purposes. Безвозвратно и безоговорочно. Если это не так, это проблемы языка. Пустот не бывает много. Если нужно больше чем одна - проблема плохого проектирования. Аналогично, пустой список ничем не отличается от любой другой пустоты.
                              Да, вы не поняли в чем претензии, поэтому я и написал, что вы не поняли :S
                              Зачем использовать ASCII символы, если есть более доступный для понимания английский язык, который, вобщем-то, и объяснять не пришлось бы? Вы себе представляете, что такое для новичка найти документацию или хоть вообще какие-то материалы в Гугле про использование | в Хаскелле? :)
                              Ответить
                              • > False = ∅, как говорят англичане, for all intents and purposes.
                                Пруф пожалуйте. Мало ли к чему вы привыклы в лиспе с перегруженным nil, в той же схеме (а она почище будет) #f и '() - разные сущности.

                                > Если нужно больше чем одна - проблема плохого проектирования.
                                Пустота одна: (), попытки приплести туда [] / False - пока неубедительны.

                                > Аналогично, пустой список ничем не отличается от любой другой пустоты.
                                Пустоту списка нельзя выразить на уровне типов, вам же (доступно вроде) объяснили.

                                > Да, вы не поняли в чем претензии, поэтому я и написал, что вы не поняли :S
                                С такой же аргументацией, как в "эти вопросы риторические, т.как на них нелзя вразумительно ответить." я мог бы сказать "эти вопросы риторические, т.как это бессвязный бред". Будьте добры пояснить почему же они _риторические_, и почему я "ничего не понял" в ваших стройных умозаключениях.

                                > Зачем использовать ASCII символы, если есть более доступный для понимания английский язык
                                Давайте скобочки в лиспе заменим ключевыми словами, хотя бы begin и end?

                                > Вы себе представляете, что такое для новичка найти документацию или хоть вообще какие-то материалы в Гугле про использование | в Хаскелле? :)
                                Ибо незачем с места в карьер, это не пинон. Пусть новичок прочитает, например, gentle introduction to haskell.
                                Ответить
                    • ЗЫ. "Сахар" никому никогда не нужен. Он никогда ничего не улучшает, только запутывает, т.как начинает создаваться впечатление, что существует разница между двумя разными фрагментами программы, в то время, как ее нет. Это скорее сигнал о том, что синтаксис в оригинале был неудачный, и это попытались как-то завуалировать.
                      Ответить
                      • > ЗЫ. "Сахар" никому никогда не нужен. Он никогда ничего не улучшает, только запутывает
                        Ага и строки в С вы пишете как массив из char. И списки в лиспе как простыню из cons. И [.. for .. in .. if] в питоне не используете. Просто иногда "засахаривают" вместо того чтобы перейти к более общим конструкциям (пример: многоэтажный list-comprehension, вместо do).

                        > ЗЫЫ. То, что в Хаскелле нет возможности отличить ссылку на функцию от ее применения - это тоже достойно отдельного упоминания, я думаю.
                        Что значит применения? Возможно для вас это секрет, но собственно что-то происходит только из-за использования IO прямо или косвенно из main: понадобился результат - выполнилось.
                        Ответить
                        • Так вот в том то все и дело, чот нет. То, что есть в Лиспе - это элемент языка, и написать:
                          `(x y) - это не то же самое, что (list 'x 'y) и не то же самое, что (cons 'x (cons 'y nil)) - т.как в первом случае - константа, а во втором вычисляемое выражение. Разница между вторым и третим в том, что list - это функция, котора вызывает другую функцию - cons в нашем случае. Это не сахар. Это просто одна функция вызывает другую. И в определенных моментах, это может различаться. Использование do ничем не оличается от прямого вызова соответствующих функций.

                          Ссылка в Лиспе: #'reference, применение: (reference) - так понятнее?
                          Ответить
                          • Имелось ввиду (list ... ) vs (cons .. (cons .. nil)), '(...) не учитывал.

                            > Ссылка в Лиспе: #'reference, применение: (reference) - так понятнее?
                            А с чего вы решили, что мне непонятно? (спасибо, elisp-ом пользуюсь регулярно).
                            Ответить
                            • list - это функция, вы ее можете переопределить локально в вашем текущем выбранном пакете, это никак не повлияет на работу cons. Но если вы переопределите cons - то, скорее всего ничего больше работать не будет. Но результат будет явно другой. Это потому, что list можно записать как:
                              (defun pseudo-list (&rest x)
                                (if (null x) x
                                    (cons (car x) (apply #'pseudo-list (cdr x)))))

                              Это не сахар. Это все равно, что в Яве вы напишете
                              ArrayList<Integer>listOfInteger(Integer a, Integer b, Integer c)
                              {
                              	ArrayList<Integer> list = new ArrayList<Integer>(3);
                              	list.add(a);
                              	list.add(b;
                              	list.add(c);
                              	return list;
                              }

                              вместо того, чтобы каждый раз, как вам нужно создать массив из 3 чисел, вы будете add() 3 раза писать.
                              Ответить
                              • > list - это функция, вы ее можете переопределить локально в вашем текущем выбранном пакете, это никак не повлияет на работу cons
                                Заглянул на вики (слабый, конечно, аргумент): там кстати пишут, что list - "shorthand" для cons. Пожалуй, с ф-ми, я погорячился, но ведь '(a b ..) и '(a . (b . .. ())) - одно и то же? Кстати, некороторые макросы вполне можно считать сахаром: например loop может ракрываться в зависящую от реализации конструкцию (вроде SB-LOOP::LOOP-BODY).

                                Просто хотелось пример из лиспа, а так мог взять prolog: [A,B,...Z] vs [A|B|...Z|[]]. В любом случае утверждение «"Сахар" никому никогда не нужен. Он никогда ничего не улучшает, только запутывает» - слишком категоричное, чтобы быть истинным.

                                > Это не сахар. Это все равно, что в Яве вы напишете
                                > ArrayList<Integer>listOfInteger(Integer a, Integer b, Integer c)
                                Давайте без явы, в ФП-сраче - это моветон :).
                                Ответить
                                • В какую Википедю вы смотрели? Есть документация, hyperspec еще называется.
                                  http://clhs.lisp.se/Body/f_list_.htm
                                  Но если с ней не получается: (describe 'list) и читайте.

                                  Какой перегруженный nil? Как можно перегрузить константу?
                                  Пруф наивной теории групп? Это на первом курсе учат, в худшем случае - почитайте в Википедии.
                                  http://en.wikipedia.org/wiki/Naive_set_theory


                                  '(a . (b . ())) vs '(a b)
                                  это уже ближе, но не одно и то же. Т.как в первом случае применяется другой reader-macros. Имея большое желание, его так же можно переопределить, и в таком случае выражения будут разными. В самом банальном случае - первое выражение занимает больше места на стеке (в зависимости от настроек компиляции), и, если места на стеке критически мало, то первое приведет к ошибке раньше, чем второе. Кроме того, первое выражение - это такая огромная редкость, что я за всю жизнь ни разу не сталкивался. Т.е. шансы, что человек изучающий язык увидит что-то такое и будет пребывать в недоумении по поводу увиденного стремятся к нулю.

                                  Scheme чище чего? О каком Лиспе вы говорите? В каком смысле "чище"? Если какому-то идиоту пришло в голову добавить еще один null в язык - это сделало его чище? Каким образом?

                                  Это все какие-то бездоказательные рассуждения из области "нас окружает невидимое энергетическое поле которым нас наделили инопланетяне. Не верите - почитайте что люди пишут!"
                                  Ответить
                                  • > Какой перегруженный nil? Как можно перегрузить константу?
                                    Перегруженный, в смысле у него много значений: и пустое, и пустой список, и False. Bторое предложение, где упоминалась схема намекало об этом.

                                    > Пруф наивной теории групп? Это на первом курсе учат, в худшем случае - почитайте в Википедии.
                                    Это вообще при чем? Или вы выбрали пост, где можете что-то возразить и ответили к тому что приведен выше? Довольно рассчетливо, но пусть, прув почему False - обязательно ∅ (если есть модели такие модели - это еще не прув, интересует почему все модели Bool должны этому следовать).

                                    > это уже ближе, но не одно и то же. Т.как в первом случае применяется другой reader-macros. Имея большое желание, его так же можно переопределить, и в таком случае выражения будут разными.
                                    Допустим, но как вы могли заметить, прочитав _весь_ текст, это не очень принципиально. Цепляться к этому вряд ли стоит.

                                    > Scheme чище чего? О каком Лиспе вы говорите? В каком смысле "чище"?
                                    Синтаксически, меньше сущностей чем в CL, более причесанные макросы. Вы так и не объяснили с какого перепугу False - это NULL.

                                    > Это все какие-то бездоказательные рассуждения из области "нас окружает невидимое энергетическое поле которым нас наделили инопланетяне. Не верите - почитайте что люди пишут!"
                                    Отличная аннотация к вашему посту, еще немного, еще чуть-чуть... вас ждет успех.
                                    Ответить
                    • ЗЫЫ. То, что в Хаскелле нет возможности отличить ссылку на функцию от ее применения - это тоже достойно отдельного упоминания, я думаю.
                      Ответить
                      • Ну если вы считаете даже Хаскел языком с большим числом недостатков, тогда какой же язык "наиболее опрятен синтаксически и семантически" с вашей точки зрения?
                        Ответить
                        • Хехе, как ни странно - Ява. Но тут скорее фишка в том, что в ней очень ограниченный синтаксис. И, опять же, синтаксис - не показатель того, на сколько язык хороший или плохой. Это всего лишь показатель того, на сколько им будет удобно пользоваться. Я думаю, факты на лицо. Хаскелл, очень интересный язык, по сути. Но исполнен так отвратительно, что ну дальше прям ехать некуда.
                          Ответить
                          • > Я думаю, факты на лицо.

                            Что, батенька, весна сказывается?
                            Ответить
                        • Io приятен, правда малоюзабелен (пока, в основном, из-за падучести).
                          Ответить
                      • > Хаскелле нет возможности отличить ссылку на функцию от ее применения
                        Какие ссылки, это же типизированное лямбда исчисление. Всё является выражением, функции - объекты первого рода, кругом каррирование, никаких взятий ссылок. (+) - функция двух аргументов, (+) 1 - функция одного аргумента, (+) 1 2 - константное выражение.
                        Ответить
                        • Типизированое лямбда исчисление - и че? И в контексте функции существуют идентификаторы, они же ссылки. В том же лямбда исчислении всегда понятно, где ссылка, а где применение...
                          Ответить
                          • >> функции - объекты
                            > идентификаторы, они же ссылки
                            В том то и дело, что функции нужно воспринимать как объекты, именованные выражения.
                            Prelude> :type (+)
                            (+) :: (Num a) => a -> a -> a
                            Prelude> :type (+) 1
                            (+) 1 :: (Num t) => t -> t
                            Prelude> :type (+) 1 1
                            (+) 1 1 :: (Num t) => t
                            В языке с каррированием функций вообще нужно забыть про слово ссылка (привитое дурацким Lisp-2), и начать мыслить выражениями. Результатом вычисления выражения может быть новая функция, это абсолютно нормально. Т.е. (+) 1 - это выражение новой функции через функцию (+). Это как раз одна из самых выразительных и полезных особенностей языка.
                            Ответить
                            • Да какая разница? Объекты или не объекты. Нет возможности получить ссылку на функцию.
                              λx.identity x <-- определение какой-то функции, которая возвращает то, что получает
                              (λx.identity x)y <-- ссылка на что-то (y), возможно, функцию
                              ((λx.identity x)y)z <-- применение функции y к аргументу z.

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

                              Кстати, тоже, интересный момент - ни один душевно здоровый человек с десяти попыток не угадает, что id - это сокращение от identity. Это все равно, что initialize до in сократить. В любом другом языке однобуквенные названия, или когда названия типа foo, foo_, foo' foo1 используются все вместе для разных вещей и т.п. - это плохой тон, а в Хаскелле в стандартных библиотеках редко когда по-другому. В переводе на Яву, код на Хаскелле выглядит примерно:
                              X<y,yy> wtDoUnow(A b, C d) { E f = (E)b; return (X<y,yy>)d; }

                              Шифровальшики, блин.
                              Добавить к этому еще совершенно бешенное форматирование - зачем нужна индентация для последовательных равнозначных элементов, таких, как, например if-else и следующий за ним if-else? Или, например, потратить с полчаса в попытках понять почему одна переменная заменяется другой в выражении типа:

                              tatement x = ...
                              
                              foo = statement 1
                                    ...
                                    statement 2
                                    ...
                                   statement  3

                              Это, на мой малопрофессиональный взгляд куда круче, чем #define true = false...
                              Ответить
                              • > Так вот нет в Хаскелле никакой возможности отличить применение от ссылки. Нужно мысленно просчитать всю программу, чтобы догадаться о чем идет речь.
                                Это просто (я бы не сказал что негативное) следствие выделения "pure core" от IO. В хаскеле удобно полагать, что при написании программы вы создаете посредством связей некую схему. Ток подается лишь на main (интерактивные возможности ghci пока не считаем, но они таки тоже выполняются в контексте IO) при запуске программы. Разве плохо, что сущностей меньше?

                                > Кстати, тоже, интересный момент - ни один душевно здоровый человек с десяти попыток не угадает, что id - это сокращение от identity
                                В математике Id_A - часто обозначает идентификатор множества, связь есть. А что, учитывая чистоту сигнатуры, душевно здоровый человек будет ожидать от id?

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

                                > Или, например, потратить с полчаса в попытках понять почему одна переменная заменяется другой в выражении типа:
                                А можно конкретный (не)работающий пример, которому удалось вызвать сей диссонанс.
                                Ответить
                              • >ни один душевно здоровый человек с десяти попыток не угадает, что id - это сокращение от identity
                                Это очень популярное обозначение в ФП, такое же, как например fold.
                                Ответить
                              • Одна из ключевых идей в Хаскеле - избавиться от лишних абстракций, оставив наиболее общие и необходимые. Никто не мешает вам давать функциям и аргументам описательные имена. Функции практически всегда имеют очень говорящее имя, а с аргументами всё немного сложнее: в ideomatic Haskell аргументы функции часто вообще отсутствуют: функции могут определяться целиком через композицию ("бесточечный" стиль). Вот в конструкторах типов же всегда указываются вразумительные имена параметров.
                                Стандартные библиотеки, как правило, работают с очень общими вещами (списками, к примеру). И я не вижу ни одной причины, почему имена переменных "x" и "xs" были бы лучше, чем "item" и "items" (мне, как человеку с неплохим математическим образованием, первый вариант ближе).
                                Ответить
                              • > Кстати, тоже, интересный момент - ни один душевно здоровый человек с десяти попыток не угадает, что id - это сокращение от identity.

                                Алгеброй не занимались, ясно.
                                Ответить
                                • В моем учебнике использовалась греческая строчная эпсилон для этой функции. Иногда видел прописную латинскую I, но id вижу во второй раз. И кроме Эрланга и Хаскелла больше в этом качестве мне нигде не попадалась. В то же самое время, в других языках, где такая же функция имеет место быть она называется либо identity, либо values (если речь идет о возрвате множества значений).
                                  Кромет того, доказательства на основании а вот "у всех так", во-первых, и не доказательства вовсе, т.как на основе такой "статистики", не возможно сделать никаких выводов о целесообразности. А во-вторых, тут еще и статистика никаким боком не подтверждает: из маргинальной группы языков выбирается еще меньшая группа (если чесно, то всего 2 языка) и на основе этого делаются какие-то утверждения? Это даже не граничит со здравым смыслом - просто желание спорить и доказать любую точку зрения, не зависимо от обстоятельств.
                                  Ответить
                            • Да, для наглядности, а вот теперь представьте, что + вы получили по ссылке, а с ним еще и какие-то переменные. Т.е. Ваше выражение превращается в:
                              a b c

                              А вот теперь угадайте с трех раз, что записано в коде выше?
                              1. Приментить a к результату от применения b к c.
                              2. Применить a к аргументам b и c.
                              3. Применить b к аргументам a и c.
                              4. Выражение не имеет значения, т.как это продолжение выражения Foo a b c, в котором a, b и c - параметры класса Foo.
                              5. Выражение не имеет значение, т.как это неоконченое объявление функции a принимающей аргументы b и c.
                              Ответить
                              • можно вырвать из контекста последоватьельность символов на любом языке и он будет иметь несколько интерпретаций. В вашем примере у меня сомнений нет: применение а к аргументам b и c. Если бы было a `b` c, получили бы применение b к аргументам a и c. Всё очень просто и однозначно.
                                по-моему, у вас просто баттхёрт от непривычных для вас конструкций. Программисту на OCaml haskell наверняка покажется очень логичным и понятным.
                                Ответить
                              • > Да, для наглядности, а вот теперь представьте, что + вы получили по ссылке
                                Проще сразу представить сферический хаскель в вакууме без типов и каррирования, сразу видно - язык говно.

                                > a b c
                                (a b) c - в нормальном хаскеле, как напоминает, КО, ибо аппликация аргументов левоассоциативна.

                                > А вот теперь угадайте с трех раз, что записано в коде выше?
                                Давайте без сферического хаскеля, "talk is cheap, show me the code" - будьте любезны привести пример кода, который сложно "распарсить". А вашу викторину оставим до лучших времен.
                                Ответить
                                • А вот и хер: b объявлен как инфиксный оператор. И это не сферичерский Хаскелл. Это валидный код.
                                  Ответить
                                  • А какая разница как он объявлен? Оператор или ф-ия определяется в контексте использования. Объявление "x `b` y = ..." - то же самое, что "b x y = ...", как и "(&) x y = ..." vs "x & y = ...". В данном случае имеется неоператорный литерал и в backquote незаключен => распарсится как аргумент.

                                    // Произвольную последовательно символов под b понимать явно двусмысленно, а то мало ли что там, возможно и "--".
                                    Ответить
                                    • ОК, конкретизируем, 3 терминала формирующие один не-терминал.
                                      Кроме того, остается еще вариант, когда это функция вызваная с двумя аргументами. Для сравнения, точно такой же синтаксис возможен например в bash - но там это однозначно понятно, что это функция (команда) с двумя аргументами. Такой же синтаксис возможен в C++, например, но в C++ это будет что-то типа unsigned int identifier - т.е. одно из слов будет ключевым.
                                      Но в Хаскелле это еще ухудшается тем, что очень трудно определить где не-терминал начался или закончился. Т.е если начать читать код с произвольного места, а не с первого знака программы, то понять из того, что было прочитано, что именно написано - практически нет шансов. Т.е. только методом подстановки и последовательных попыток угдать. На каком-то этапе отпадут другие варианты, но для того, чтобы это случилось нужно будет несколько раз прочитать текст до и после нужного места, найти то, на что указывают идентификаторы, при чем все. Т.как из контекста не понятно ни тип ни предназначение идентификатора... И это еще хорошо, если в коде нет ошибок, и все определения идентификаторов находятся в том же файле.
                                      Ответить
                                      • Вы просто ещё не привыкли к Haskell. Узнать тип функции (и, соответственно, аргументов) очень просто. Для этого есть ghci (:type). Кроме того, ошибку с типами в программе на Haskell совершить очень трудно. Компилятор отлавливает все ошибки типов, и если уж программа скомпилировалась, то она на 98% работает правильно.
                                        Кроме того, принято описывать сигнатуру функции, из которой читатель сможет узнать типы всех аргументов (а компилятору она может помочь сгенерировать более эффективный код).

                                        P.S. Страйко, SMTP Error: Data not accepted. The following From address failed: [email protected]
                                        Ответить
                                      • > ОК, конкретизируем, 3 терминала формирующие один не-терминал. Кроме того, остается еще вариант...
                                        Тот кто смотрит код видит, что это за терминалы и (при наличии подходящего опыта) выявит синтаксическую конструкцию. Конечно, хотелось бы увидеть сам код, а то до конца не понимаю в чем проблема различить варианты.

                                        btw, никто не запрещает писать в lisp-style: заковываем операторы в скобочки, ((*) x ((+) y z)).

                                        > Но в Хаскелле это еще ухудшается тем, что очень трудно определить где не-терминал начался или закончился. Т.е если начать читать код с произвольного места, а не с первого знака программы
                                        Не преувеличивайте, все-таки не первого знака, можно сразу смотреть на top-level declaration. Размеется, могут быть проблемы с читаемость, особенно если запаковать нетривиальную фунцию в строку с помощью ($) / (=<<) / (<=<) / fmap / (.) и сотоварищи. Но это вина автора кода, который не выделил локальные ф-ии с читаемыми именами etc. Данная проблема может возникнуть из-за неидиоматичной для хаскеля конструкции.

                                        > нужно будет несколько раз прочитать текст до и после нужного места, найти то, на что указывают идентификаторы, при чем все
                                        Обычно можно искать: биндинги, создаваемые let -> where -> top-level declarations. В том же лиспе тоже нужно посмотреть на внешние let. Если хотите, можете where (но он удобен) не использовать - не придется забегать вперед.

                                        > и все определения идентификаторов находятся в том же файле.
                                        Если правильно понимаю, это уже несколько в сторону. Вопрос организации модулей: как лучше разделить и что предоставить.

                                        > и все определения идентификаторов находятся в том же файле.
                                        Если правильно понимаю, это уже несколько в сторону. Вопрос организации модулей: как лучше разделить и что предоставить. (Но сигнатура / принадлежность к классу или ADT видна и для внеших идентификаторов, про ghci roman упомянул).
                                        Ответить
                                        • В "Лисп-стиле" писать все время не получится, потому что парсер разрешает очень много того, что в Лиспе нельзя сделать - изза чего получается синтаксические ошибки. С другой стороны - не получится потому что язык не различает ссылки и применения.

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

                                          В том же лиспе тоже нужно посмотреть на внешние let. - Нет. Вы просто либо вообще не знаете о чем говорите, либо специально говорите неправду. В Лиспе парсер синтаксиса, при условии, что не использованы пользовательские ридер-макросы всегда, причем именно всегда, при наличии синтаксичесой ошибки укажет на ошибочный терминал. Так построена граматика языка. Я не берусь утверждать на 100%, но в bash по-моему так же. На вскидку я не могу придумать ситуацию, когда бы парсер не смог однозначно определить терминал (не окно консоли, а атомарный елемент граматики), в котором есть синтаксическая ошибка.

                                          Вы путаете синтаксис и то, что из синтаксиса получается:

                                          String foo = 1 + 2;
                                          Это валидный синтаксис но не валидный код, т.как очевдно, что строка не совпадает с int. Но с точки зрения парсера - тут все хорошо, есть 7 терминалов, 4 не-терминала: '1 + 2', 'String foo', 'String foo = 1 + 2', 'String foo = 1 + 2;' - человек похожим способом воспринимает код. Т.е. прочитав код выше он поймет, что должно было быть написано (и в чем ошибка) и исправит.
                                          Т.е. для сравнения:
                                          let foo = 1 + 2
                                          Тип foo не определен (если есть несовпадение типов - нужно угадывать, что имелось в виду). Нет уверенности в том, что не-терминал закончился, т.как если дальше идет + 3 - то это очевидно продолжение не-терминала.
                                          Ответить
                                          • Не осилили синтаксис - значит, язык не для вас. Я лично код из pure core понимаю (с точки зрения синтаксиса) без малейших проблем. Мне синтаксис кажется очень простым. Научиться строить и понимать функциональные алгоритмы - гораздо более трудоёмкая задача.
                                            Ответить
                                          • > В том же лиспе тоже нужно посмотреть на внешние let. - Нет. Вы просто либо вообще не знаете о чем говорите, либо специально говорите неправду. В Лиспе парсер синтаксиса...
                                            Вообще-то мы (по-крайней мере я) говорили о читаемости кода программистом _глазами_. Конкретные парсеры - это уже вопросы реализации, которые не имеют непосредственного отношения к языку.

                                            > Вы путаете синтаксис и то, что из синтаксиса получается:
                                            Да вы, батенька, телепат. Давайте конкретно: почему путаю?

                                            > String foo = 1 + 2; Это валидный синтаксис но не валидный код, т.как очевдно, что строка не совпадает с int ...
                                            Невалидный код - потому что String не data constructor, а type и в данном контесте использоватся не может. Вы хоть проверили перед тем как постить?

                                            > Но с точки зрения парсера - тут все хорошо
                                            Еще бы, нормальный код тоже так может выглядеть: Just b = ... (где-нибудь в let).

                                            > Т.е. для сравнения: let foo = 1 + 2
                                            Определен: смотрите top-decl default (целый, дробный) - по умолчанию (Integer, Double)
                                            Ответить
                                    • ЗЫ. Именно поэтому сообщения парсера об ошибках синтаксиса как правило ни о чем не говорят / не могут указать конкретно на ошибку - т.как есть очень много вариантов, и невозможно автоматически понять, что именно случилось. Ошибки синтаксиса как правило не то, что не указыватют правильно позицию в строке, где эта ошибка случилась, они вообще даже строку угадать не могут.
                                      Ответить
                                      • > ЗЫ. Именно поэтому сообщения парсера об ошибках синтаксиса как правило ни о чем не говорят / не могут указать конкретно на ошибку - т.как есть очень много вариантов, и невозможно автоматически понять, что именно случилось.
                                        Можно, но непросто, с этим проблема есть.

                                        > Ошибки синтаксиса как правило не то, что не указыватют правильно позицию в строке, где эта ошибка случилась, они вообще даже строку угадать не могут.
                                        Показывается проблема где компилятор не осилил приписать тип, он же не телепат, чтобы ошибку идеально разрулить. Но найти исходное место это поможет.
                                        Ответить
                                        • Вы теплое с мягким путаете: синтаксис и то, во что этот синтаксис превращается:
                                          foo(x) в Яве - вы не знаете, что тип этого выражения это String потому, что вы не знаете что возвращает foo. Но вы знаете, что это вызов функции. Что такое foo x не возможно сказать однозначно, можно понять только из контекста.

                                          Я про ошибки синтаксиса говорю, вы вообще понимаете в чем разница?
                                          Ответить
                                          • > foo(x) в Яве - вы не знаете, что тип этого выражения это String потому, что вы не знаете что возвращает foo
                                            Вам запрещено смотреть сигнатуру ф-ии? Про ghci уже было сказано.

                                            > Что такое foo x не возможно сказать однозначно, можно понять только из контекста.
                                            Значит надо смотреть на более широкий контекст (включить в него объявление foo).

                                            > Я про ошибки синтаксиса говорю, вы вообще понимаете в чем разница?
                                            А вы всмысле "parse error"? Пардон, просто реже с ними сталкиваюсь, тут вам действительно компилятор не всегда поможет. А вот прочтение "syntax reference" из haskell report (или gentle introduction) - могло бы.
                                            Ответить
                                            • Да при чет тут не осилил? Какими "глазами"? Блин, большего кретинизма смешенного с элитизмом родившимся на пустом месте тяжело найти. Вам дают пример, где все как 2 + 2 расписано, а вы начинаете воду по фотографии заряжать. Не хотите замечать - я достаточно написал, чтобы можно было меня понять. Нет смысла продолжать что-то объяснять.
                                              Ответить
                                              • Над дизайном языка работали умнейшие и опытнейшие люди, много лет занимающиеся функциональным программированием и исследованиями в области искуственного интеллекта (рание реализовавшие другие функциональные языки: Miranda etc). То есть вы хотите сказать, что они нихрена не понимают в дизайне языков и сотворили нечитаемое говно (sic!). Ну-ну.

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

                                                Есть там проблемы, да. Например, в стандарте 98 отсутсвует возможность инстанциировать несколько экземпляров классов для полиморфных типов (немного напоминает специализацию шаблонов c++). ghc имеет расширение, позволяющее решить проблему, но стандартное решение (использовать newtype) не очень изящно.
                                                Ответить
                                              • > Да при чет тут не осилил?о
                                                Вы про компилятор? Тогда это вне контекста, можете вопрос более четко задать... или это не мне?
                                                Какими "глазами"? Был разговор про читаемость синтаксиса, скакать между как его воспринимает человек и парсер - мне не улыбается. Конкретно: про let имелось ввиду, что в haskell, как в lisp нужно посмотреть на "внешние" let, чтобы понять код. А вы почему-то про парсер вспомнили.

                                                > с элитизмом родившимся на пустом месте тяжело найти
                                                Какой еще элитизм? Элитизмом больше от лисперов "веет", как компенсация того, что их "более достойный" предмет обожаний незаслуженно забыт на задворках computer science.

                                                > Вам дают пример, где все как 2 + 2 расписано, а вы начинаете воду по фотографии заряжать.
                                                >> Определен: смотрите top-decl default (целый, дробный) - по умолчанию (Integer, Double)
                                                Это и был ответ: если компилятор не сможет уточнить тип foo из контеста (скажем, аргумент foo складывается с Double). То будет Integer (если нет default-declaration).

                                                > Не хотите замечать - я достаточно написал, чтобы можно было меня понять
                                                Аналогично, я доступно ответил, чтобы можно было меня понять.

                                                > Нет смысла продолжать что-то объяснять.
                                                Убедили, бросаю, судя по всему, бесцельные попытки.
                                                Ответить
                                          • // раз уж опять на личности переходите, скромно намекну, что у вас от штанги грыжа, а все из-за присяда без пояса =)
                                            Ответить
              • > Я это говорю к тому, что зачем эти типы вообще нужны?

                By design, тип должен быть известен на этапе компиляции (если обойтись без каких-нибудь сильных колдунств).

                > "Tuple #"

                Просто число для # не подойдет, его же можно будет проверить только в рантайме. Надо делать тип, например () -> () ... -> (). Уже получается не очень просто.
                Ответить
                • Для таких целей в других языках были придуманы шаблоны. Но если представить, что в Хаскелле еще бы и шаблоны были бы, ну его, лучше уже так потерпеть.
                  Ответить
              • Мне Haskell показался очень продуманным и красивым языком.
                И уж он гораздо более продуман и логичен, чем CL, да и стандартная библиотека побогаче. IMHO, CL на фоне Haskell выглядит как набор кривых костылей аля C++.
                Условностей мало, основной синтаксис можно освоить за день (да, "синтаксис" лиспа можно освоить за час, но для понимания различий в семантике и особых форм нужны месяцы). Да, для понимания монад и аппликативных функторов нужно приложить определённые усилия.
                Ответить
    • Интересно, почему говнокод раскрасил буквы m, q, s, x и y?
      Ответить
      • это прям какое-то искуство
        Ответить
        • искусство
          Ответить
          • http://govnokod.ru/9598#comment132056
            roman-kashitsyn
            >Над дизайном языка работали умнейшие и опытнейшие люди, много лет занимающиеся функциональным программированием и исследованиями в области искуственного интеллекта
            >в области искуственного интеллекта
            >искуственного

            Никудышный из тебя граммар-наци.
            Ответить
            • я уважаю слово "искусство", но не уважаю слово "искусственный" :)
              да там ещё прилично опечаток найти можно. shame on me
              Ответить

    Добавить комментарий