LINUX.ORG.RU
Ответ на: комментарий от alienclaster

Я привел объективный пример когда это неудобно

Любое решение чем-то неудобно. Твой «объективный пример» на практике неважен.

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

твой end для замыкающих лесенок только чисто визуальный

Танунах такое xD

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

Твой «объективный пример» на практике неважен.

Не забывай о том, что это твое субъективное *мнение* об объективно факте.

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

Твой «объективный пример» на практике неважен.

Не забывай о том, что это твое субъективное *мнение*

Ну, можно придумать практику, в которой это будет важно, но зачем? А мнение, конечно, субъективно.

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

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

>>> (lambda x, (y, (z1, z2)): x and  x/y or max(z1, za2))(1, (0, (3, 0)))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<console>", line 1, in <lambda>
ZeroDivisionError: integer division or modulo by zero
>>> (
    lambda x, (y, (z1, z2)):
        x
          and
        x/y
          or
        max(z1, za2)
)(1, (0, (3, 0)))
Traceback (most recent call last):
  File "<console>", line 8, in <module>
  File "<console>", line 5, in <lambda>
ZeroDivisionError: integer division or modulo by zero
>>> 
Здесь, правда, тип исключения указывает на источник ошибки, но он не всегда так информативен.

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

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

То что было приведено это совсем другой вопрос не относящийся особо к PM - писать функции через явную рекурсию или через [point free] композиции комбинаторов / свёртку и т.п. (естественно, второе будет декларативнее). Числа вообще неалгебраические типы в хаскеле, а вот если ты возьмёшь любые сложные данные (алгебраических типов, например, XML, JSON, термы любого языка), то большинство функций для этих сложных данных будут писаться с помощью PM. Вообще, если почитать и пописать программ на хаскеле, то можно увидеть, что без ADT и PM вообще ничего обычно не делается.

как делать (имератив), во втором - что хотим получить (декларатив).

Если я хочу получить «Hello world» на экране, то (print «Hello world») и будет наиболее декларативной записью, если я _действительно хочу_ in-place обновление данных, то присваивание будет очень даже декларативным элементом (это то что я хочу получить - обновление структуры на месте), то же самое про сообщения, треды и т.п.

А я наоборот - что они подходят _наилучшим_ образом.

Ну и какой образцовый компилятор написан на лиспе? Надеюсь, не SBCL? :)

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

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

Вот ADT и PM это такие концепты, которые в ML-ях являются очень удобными конструкциями языка (не паттернами), а в си или питоне - только лишь паттернами. Если это конструкции языка, то волноваться за целостность PM не нужно (реализация за этим проследит), если паттерны, то да, могут быть опасения. В лиспе нет ADT+PM в виде конструкций языка - это паттерны, но, в принципе, макро-система позволяет их достроить в виде конструкций. Но это только в принципе.

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

Вот ADT и PM это такие концепты

Т.е. им можно сопоставить конкретную мат. модель.

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

То что было приведено это совсем другой вопрос не относящийся особо к PM - писать функции через явную рекурсию

Чел, не гони - там было сопоставление с образцом, несмотря на то что была и рекурсия (в данном случае фиолетова именно она)

или через [point free] композиции комбинаторов / свёртку и т.п. (естественно, второе будет декларативнее).

Угу, естественно будет. В этом суть примера

Числа вообще неалгебраические типы в хаскеле

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

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

JSON вполне допускают может быть не ADT - частный случай можем описать как корректный JSON или как отсутствие JSON'a и обработать уже на уровне логики, не зашивая паттерн матчинг в определение.

то большинство функций для этих сложных данных будут писаться с помощью PM

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

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

Я это видел и считаю полнейшей херней и пагубной практикой

как делать (имератив), во втором - что хотим получить (декларатив).

Если я хочу получить «Hello world» на экране, то (print «Hello world») и будет наиболее декларативной записью, если я _действительно хочу_ in-place обновление данных, то присваивание будет очень даже декларативным элементом (это то что я хочу получить - обновление структуры на месте), то же самое про сообщения, треды и т.п.

С чем ты споришь? Я написал ровно то же самое несколько постов назад

Ну и какой образцовый компилятор написан на лиспе? Надеюсь, не SBCL? :)

Я не знаю на счет «образцовых», и практически уверен - что все что можно было бы посмотреть и не проблеваться - закрытое чуть более чем полностью и не является компилятором лиспа на лиспе в машкод. Скорее лисп выступает компилятором из dsl в формы lisp, ast или вочтоугодно. И я считаю это очевидным

Это не buzzword и не модный. Это я просто говорю так.

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

В лиспе нет ADT+PM в виде конструкций языка - это паттерны, но, в принципе, макро-система позволяет их достроить в виде конструкций. Но это только в принципе.

Есть сомнение, что ADT в виде «конструкции языка» нахрен не нужна, а паттерн матчинг делается на макросах. С любым синтаксисом, as u wish

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

Чел, не гони - там было сопоставление с образцом, несмотря на то что была и рекурсия (в данном случае фиолетова именно она)

Угу, естественно будет. В этом суть примера

Ещё раз, ты берёшь неалгебраические типы (числа) с конструкторами [minBound .. maxBound] и пишешь факториал через рекурсию (PM - рекурсия на default clause и терминальное значение на 0-clause) и через свёртку. Делаешь ты это чтобы обосновать своё «PM ... отрубили ещё что-то там у декларативности». Тогда как PM естественно использовать с алгебраическими типами (ADT), так что разумнее было привести пример сложного ADT и функций матчащих этот ADT - то есть то как обычно используют PM. Но этим ты бы опроверг утверждение о недекларативности PM. См. Wearing the hair shirt: a retrospective on Haskell (pdf) про то что считать декларативными конструкциями в хаскеле, а что нет.

Про числа в виде ADT можешь посмотреть арифметику Пеано (PM там тоже можно рассмотреть).

У хаскелистов всегда какое-то шатание с терминологией.

Да ты што.

Если ты понимаешь под алгебраическими типами...

http://bit.ly/yOMUXR

JSON вполне допускают может быть не ADT - частный случай можем описать как корректный JSON или как отсутствие JSON'a и обработать уже на уровне логики, не зашивая паттерн матчинг в определение. В пакете json можно посмотреть как это выглядит (пакеты для XML, XHTML, whatever можно поискать в hoogle).

Это предложение я уже не понимаю. Но если ты пойдёшь на json.org, то увидишь синтаксическую диаграмму, которая изоморфна BNF, который изоморфен грамматикам Хомского 2/3 типа, которые изоморфны [неполиморфным] алгебраическим типам.

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

Не распарсил.

Я это видел и считаю полнейшей херней и пагубной практикой

Давай расскажем это создателям / пользователям OCaml / SML / Haskell / Clean / Agda / Coq / Racket / Clojure / Erlang / F# / Nemerle / Scala / ... (в Erlang - PM с records, в Clojure - PM и ADT из contrib).

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

Ок, а вот на C++ или Haskell написаны разные вменяемые вещи.

Скорее лисп выступает компилятором из dsl в формы lisp, ast или вочтоугодно. И я считаю это очевидным

Ну да, скобочный eDSL (макро-форма-1)-> скобочный eDSL (макро-форма-2)-> ... (макро-форма-n)-> данный лисп. И Racket в котором этот подход допилен до использования PM на AST.

Твой собственный термин? А зачем он нужен, если есть вполне примений и устоявшийся - «паттерн»?

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

Есть сомнение, что ADT в виде «конструкции языка» нахрен не нужна

ADT уже есть - defclass / defstruct как типы произведения. deftype+or как типы суммы. Нет нормальной статической системы типов, позволяющей ограничить case (typecase) со всего T к конкретной сумме типов. Это хорошо или плохо - холиварный вопрос.

а паттерн матчинг делается на макросах.

Делается. Но как-то всё никак не сделается. Никто просто его не использует (cliki завален разными реализациями, но они не числятся зависимостями ни у одного нормального проекта). Разве что в Racket уже сделалось. Но вот и получается - если не заложить возможность в язык, оставив возможность достроить (макросами, например), то широкого распространения фича не получит.

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

В пакете json можно посмотреть как это выглядит (пакеты для XML, XHTML, whatever можно поискать в hoogle).

Вот так.

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

Ещё раз, ты берёшь неалгебраические типы (числа)

Еще раз. Это был пример плохой практики использования PM, с разговорами об алгебраических типах ты пришел позже.

Тогда как PM естественно использовать с алгебраическими типами (ADT)

Я пишу об этом третий пост. ADT *задаются* с помощью того или иного набора «образцов», т.е. с помощью PM - естественно, что такие типы удобно обрабатывать с помощью PM. Что неясно-то?

(pdf) про то что считать декларативными конструкциями в хаскеле, а что нет.

Уж как-нибудь сам разберусь, без священных писаний - что и чем считать

Про числа в виде ADT можешь посмотреть арифметику Пеано (PM там тоже можно рассмотреть).

О применимости PM к математике (о чем изначально писал я) ты как-то решил фильтрануть из поля внимания

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

Не распарсил.

ADT - «контейнерный» тип: тип из типов, обертка, коробка для типов представляющая новый тип, обладающий выборочными свойствами базовых типов.

Я это видел и считаю полнейшей херней и пагубной практикой

Давай расскажем это создателям / пользователям

Что рассказать? Что употребление не к месту PM - пагубная практика? Уверен, «мужики и так знают»

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

Ок, а вот на C++ или Haskell написаны разные вменяемые вещи.

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

Твой собственный термин? А зачем он нужен, если есть вполне примений и устоявшийся - «паттерн»?

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

Ok, пусть будет «концепт», но зачем рядом с ним столько пафосных слов, агностик там и все такое - для понтов?

Есть сомнение, что ADT в виде «конструкции языка» нахрен не нужна

ADT уже есть - defclass / defstruct как типы произведения.

Это не конструкция языка, а макрос.

Нет нормальной статической системы типов, позволяющей ограничить case (typecase) со всего T к конкретной сумме типов. Это хорошо или плохо - холиварный вопрос.

Зачем ты от динамически-типизированного языка требуешь статики? Используй haskell, shen, whatever

а паттерн матчинг делается на макросах.

Делается. Но как-то всё никак не сделается.

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

Никто просто его не использует

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

cliki завален разными реализациями, но они не числятся зависимостями ни у одного нормального проекта

Проект нормальный (сам сказал) - не используется PM -> PM ненужен

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

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

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

Это все одно и то же - урезанные варианты escape continuations.

Полноценные escape continuations есть, например, в Common Lisp - и на них уже строится знаменитая система обработки исключений CL. А вот в других языках их нету, и есть какие-то огрызки типа throw/catch или break/return/goto.

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

Что рассказать? Что употребление не к месту PM - пагубная практика?

Вот, теперь уже не «ввели PM - отрубили голову декларативности» (вообще), а «употребление не к месту PM - пагубная практика» (что верно).

ADT *задаются* с помощью того или иного набора «образцов»

ADT задаётся именами и сигнатурами конструкторов (+ именами аккессоров, при необходимости). Ну и трудно вспомнить язык в котором не было бы ADT именно в такой форме (например, структуры и объединения в си), и, таким образом, не был бы применим PM (как паттерн или языковая конструкция).

О применимости PM к математике (о чем изначально писал я) ты как-то решил фильтрануть из поля внимания

тут уже писал адаптацией чего является PM.

Ok, пусть будет «концепт», но зачем рядом с ним столько пафосных слов, агностик там и все такое - для понтов?

А зачем вообще нужны слова? По мне - слова как слова, никаких понтов не задумывалось.

Какие еще «вменяемые вещи»?

Да ладно, это чисто моё субъективное мнение - тот же LLVM выглядит лучше чем SBCL, про GHC я вообще не говорю.

Используй haskell, shen

shen

Буэ :)

Уж как-нибудь сам разберусь, без священных писаний - что и чем считать

Удачи.

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

Вот, теперь уже не «ввели PM - отрубили голову декларативности» (вообще)

Это не мои слова, я писал лишь об «отличном стимуле» делать это где попало, что тождественно утверждению:

«употребление не к месту PM - пагубная практика»

Уж как-нибудь сам разберусь, без священных писаний - что и чем считать

Удачи.

Интересно, чем вызвана столько агрессивная реакция, если мнение «авторитетных» источников не возводить в культ

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

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

Да хватит уже. Я же сказал, что тотальность PM чекается. Примеров негодного PM ты не привёл. И правильно - что может быть естественнее расписать функцию по конструкторам ADT?

Интересно, чем вызвана столько агрессивная реакция

Где?

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

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

Да хватит уже.

Че ты так эмоционально реагируешь, я не понял. Считаешь что я как-то дико туплю в этой дискуссии или что?

Я же сказал, что тотальность PM чекается.

Не понял этой фразы

Примеров негодного PM ты не привёл.

Тебе нужны примеры на ADT типах? Их не будет, по понятным причинам

И правильно - что может быть естественнее расписать функцию по конструкторам ADT?

Для функции, которая будет работать с ADT зачастую паттерн-матчин - это то что нужно

Интересно, чем вызвана столько агрессивная реакция

Где?

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

// кроме того, у этого общения есть хотя бы определенный выхлоп, в отличии от многих других флеймов на лоре

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

Че ты так эмоционально реагируешь, я не понял.

но в этом разговоре - срываешься на эмоции и прочие приколы.

Тебе показалось.

Не понял этой фразы

[ruby] Как язык общего назначения (комментарий) — там где про предупреждения про потерянные clauses.

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

Тебе нужны примеры на ADT типах?

Да, потому что ADT-типы это, в основном, именно те типы, которые используются при написании программ (остальные это примитивные типы). ADT = типы суммы типов произведений, всякий раз когда в си мы используем struct мы делаем тип произведение, размеченный union - тип сумму, всякий switch по тайптегу и связывание переменных (которые на стеке) с полями структуры (на стеке или в куче) это единичный case, вложенные switch со связыванием - ручной хардкод паттерн матчинга. Получается использование паттерна ADT+PM, без всяких гарантий покрытия кодом своих структур данных. Вот ADT+PM как конструкция языка это то же самое, только более удобно и с гарантиями.

Вот, например, BNF для s-выражений:

sexp ::= string | ( sexp . sexp )

s-выражения это язык (множество цепочек над словарём), полноценное использование их в основном языке делает из этого языка eDSL (не просто язык, но гомоиконно встроенный и предназначенный для специальных целей). BNF это грамматика (конечный способ задания языка как множества), ADT это тоже грамматика, эквивалентная по выразительности BNF.

В языке в котором ADT+PM это концепты-паттерны, например, в си, реализация такого eDSL будет выглядеть примерно так:

#include <stdio.h>
#include <stdlib.h>

// type tag values
typedef enum { SYM, CONS } SExpCon;

struct SExp {
    // type tag
    SExpCon con;
    // type sum
    union {
        // accessors
        char *sym;
        struct Cons *cons;
    } sexp;
};

// product type
struct Cons {
    // accessors
    struct SExp *car;
    struct SExp *cdr;
};

typedef struct Cons Cons;
typedef struct SExp SExp;

// constructor
SExp* mkSym(char *sym)
{
    SExp *sexp = (SExp*)malloc(sizeof(SExp));

    sexp->con = SYM;
    sexp->sexp.sym = sym;

    return sexp;
}

// constructor
SExp* mkCons(SExp *car, SExp *cdr)
{
    Cons *cons = (Cons*)malloc(sizeof(Cons));
    SExp *sexp = (SExp*)malloc(sizeof(SExp));

    cons->car = car;
    cons->cdr = cdr;

    sexp->con = CONS;
    sexp->sexp.cons = cons;

    return sexp;
}

// destructor
void gcSExp(SExp* sexp)
{
    // pattern matching
    switch (sexp->con) {
    case SYM:
        free(sexp->sexp.sym);
        break;
    case CONS:
        if (sexp->sexp.cons->car)
            gcSExp(sexp->sexp.cons->car);
        if (sexp->sexp.cons->cdr)
            gcSExp(sexp->sexp.cons->cdr);
        break;
    }
    free(sexp);
}

// pretty printer
void printSExp(SExp* sexp)
{
    // pattern matching
    switch (sexp->con) {
    case SYM:
        printf("%s", sexp->sexp.sym);
        break;
    case CONS:
        printf("(");
        if (sexp->sexp.cons->car)
            printSExp(sexp->sexp.cons->car);
        else
            printf("()");
        printf(" . ");
        if (sexp->sexp.cons->cdr)
            printSExp(sexp->sexp.cons->cdr);
        else
            printf("()");
        printf(")");
        break;
    }
}

int main ()
{
    char *hi = "Hi!";
    SExp *sexp = mkCons(mkSym(hi), mkCons(mkSym("You!"), NULL));
    printSExp(sexp);
    printf("\n");
    return 0;
}

работает на честном слове.

В языке в котором ADT+PM это концепты-конструкции языка, например, в хаскеле, будет так:

data SExp = Sym String | Cons SExp SExp
  deriving ( Show )

от BNF отличается только тем, что названы конструкторы (точно так же можно назвать аккессоры), в отличии от си не нужно писать аллокаторы/деаллокаторы (правда, нужно обзавестись GC), волноваться за покрытие случаев в PM, функции сравнения, печати, чтения, сериализации и т.п. тоже можно не писать, а попросить сгенерировать их в deriving. Теоретически, из задания ADT автоматически выводится свёртка этого ADT, если с помощью ADT задаются термы некоего языка, то функции pretty_print, parse и eval выражаются через такую свёртку.

Аналог printSExp написанный с PM будет таким:

pprint :: SExp -> String
pprint (Sym "")   = "()"
pprint (Sym xs)   = xs
pprint (Cons x y) = concat ["(", pprint x, " . ", pprint y, ")"]

Если бы мы что-то забыли, то с -Wall нам бы про это написали.

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

Языки в которых есть нормальные ADT и PM я уже перечислял.

В случае динамических ЯП нужна специальная форма (и/или макрос) match (например, http://docs.racket-lang.org/reference/match.html), но вот она как раз не может предоставит гарантии покрытия (fixme?) - можно забывать clasuses сколько угодно и натыкаться на это только во время выполнения программы.

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

Аналог printSExp написанный с PM будет таким

Они ещё хреново-рекурсивные оба (как и gcSExp).

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

Вот, например, BNF для s-выражений

Бинарные деревья, с помощью параметрических ADT можно делать обобщённые бинарные деревья, без вреда для runtime (чего-то подобного в си добиться трудно, разве что макросы вроде тех что в queue (3), или шаблоны в C++).

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

Уж как-нибудь сам разберусь, без священных писаний - что и чем считать

Удачи.

Интересно, чем вызвана столько агрессивная реакция

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

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

очень интересно. nop в питоне из коробки

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