Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Здравствуйте, Greeter, Вы писали:
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Что конкретно вам непонятно?
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, Greeter, Вы писали:
G>>Или не до конца понимаете в программировании?
D>Монады. Несколько раз подкатывал, без толку.
Ну и нафиг он нужен? По ссылке не ходил, надоело уже. Из последнего прочитанного смутно помню, что это просто две функции специального вида, далеко не самого сложного в мире. И что с ними носятся как с писаной торбой?
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, gandjustas, Вы писали:
D>>>Монады. Несколько раз подкатывал, без толку.
G>>Да это же элементарно, всего лишь моноид в категории эндофункторов
D>Ну и нафиг он нужен? По ссылке не ходил, надоело уже. Из последнего прочитанного смутно помню, что это просто две функции специального вида, далеко не самого сложного в мире. И что с ними носятся как с писаной торбой?
Монады — паттерн проектирования. Примерно такой же, как все 23 в GOF. Только более функциональный.
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, gandjustas, Вы писали:
G>>Монады — паттерн проектирования.
D>Ага, вот оно что!.. Блин, ну и что ты сделал? Теперь придётся (n+1)-й раз читать.
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, gandjustas, Вы писали:
G>>Монады — паттерн проектирования.
D>Ага, вот оно что!.. Блин, ну и что ты сделал? Теперь придётся (n+1)-й раз читать.
попробуйте прочитать http://habrahabr.ru/post/151703/
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Решить с помощью map не выйдет. так как в результате получим Maybe<Maybe<B>>, поэтому нам нужна еще одна функция
static class Monad {
В скале это называется flatMap() в дополнение к map(). И что, это и есть монада? Господи, да в скаловских коллекциях функций мильярд, на каждую придумывать по параллельному термину — озвереешь.
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Greeter, Вы писали:
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Надо читать вменяемую литературу, типа Гарсиа-Молина et al. Там подробно разжёвывается, как работает оптимизатор, и из каких кусочков он собирает план исполнения запроса.
А про "пц быстрое, и при этом устойчивое" — это городская легенда.
Т.е. есть и быстрее Оракла, и устойчивее Оракла. А уж стоимость эксплуатации Оракла и вовсе как у Боинга. А вот маркетинг у Оракла правильный, поэтому все думают, что Оракл лучше всех.
На самом деле, самая крутая RDBMS — это DB2. Потом идёт MS SQL, потом Оракл, потом Postgres, а уж потом, с большим-большим отрывом, все остальные.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, welltyped2, Вы писали:
W>>попробуйте прочитать http://habrahabr.ru/post/151703/
D>
D>Решить с помощью map не выйдет. так как в результате получим Maybe<Maybe<B>>, поэтому нам нужна еще одна функция
D>static class Monad {
D>В скале это называется flatMap() в дополнение к map(). И что, это и есть монада? Господи, да в скаловских коллекциях функций мильярд, на каждую придумывать по параллельному термину — озвереешь.
flatMap это только для списков. Если абстрагировать его на любой F[A] и добавить pure, то в итоге можно получить то что есть в scalaz
trait Monad[F[_]] extends Applicative[F] with Bind[F]
где как раз Bind дает
def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
а Applicative
def pure[A](a: => A): F[A]
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, welltyped2, Вы писали:
W>flatMap это только для списков. Если абстрагировать его на любой F[A] и добавить pure, то в итоге можно получить то что есть в scalaz
Прикольно, но опять возвращается вопрос: нафиг оно надо? Мне и flatMap-то раз в сто лет пригождается.
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Надо читать вменяемую литературу, типа Гарсиа-Молина et al. Там подробно разжёвывается, как работает оптимизатор, и из каких кусочков он собирает план исполнения запроса. Петров-Водкин Гарсиа-Молина? Есть совет попроще — сходить в гитхаб и посмотреть на исходники PostgreSQL. А потом задать полагающиеся вопросы джентельменам на форуме.
S>На самом деле, самая крутая RDBMS — это DB2. Потом идёт MS SQL, потом Оракл, потом Postgres, а уж потом, с большим-большим отрывом, все остальные.
Как это вы "крутость" так опередили? Почему это MS SQL опередил oracle, а PostgreSQL отстает от оракла, а на вершине всего этого DB2 UDB?
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, welltyped2, Вы писали:
W>>flatMap это только для списков. Если абстрагировать его на любой F[A] и добавить pure, то в итоге можно получить то что есть в scalaz
D>Прикольно, но опять возвращается вопрос: нафиг оно надо? Мне и flatMap-то раз в сто лет пригождается.
Оно нужено когда у вас для F[A] нужно использовать функцию А => F[B]
Если в сто лет нужен flatMap значит в сто лет у вас появляется функция вида A => List[B] применяемая к List[A]
Представте такую ситуация, есть три функции
getA:: Int => Option[A]
getB:: A => Option[B]
getC:: B => Option[C]
вам нужно получить C. Как вы запишите код с этими функциями?
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>>>И что с ними носятся как с писаной торбой? F>>потому что всё есть монада D>Звучит в духе этого, который "я есмь сущий", с которым тоже все носятся.
именно так оно и происходит
...coding for chaos...
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, welltyped2, Вы писали:
W>Представте такую ситуация, есть три функции W>getA:: Int => Option[A] W>getB:: A => Option[B] W>getC:: B => Option[C] W>вам нужно получить C. Как вы запишите код с этими функциями?
в скале Option — тоже коллекция:
scala> class A; class B; class C
defined class A
defined class B
defined class C
scala> def getA(i: Int) = Some(new A)
getA: (i: Int)Some[A]
scala> def getB(a: A) = Some(new B)
getB: (a: A)Some[B]
scala> def getC(b: B) = Some(new C)
getC: (b: B)Some[C]
scala> def getA(i: Int): Option[A] = Some(new A)
getA: (i: Int)Option[A]
scala> def getB(a: A): Option[B] = Some(new B)
getB: (a: A)Option[B]
scala> def getC(b: B): Option[C] = Some(new C)
getC: (b: B)Option[C]
scala> getA(0).flatMap(a => getB(a).flatMap(b => getC(b)))
res0: Option[C] = Some(C@a87f680)
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, welltyped2, Вы писали:
W>>Представте такую ситуация, есть три функции W>>getA:: Int => Option[A] W>>getB:: A => Option[B] W>>getC:: B => Option[C] W>>вам нужно получить C. Как вы запишите код с этими функциями?
D>в скале Option — тоже коллекция:
D>
scala>> class A; class B; class C
D>defined class A
D>defined class B
D>defined class C
scala>> def getA(i: Int) = Some(new A)
D>getA: (i: Int)Some[A]
scala>> def getB(a: A) = Some(new B)
D>getB: (a: A)Some[B]
scala>> def getC(b: B) = Some(new C)
D>getC: (b: B)Some[C]
scala>> def getA(i: Int): Option[A] = Some(new A)
D>getA: (i: Int)Option[A]
scala>> def getB(a: A): Option[B] = Some(new B)
D>getB: (a: A)Option[B]
scala>> def getC(b: B): Option[C] = Some(new C)
D>getC: (b: B)Option[C]
scala>> getA(0).flatMap(a => getB(a).flatMap(b => getC(b)))
D>res0: Option[C] = Some(C@a87f680)
D>
Вот за этим и нужен flatMap. Представте теперь что все функции возвращают не Option а Future, ваш код получения C при этом не измненится.
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Нахлобуч, Вы писали:
Н>Не совсем программирование, но все же. Не могу понять, в чем такая прелесть vi/emacs (если пользователи не врут).
Всё просто. Они работают, а другие ИДЕ посто жрут процессорное время.
Sic luceat lux!
Re[13]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, welltyped2, Вы писали:
W>>Представте теперь что все функции возвращают не Option а Future, ваш код получения C при этом не измненится.
D>Future — тоже хороший пример. А ещё какой-нибудь есть?
Например можно посмотреть какие монады есть в haskell. Логирование, побочные эффекты, парсеры и т.д.
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Монады. Несколько раз подкатывал, без толку.
А что там понимать... Абстрактная алгебра и немножко теоркат. (Тот самый моноид в эндофункторах).
Практические фичи для пользователя
1) Тип-обёртка — позволяет изолировать данные, чтобы случайно что-нибудь неправильное не сделать. Самый яркий пример — IO. Внутри всё сводится к unsafePerformIO, но это секрет!
2) Унифицированный контейнер — работа с содержимым выполняется через map и filter (foreach и if, говоря императивно).
2а) Не надо специально отслеживать пустые контейнеры; не надо придумывать сигнальные значения — достаточно вернуть пустой или единичный контейнер
2б) Некоторые алгоритмы выглядят одинаково для разных контейнеров (foreach же!)
3) Специфичные функции (чтение-запись состояния, например) укладываются в этот же синтаксис
3а) Это позволяет писать код в разном сахаре — set comprehension (в хаскелле — только list comprehension, а в гофре и идрисе и внезапно питоне — для любых типов), do-нотация, конвееры
3б) А также легко сочетать монады, применяя трансформеры
лунапарк — исходная монада
лбс = сБлекджеком(соШлюхами(лунапарк))
блекджек(лбс) — доступ к специфике верхнего уровня
шлюхи(безБлекджека(лбс)) — доступ к специфике внутреннего уровня
аттракцион <- лбс
аттракцион <- безБлекджека(лбс)
аттракцион <- безШлюх(безБлекджека(лбс))
аттракцион <- лунапарк
А моноиды и эндофункторы — это теоретический базис и гарантия того, что 0*X = X*0 = 0, 1*X = X*1 = 1, X*Y*Z = X*Y*Z (скобки расставьте по вкусу)
Перекуём баги на фичи!
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Kernan, Вы писали:
K>Всё просто. Они работают, а другие ИДЕ посто жрут процессорное время.
Я не представляю, как они там работают. Возможно, в этих ваших хипстерских Руби и Питонах вместо интеллисенса канает банальное автодополнение с выбором из списка всех идентификаторов в файле/проекте и скорость работы находится в прямой зависимости от умения виртуозно перемещать строки и писать макросы, но как-то меня гложут сомнения в том, что IDE может сколь-нибудь заметно влиять на скорость набора текста.
HgLab: Mercurial Server and Repository Management for Windows
Re[14]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, welltyped2, Вы писали:
W>>Представте теперь что все функции возвращают не Option а Future, ваш код получения C при этом не измненится.
D>Future — тоже хороший пример. А ещё какой-нибудь есть?
Option\Maybe
Lazy
Exception
List
Parser
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Прикольно, но опять возвращается вопрос: нафиг оно надо? Мне и flatMap-то раз в сто лет пригождается.
Просто посмотри, как сделаны всякие монадические сущности. Вот скажем промисы в js очень хорошо показывают, что к чему.
Идейка, в кратце очень простая. Проблема в том, что монады везде описывают, что это такое, но практически нигде не пишут, для чего это надо и как с их помощью решать обыденные задачи.
Вот задачи:
есть два числа который надо сложить
решение
c = a + b.
есть три числа, два есть сейчас и одно принесет резиновая Зина, их надо сложить
решение
d = a + b + c.
есть четыре числа, два есть сейчас, одно принесет резиновая Зина, одно может через год, а может быть, через два, может быть подскажет тётя Зина из магазина, их надо сложить
решение
r = a + b + c + d
есть пять чисел, два есть сейчас, одно принесет резиновая Зина, одно может через год, а может быть, через два, может быть подскажет тётя Зина из магазина, одно это сумма потерь какой нибудь разини, их надо сложить
решение
r = a + b + c + d
Если добавить типы, то окажется ,что в первом случае числа просто инты, во втором добавляется M<int>, в третьем M1<int>, в четвертом M2<int>
В с++ ты вспотеешь описывать классы и перегрузку операторов для всех возможных комбинаций типов. Если в лоб, то в императивной реализации надо будет понавыдумать целый вагон способов диспетчерзации для случаев " может через год, а может быть, через два, может быть".
Для чего ?
Для того, что бы по прежнему сложить два числа.
И вот для того, что бы числа можно было просто складывать, и не возиться при этом с указателями, конструкторами, деструкторами и смартпоинтерами, люди придумали монады.
Итого: "Monad — just works"
Т.е. экземпляр монадического типа это не само значение, а способ его получения.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, neFormal, Вы писали:
К>>Самый яркий пример — IO. Внутри всё сводится к unsafePerformIO, но это секрет! F>т.е. я порчу себе карму и даже не знаю об этом?!
Ты не портишь себе карму, потому что операции ввода-вывода совершаются в должное время в должном месте в должном порядке.
За должный порядок отвечает реализация монады IO, не позволяющая компилятору ни пропускать, ни дублировать, ни перетасовывать операции.
Перекуём баги на фичи!
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
D>>Монады. Несколько раз подкатывал, без толку. К>А что там понимать... Абстрактная алгебра и немножко теоркат. (Тот самый моноид в эндофункторах).
Я вот тоже пытался их понять, читал разные статьи, но все равно не понимаю. С практической, низкоуровневой такой точки зрения... (что уж поделаешь, я начинал с Си и Ассемблера, и мышление заточено именно на то — а как оно в процессоре-то будет выполняться?)
Если говорить об ФП, то я понимаю что такое функция высшего порядка, это легко. Зачем нужно функцию передавать в другую функцию. Что такое частичное применение функций. Как работают замыкания. Как функция может возвратить другую функцию. Это простые концепции, с ними все ок, причем достаточно ясно как оно реализуется на низком уровне.
А монада — что она такое? (я даже не могу идентифицировать, это структура данных, управляющий оператор или что-то еще?)
Вот есть допустим язык Си (специально не С++). Мы можем (пусть даже слегка изменив синтаксис языка) внедрить туда монады, что это будет и какая от них будет польза?
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>На самом деле, самая крутая RDBMS — это DB2.
В этом её беда. Она прощает столько тупости и с успехом нивелирует самые кривые руки. Но в конце концов безнаказанная тупость и бесконечная кривизна берут своё.
Если нам не помогут, то мы тоже никого не пощадим.
Re[15]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, welltyped2, Вы писали:
D>>Future — тоже хороший пример. А ещё какой-нибудь есть? W>Например можно посмотреть какие монады есть в haskell. Логирование, побочные эффекты, парсеры и т.д.
Спасибо, вот теперь понял, зачем оно.
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>>>Самый яркий пример — IO. Внутри всё сводится к unsafePerformIO, но это секрет! F>>т.е. я порчу себе карму и даже не знаю об этом?! К>Ты не портишь себе карму, потому что операции ввода-вывода совершаются в должное время в должном месте в должном порядке.
Т.е. это все же safePerformIO, а не unsafe.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
I>А монада — что она такое? (я даже не могу идентифицировать, это структура данных, управляющий оператор или что-то еще?)
Как выше сказали, это скорее идея, паттерн проектирования. Но в приложении к программированию это обычно параметризованный тип с определенными свойствами (ибо это самый прямой перевод понятия функтора из теории категорий, а монада там и есть функтор с парой естественных преобразований).
I>Вот есть допустим язык Си (специально не С++). Мы можем (пусть даже слегка изменив синтаксис языка) внедрить туда монады, что это будет и какая от них будет польза?
Нужны хотя бы шаблоны, чтобы делать параметризованные типы. А чтобы в применении всего этого был толк, хорошо бы иметь средство абстрагирования еще одним уровнем выше, чтобы писать код "для любой переданной монады М сделать то-то", работающий с разными экземплярами монад. В терминах С++ — шаблон с параметром-шаблоном.
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, a_g_99, Вы писали:
S>>Надо читать вменяемую литературу, типа Гарсиа-Молина et al. Там подробно разжёвывается, как работает оптимизатор, и из каких кусочков он собирает план исполнения запроса. __>Петров-Водкин Гарсиа-Молина? Есть совет попроще — сходить в гитхаб и посмотреть на исходники PostgreSQL. А потом задать полагающиеся вопросы джентельменам на форуме.
Это путь хардкорных джедаев. Для обычных людей такой сложности обычно начинать читать с исходников более чем бесполезно. С Гарсиа-Молина практически полностью устраняется риск "прочитал — не понял". Опять же, можно сравнить объёмы текста там и там.
S>>На самом деле, самая крутая RDBMS — это DB2. Потом идёт MS SQL, потом Оракл, потом Postgres, а уж потом, с большим-большим отрывом, все остальные. __>Как это вы "крутость" так опередили? Почему это MS SQL опередил oracle, а PostgreSQL отстает от оракла, а на вершине всего этого DB2 UDB?
Это мой личный рейтинг.
DB2 — за значительный вклад в развитие реляционных СУБД и несомненные успехи. На tpc-c они были последними, кто выиграл перформанс "честным" образом, а не тупо наращивая стоимость системы.
MS SQL — за минимальные потребности в обслуживании, высокую стабильность, и хороший фичесет. Например, в отличие от Оракла, он умеет и версионную конкурентность, и блокировочную.
Postgres — просто самый достойный из бесплатных движков, но, простите, я не верю, что некоммерческое решение может догнать полноценное коммерческое.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Postgres — просто самый достойный из бесплатных движков, но, простите, я не верю, что некоммерческое решение может догнать полноценное коммерческое.
Он не просто догоняет, а перегоняет.
Во-первых, по уровню обслуживания он ещё проще MSSQL — тупо воткнуть пакет и оно работает, всякий тюнинг обычно только ухудшает ситуацию.
Во-вторых, по общему уровню фич он уже лучше Оракла (скажем, есть транзакционный DML) и не хуже MSSQL. В некоторых областях Postgres вообще лучше всех — в GIS, например.
В-третьих, он нифига не некоммерческий. На продаже PostgreSQL и его разработке живут множество компаний. Мы сейчас занимаемся продажей Infrastructure As A Service и один из наших клиентов занимается запуском кластеров PostgreSQL на нашей инфраструктуре — за это они получают весьма неплохие деньги. На эти деньги они дописывают нужные им фичи.
Sapienti sat!
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Kernan, Вы писали:
Н>>Не совсем программирование, но все же. Не могу понять, в чем такая прелесть vi/emacs (если пользователи не врут). K>Всё просто. Они работают, а другие ИДЕ посто жрут процессорное время.
да и пусть жрут, компьютер железный. зато не надо лисп изучать чтобы размер табуляции настроить
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
В истории я профан, тут конечно мнение историков более важно чем мое.
S>DB2 — за значительный вклад в развитие реляционных СУБД и несомненные успехи. На tpc-c они были последними, кто выиграл перформанс "честным" образом, а не тупо наращивая стоимость системы.
А как выиграть "честным образом"? Напр. в тестах по производительности или произв./цена первое место занимает Oracle.
S>MS SQL — за минимальные потребности в обслуживании, высокую стабильность, и хороший фичесет. Например, в отличие от Оракла, он умеет и версионную конкурентность, и блокировочную.
А oracle умеет организовать версионную конкурентность быстро в отличии.
И вообще SQL Server почти всегда выступает в роли догоняющего по фичам относительно oracle. Хотя качество доставки фич для developers как правило выше (за что сильно ценю mssql).
C>Он не просто догоняет, а перегоняет.
Я бы все-таки сказал что все-таки уровень производительности PostgreSQL на уровне SQL Server (возможно выше/чуть выше — мое сравнение показывает примерно равные результаты). К тому же он показывает ровные результаты по perf на разных ОС (в моем случае на Windows и OS X) в отличие от Oracle который красиво работает только на линуксах и солярке (и желательно под спарк ).
C>В некоторых областях Postgres вообще лучше всех — в GIS, например.
postGIS и pgRouting действительно делают PostgreSQL лидером этого сегмента. В oracle тоже есть некоторая поддержка spatial data, но на мой взгялд не такая гибкая как в postgre.
C>В-третьих, он нифига не некоммерческий. На продаже PostgreSQL и его разработке живут множество компаний.
Главная EnterpriseDB, которая продает extended tools & платный саппорт. Они же собирают каждый новый релиз. Т.е. это не просто полузабытая народная система, есть компании где люди профессионально развивают систему.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Нахлобуч, Вы писали:
Н>Возможно, в этих ваших хипстерских Руби и Питонах вместо интеллисенса канает банальное автодополнение
по сути да. если нет синтаксического оверхеда™, то от ide можно отказаться в пользу чего-то легковесного.
Н>но как-то меня гложут сомнения в том, что IDE может сколь-нибудь заметно влиять на скорость набора текста.
ещё как влияет. например, java-код в ide набирается очень быстро за счёт хорошего автокомплита.
это достоинство ide и недостаток java.
...coding for chaos...
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
I>>А монада — что она такое? (я даже не могу идентифицировать, это структура данных, управляющий оператор или что-то еще?)
DM>Как выше сказали, это скорее идея, паттерн проектирования. Но в приложении к программированию это обычно параметризованный тип с определенными свойствами (ибо это самый прямой перевод понятия функтора из теории категорий, а монада там и есть функтор с парой естественных преобразований).
I>>Вот есть допустим язык Си (специально не С++). Мы можем (пусть даже слегка изменив синтаксис языка) внедрить туда монады, что это будет и какая от них будет польза?
DM>Нужны хотя бы шаблоны, чтобы делать параметризованные типы. А чтобы в применении всего этого был толк, хорошо бы иметь средство абстрагирования еще одним уровнем выше, чтобы писать код "для любой переданной монады М сделать то-то", работающий с разными экземплярами монад. В терминах С++ — шаблон с параметром-шаблоном.
Да вот здесь например статья про монады и прочее. Можно понять как это работает.
Понять бы, зачем это нужно. Какие задачи они решают? Они полезны только для "чисто функциональных" языков или нет?
Помогут ли они чем-то программисту в "гибридном" языке программирования (т.е. в котором есть функциональное программирование, но при этом есть все императивные возможности)
Понимание "зачем" сразу проясняет очень многие "как".
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Greeter, Вы писали:
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Понимаю все, скорее не умею пользоваться. Сюда функциональное программирование (первым в голову всегда приходит императивное решение, которое потом в муках преобразуется в что-то функциональное). Сюда же чрезмерная шаблонная магия C++. Разобраться при желании можно, но уходит гораздо больше сил.
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, a_g_99, Вы писали:
S>>DB2 — за значительный вклад в развитие реляционных СУБД и несомненные успехи. На tpc-c они были последними, кто выиграл перформанс "честным" образом, а не тупо наращивая стоимость системы. __>А как выиграть "честным образом"? Напр. в тестах по производительности или произв./цена первое место занимает Oracle.
У DB2 офигенный оптимизатор над которым работали поколения академиков. Он реально крут.
Проблема в том, что продукты IBM никогда не отличались дешевизной.
__>И вообще SQL Server почти всегда выступает в роли догоняющего по фичам относительно oracle. Хотя качество доставки фич для developers как правило выше (за что сильно ценю mssql).
Это вряд ли. По фичам последний SQL Server и Oracle примерно одинаковы. Точнее, можно найти для большинства фич примерный аналог (не обязательно работающий так же).
И вообще, с SQL Server работать не в пример удобнее, чем с Oracle.
C>>Он не просто догоняет, а перегоняет. __>Я бы все-таки сказал что все-таки уровень производительности PostgreSQL на уровне SQL Server (возможно выше/чуть выше — мое сравнение показывает примерно равные результаты). К тому же он показывает ровные результаты по perf на разных ОС (в моем случае на Windows и OS X) в отличие от Oracle который красиво работает только на линуксах и солярке (и желательно под спарк ).
Солярка и спарк — они уже давно слились...
Для Postgres вполне официально известно, что на Windows он работает заметно медленнее из-за особенностей ввода-вывода и расшареной памяти. Что для практических применений проблем не составляет — поставить любой бесплатный Линукс сейчас можно без всяких особых специальных знаний.
Насчёт скорости — у Postgres базовые запросы (типа взять строку таблицы по PK) выполняются быстрее, чем у Оракла. Причём очень заметно быстрее — у нас товарищи добиваются того, что опережают MongoDB по скорости работы с JSON'ом на слегка патченом (будет в следующей версии официально) Постргесе.
Со сложными запросами с кучей JOIN'ов всё сложнее — оптимизатор у Oracle никогда не славился особым умом и сообразительностью, так что Постгрес часто делает намного лучшие планы. С другой стороны, для Oracle можно в стратегические места поставить hint'ы и ускорить запросы, а с Postgres это существенно сложнее.
C>>В некоторых областях Postgres вообще лучше всех — в GIS, например. __>postGIS и pgRouting действительно делают PostgreSQL лидером этого сегмента. В oracle тоже есть некоторая поддержка spatial data, но на мой взгялд не такая гибкая как в postgre.
У Оракла есть отдельный пакет для geospatial баз, за кучубабла. Впрочем, он тоже сосёт. У SQL Server есть некоторые зайчатки GIS и есть пакеты третьих фирм, но по полноценности до PostGIS они не дотягивают.
C>>В-третьих, он нифига не некоммерческий. На продаже PostgreSQL и его разработке живут множество компаний. __>Главная EnterpriseDB, которая продает extended tools & платный саппорт. Они же собирают каждый новый релиз. Т.е. это не просто полузабытая народная система, есть компании где люди профессионально развивают систему.
Контрибьюторов существенно больше. Вот можно для последнего спринта посмотреть список: https://commitfest.postgresql.org/action/commitfest_view?id=20
PostgreSQL удалось повторить модель Линукса, когда многим компаниям выгодно развивать общий продукт, чем делать своё местечковое дерьмо.
Sapienti sat!
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
D>>>Монады. Несколько раз подкатывал, без толку. К>>А что там понимать... Абстрактная алгебра и немножко теоркат. (Тот самый моноид в эндофункторах).
I>Я вот тоже пытался их понять, читал разные статьи, но все равно не понимаю. С практической, низкоуровневой такой точки зрения... (что уж поделаешь, я начинал с Си и Ассемблера, и мышление заточено именно на то — а как оно в процессоре-то будет выполняться?)
А как "в процессоре будет выполняться", например, массив?
I>Если говорить об ФП, то я понимаю что такое функция высшего порядка, это легко. Зачем нужно функцию передавать в другую функцию. Что такое частичное применение функций. Как работают замыкания. Как функция может возвратить другую функцию. Это простые концепции, с ними все ок, причем достаточно ясно как оно реализуется на низком уровне.
I>А монада — что она такое? (я даже не могу идентифицировать, это структура данных, управляющий оператор или что-то еще?)
Тут есть два слоя понимания.
Первый — если не вдаваться в реализацию полиморфных функций хаскелла. Монада, как и любой другой класс — это этикетка, наклеенная на тип. "С данными этого типа можно делать то и это".
В случае монады — можно делать return, >>= и т.п. и использовать do-нотацию; с самим типом тоже кое-что можно и нужно делать: у него есть параметр.
Т.е.
class Show x where
show :: x -> String-- тип и тип, ничего особенногоclass Monad x where
return :: y -> (x y) -- опа! тип x параметризуется типом y
fail :: String -> x a -- пустая монада имеет неизвестно какой параметр, это будет уточнено при выводе типов, по месту использования
(>>=) :: (x a) -> (a -> (x b)) -> (x b) -- параметр превращается... превращается...
-- тип Either l r - если его каррировать, то полученный Either l вполне может быть монадой
-- но для разных l будут разные монадыinstance Monad (Either String) where-- это классика
return r = Right r
fail s = Left s
....
-- этого в Control.Monad.Instances, вроде бы, нет, но можно дописать руками:instance Monad (Either ()) where-- левым типом может быть только такой, для которого существуют "дефолтные" значения
....
fail s = Left ()
....
instance (Monad m) => Monad (Either (m x)) where
....
fail s = Left (fail s)
....
Второй слой — это реализация полиморфизма.
Функция, принимающая и/или возвращающая "неизвестно какую монаду", или "неизвестно какое число", или "неизвестно какое Show-совместимое значение", — имеет неявный параметр: словарь функций соответствующего класса. Это как таблица виртуальных функций, только в отрыве от значения. Таким образом, мы можем полностью абстрагироваться от того, какой тип выступил в роли монады, — до тех пор, пока не станем дёргать функции, специфичные для данного типа.
multiplyAll xs ys = do-- (Monad m, Num a) => m a -> m a -> m a
x <- xs
y <- ys
return x*y
multiplyAll' xs ys = [x*y | x<-xs, y<-ys] -- (Num a) => [a] -> [a] -> [a], потому что дёрнули list comprehension
multiplySome' xs ys = do-- [Int] -> [Int] -> [Int], потому что length
x <- xs
y <- ys
return x*y*(length xs)
I>Вот есть допустим язык Си (специально не С++). Мы можем (пусть даже слегка изменив синтаксис языка) внедрить туда монады, что это будет и какая от них будет польза?
В сях от монад толку не будет — слишком далеко система типов сей от системы типов хаскелла. А руками её воспроизводить — мрачное дело. Это на порядок громоздче, чем ООП. (Ком-серверы на сях видел? Умножь страхолюдность на десять).
Перекуём баги на фичи!
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
I>Понять бы, зачем это нужно. Какие задачи они решают? Они полезны только для "чисто функциональных" языков или нет? I>Помогут ли они чем-то программисту в "гибридном" языке программирования (т.е. в котором есть функциональное программирование, но при этом есть все императивные возможности)
Скажем так: в чистых ФЯ (особенно ленивых) они очень-очень нужны, чтобы структурировать код и не превращать его в месиво. В том же Clean, где монад нет, их недостаток весьма остро ощущается, когда пытаешься что-то делать.
В гибридных языках обычно можно обойтись без них, как показывает практика окамла и скалы. Но когда они есть (и особенно когда в языке есть их синтаксическая поддержка в виде do или for нотации), они позволяют в том числе вводить новые управляющие конструкции, вроде async, исключений, продолжений и т.д. Можно не ждать, пока авторы языка додумаются их включить в язык, а делать библиотечно. Например, основанные на монадах зеленые потоки с кооперативной многозадачностью применялись в окамле для создания неблокирующихся веб-серверов за много лет до того, как появилась Node.js и все стали дро возбуждаться на эту тему.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Cyberax, Вы писали:
C>У DB2 офигенный оптимизатор над которым работали поколения академиков. Он реально крут.
Чем же он офигенный ? Каждый производитель это твердит. "У нас офигенный оптимизатор!!!".
C>Проблема в том, что продукты IBM никогда не отличались дешевизной.
40к за we, от 80k до 250k за ese. цены вполне сравнимые с oracle.
>Это вряд ли. По фичам последний SQL Server и Oracle примерно одинаковы. Точнее, можно найти для большинства фич примерный аналог (не обязательно работающий так же).
Да куда уж там "вряд ли". Напр. MINUS/EXCEPT. Насколько я помню EXCEPT появился в 2к5, а MINUS был уж не помню с какой версии (в 8-ке кажется точно был). Опять же всякие гриды/кластеринг, которые появились у ms сильно позже. И где кстати MS IMDB совместимая c mssql? Ее нет а у oracle timesten.
C>И вообще, с SQL Server работать не в пример удобнее, чем с Oracle.
С этим невозможно не согласиться.
C>Солярка и спарк — они уже давно слились...
Да посмотрите вы тесты TPC-C. Они живее всех живых и чемпионы производительности.
C>Для Postgres вполне официально известно, что на Windows он работает заметно медленнее из-за особенностей ввода-вывода и расшареной памяти. Что для практических применений проблем не составляет — поставить любой бесплатный Линукс сейчас можно без всяких особых специальных знаний.
Это не проблема PG, а ОС-производительности. Последние версии (с 9.1) на win могут работать так же быстро как и на linux если win имеет больше памяти.
C>Со сложными запросами с кучей JOIN'ов всё сложнее — оптимизатор у Oracle никогда не славился особым умом и сообразительностью, так что Постгрес часто делает намного лучшие планы. С другой стороны, для Oracle можно в стратегические места поставить hint'ы и ускорить запросы, а с Postgres это существенно сложнее.
Я все-таки вижу главное преимущества Postgres здесь не в скорости by design (все равно oracle придет первым к финишу при "правильной конфигурации"), а в открытом исходном коде и возможности "ускоряться" под свои задачи с помощью собственных модификаций.
C>У Оракла есть отдельный пакет для geospatial баз, за кучубабла. Впрочем, он тоже сосёт. У SQL Server есть некоторые зайчатки GIS и есть пакеты третьих фирм, но по полноценности до PostGIS они не дотягивают.
Нет не сосет. Вы похоже просто не пользовались им профессионально и не знаете его возможностей. А пользовался и пользуюсь и знаю. В любом случае PostGIS отличный package.
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
I>Понять бы, зачем это нужно. Какие задачи они решают? Они полезны только для "чисто функциональных" языков или нет? I>Помогут ли они чем-то программисту в "гибридном" языке программирования (т.е. в котором есть функциональное программирование, но при этом есть все императивные возможности)
Все императивные возможности есть в чистых ФЯ. Они отличаются от ФЯ императивных, не отсутствием возможностей, а тем, что упорядоченность действий является явной, а не неявной.
Монады для этой "явной упорядоченности" не обязательны.
Чистота функций гарантируется по построению. Начинается все с базовой иммутабельности. Однако, изменяемые ссылки нужны и мы добавляем в чистый язык соотвествующие функции:
readMutVar :: MutVar a -> a
writeMutVar :: MutVar a -> a -> ()
Так делается в SML и в этот момент эта "чистота по построению" теряется. Т.е. в случае "в основном иммутабельного" языка вроде ML это решение уровня библиотеки (по большому счету, некоторая модификация языка нужна — неявный runIO для main).
Мы же сейчас строим чистый язык, так что этот вариант для нас не подходит — нам нужна другая библиотека.
Делаем функции работы с изменяемыми ссылками чистыми:
readMutVar :: MutVar a -> State -> (State, a)
writeMutVar :: MutVar a -> a -> State -> State
Все, теперь сайд-эффект обозначен как "изменение" некоторого фиктивного параметра State — т.е. сайд-эффектом он быть перестал, ссылочная прозрачность не нарушается.
Но у нас все еще есть проблема: из таких функций можно собрать функцию, которая чистой не является, ссылочную прозрачность нарушает.
Как же быть? Если в языке есть уникальные типы — мы просто делаем State уникальным:
readMutVar :: MutVar a -> *State -> (*State, a)
writeMutVar :: MutVar a -> a -> *State -> *State
Все, теперь "нечистая" комбинация таких функций просто не пройдет тайпчек.
Ну а что делать, если у нас уникальных типов нет?
Нам поможет другой аспект типобезопасности — обычная инкапсуляция.
readMutVar :: MutVar a -> State -> (State, a)
-- слегка поправим сигнатуру:
writeMutVar :: MutVar a -> a -> State -> (State,())
-- теперь сходство становится очевидным:newtype IO a = IO (State -> (State, a))
readMutVar :: MutVar a -> IO a
writeMutVar :: MutVar a -> a -> IO ()
Теперь реализуем комбинаторы для этих функций, которые сохраняют уникальность State, и экспортируем их, а конструктор IO не экспортируем.
Вот теперь любая функция у нас чистая по построению (пока мы не нарушим инкапсуляцию IO).
Как видите, мы обошлись без монад, поэтому я и говорил, что они не нужны. Но желательны. Для чего? Для уменьшения писанины.
Выше я упоминал "безопасные комбинаторы". Для удобства их нужно много, а минимальный их набор — две штуки. Так вот, набор удобных комбинаторов, выражаемых в терминах этих базовых двух — одинаков для всех монад. А описываемое выше протаскивание параметра-состояния — это монада state. Поэтому вместо отдельной инфраструктуры построения безопасных (с точки зрения ссылочной прозрачности) мутирующих функций нам нужно просто реализовать инстанс класса Monad для IO (две функции). Плюс к тому, для монад делается синтаксический сахар, который маскирует всю эту "обвязку" из комбинаторов.
Ну и класс Monad — это только одно из многих доступных решений для безопасного комбинирования действий. В хаскеле сейчас "из коробки" есть две иерархии таких интерфейсов для комбинации вычислений Functor/Applicative/Monad и (менее популярные) стрелки.
Т.е. смысл монад, во-первых, в повторном использовании кода. Одна и та же функция для монады IO выполнит список действий поочередно, вычислит декартово произведение списка списков для list, проверит успешность всех вычислений для maybe и т.д.
А во-вторых это средство для разделения кода на некие "основные действия" и "обвязку", от которой можно абстрагироваться.
В третьих, это способ уменьшить порог вхождения для встроенного языка.
Дело в том, что инстансы класса Monad должны выполнять законы.
return >=> f === f
f >=> return === f
(f >=> g) >=> h === f >=> (g >=> h)
Т.е. такие свойства комбинаций функций, которые выполняются независимо от того, что это за монада и, соответственно, что это за встроенный язык — для недетерминированных вычислений или для построения парсеров.
Таким образом, знающий монады знает не только большую часть функций из всех монадических встроенных языков (включая еще не написанные), но и какими свойствами обладают их комбинации, и как их можно переписать не меняя смысла, т.е. отрефакторить. В данном случае монады это ответ на часто обсуждаемую проблему встроенных языков: "встроенный язык нужно проектировать, реализовывать, поддерживать. Каждый встроенный язык программисту-пользователю нужно изучать заново". Тут большая часть первой работы (для разработчика встроенного языка) уже проделана теми, кто написал стандартную библиотеку, а большую часть работы по освоению языка нужно проделать только один раз для любого числа встроенных языков.
В-четвертых, монады позволяют модульным образом собирать комбинации из таких монадических языков, подключая нужные фичи и отключая ненужные с помощью трансформеров.
Поэтому монады имеют смысл в языке вне зависимости от того, чистый (декларативный) это язык или императивный.
Однако, в большинстве гибридных языков, монадами пользоваться неудобно (из-за слабости реализации функциональных фич и/или системы типов), так что используются они ограниченно либо вовсе не используются.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, a_g_99, Вы писали:
C>>У DB2 офигенный оптимизатор над которым работали поколения академиков. Он реально крут. __>Чем же он офигенный ? Каждый производитель это твердит. "У нас офигенный оптимизатор!!!".
Я видел примеры, когда DB2 делал запросы во много раз эффективнее Оракуловых.
C>>Проблема в том, что продукты IBM никогда не отличались дешевизной. __>40к за we, от 80k до 250k за ese. цены вполне сравнимые с oracle.
Её ещё нужен AIX и POWER
>>Это вряд ли. По фичам последний SQL Server и Oracle примерно одинаковы. Точнее, можно найти для большинства фич примерный аналог (не обязательно работающий так же). __>Да куда уж там "вряд ли". Напр. MINUS/EXCEPT. Насколько я помню EXCEPT появился в 2к5, а MINUS был уж не помню с какой версии (в 8-ке кажется точно был). Опять же всякие гриды/кластеринг, которые появились у ms сильно позже. И где кстати MS IMDB совместимая c mssql? Ее нет а у oracle timesten.
Так ещё MSSQL 2000 вспомни. Понятно, что многие фичи у МС позднее появились, но таки появились. Насчёт IMDB — есть xVelocity.
C>>Солярка и спарк — они уже давно слились... __>Да посмотрите вы тесты TPC-C. Они живее всех живых и чемпионы производительности.
В морг, в морг. Тесты TPC-C нынче вообще нерелевантны.
C>>Со сложными запросами с кучей JOIN'ов всё сложнее — оптимизатор у Oracle никогда не славился особым умом и сообразительностью, так что Постгрес часто делает намного лучшие планы. С другой стороны, для Oracle можно в стратегические места поставить hint'ы и ускорить запросы, а с Postgres это существенно сложнее. __>Я все-таки вижу главное преимущества Postgres здесь не в скорости by design (все равно oracle придет первым к финишу при "правильной конфигурации"), а в открытом исходном коде и возможности "ускоряться" под свои задачи с помощью собственных модификаций.
Модификации обычно делать — это последняя возможность. Хотя расширяемость с помощью плугинов у PSQL сильно неплохая.
C>>У Оракла есть отдельный пакет для geospatial баз, за кучубабла. Впрочем, он тоже сосёт. У SQL Server есть некоторые зайчатки GIS и есть пакеты третьих фирм, но по полноценности до PostGIS они не дотягивают. __>Нет не сосет. Вы похоже просто не пользовались им профессионально и не знаете его возможностей. А пользовался и пользуюсь и знаю. В любом случае PostGIS отличный package.
Пользовался, плевался, перешёл на PostGIS. Оракл не мог нормально даже пересечения фигур делать — sdo_intersection тормозил минутами на таблицах с сотнями записей
Sapienti sat!
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Т.е. это все же safePerformIO, а не unsafe.
Ну так внутри кондома-то всегда находится весьма небезопасный х. Это не делает секс в кондоме небезопасным.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну, я готов дать разъяснения, если есть конкретные вопросы.
Для этого нужно знать (и судя по всему весьма неплохо знать) SML, Haskell и т.д. Причем, как я понимаю, мало прочитать книжку — нужно на нем что-то написать реальное.
Вы можете объяснить что такое монады, используя базовую терминологию языков типа C++/C#/Java? (можно вводить новые понятия, но каждое понятие должно быть подкреплено реальными практическими примерами)
ЗЫ. можно даже создать отдельную тему здесь. Вопрос-то как видим популярный.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Ну так внутри кондома-то всегда находится весьма небезопасный х. Это не делает секс в кондоме небезопасным.
...хватит уже умничать, Рваная резинка! Маленьким мальчикам пора спать!!!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, D. Mon, Вы писали:
DM>>Т.е. это все же safePerformIO, а не unsafe. S>Ну так внутри кондома-то всегда находится весьма небезопасный х. Это не делает секс в кондоме небезопасным.
Не-не-не, ты в католической школе что-ли учился? Небезопасность заключается не в самом х, в нем нет ничего плохого, а в беспорядочном его применении.
Возвращаясь от метафоры обратно, если у нас есть такой условно код:
x = readInt();
y = readInt();
return f(x,y);
То в ленивом языке порядок вычисления x и y крайне сложно предсказуем (зависит от того, как они будут использованы в f), и если readInt() читает числа извне, то что окажется в x, а что в y — не угадаешь. Т.е. просто так пользоваться IO в ленивом языке нельзя. А вот если обернуть его в монаду, она заставляет выполняться все IO операции в четко определенном порядке, что даже в условиях ленивости делает IO безопасным — разумным и предсказуемым. Проблема с unsafePerformIO в том, что она прячет IO операцию в чистое значение, что приводит опять к непредсказуемому порядку выполнения таких операций, отсюда и небезопасность. Т.е. проблема не в самом х IO, а в беспорядочном неупорядоченном его применении.
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
I>Вы можете объяснить что такое монады, используя базовую терминологию языков типа C++/C#/Java? (можно вводить новые понятия, но каждое понятие должно быть подкреплено реальными практическими примерами)
Я начну с примеров.
int x,y;
x = 1;
y = x;
x = 2;
return x + y;
Вот это была монада State.
string s = readLine();
writeLine(s);
Вот это была монада IO.
int x,y;
x = 1;
string s = readLine();
y = x;
x = 2;
writeLine(s);
return x + y;
А тут был применен трансформер монад StateT, соединивший две монады в одну.
В языках вроде C++ и Java ряд монад уже встроены. А хаскель просто такой примитивный и бедный язык, что там их забыли включить, приходится библиотечно решать те же задачи.
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>В языках вроде C++ и Java ряд монад уже встроены. А хаскель просто такой примитивный и бедный язык, что там их забыли включить, приходится библиотечно решать те же задачи.
Ну вы же сами прекрасно понимаете что это не монады
Ладно, на следующей неделе я постараюсь собрать всю инфу по монадам и сделаю отдельную тему, в которой изложу свое (возможно ошибочное) видение. А вы, если захотите, меня поправите
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, senglory, Вы писали:
S>Например, Sharepoint. Порой кажется, что его писала команда шизофреников, к-рым поставили задачу повыделываться.
Все проще
1) Писали индусы. Реально видел фотку Office Team в 2009 году — одни индусы.
2) Очень древний код. Некоторые вещи достались в наследство с 1998-2001 года.
3) У руля Product Group с 2003 года стоят маркетологи, поэтому качество и полезность уступают "потенциальной продаваемости".
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>В языках вроде C++ и Java ряд монад уже встроены. А хаскель просто такой примитивный и бедный язык, что там их забыли включить, приходится библиотечно решать те же задачи.
Неправда. Монада появляется тогда, когда неявные вещи становятся явными. Это сильно улучшает локальность и позволяет с меньшими затратами анализировать код.
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, senglory, Вы писали:
S>>Например, Sharepoint. Порой кажется, что его писала команда шизофреников, к-рым поставили задачу повыделываться.
G>Все проще G>1) Писали индусы. Реально видел фотку Office Team в 2009 году — одни индусы. G>2) Очень древний код. Некоторые вещи достались в наследство с 1998-2001 года. G>3) У руля Product Group с 2003 года стоят маркетологи, поэтому качество и полезность уступают "потенциальной продаваемости".
Только как понятийный аппарат (все эти service applications и services, SPSite к-рый называется site collection, а SPWeb — это сайт и т.п. муть ЛСДшная) влияет на продаваемость? Я вот ника кне догоню, нафига вводить раздельно понятия сервисов и приложений, когда сам ASP.NET прекрасно и без этого огорода слов живет и работает?
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, senglory, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, senglory, Вы писали:
S>>>Например, Sharepoint. Порой кажется, что его писала команда шизофреников, к-рым поставили задачу повыделываться.
G>>Все проще G>>1) Писали индусы. Реально видел фотку Office Team в 2009 году — одни индусы. G>>2) Очень древний код. Некоторые вещи достались в наследство с 1998-2001 года. G>>3) У руля Product Group с 2003 года стоят маркетологи, поэтому качество и полезность уступают "потенциальной продаваемости".
S>Только как понятийный аппарат (все эти service applications и services, SPSite к-рый называется site collection, а SPWeb — это сайт и т.п. муть ЛСДшная) влияет на продаваемость?
Никак, этого всего пользователь (покупатель) не видит. Пользоватаель как раз видит то, что разработчику очень сложно использовать. Например в 2013 friendly-urls требуют десятки приседаний/
S>Я вот ника кне догоню, нафига вводить раздельно понятия сервисов и приложений, когда сам ASP.NET прекрасно и без этого огорода слов живет и работает?
Service Applications позволяют частями масштабировать функциональность. например на серваках A и B работает excel services, а на B и C поиск. ASP.NET не позволяет все это делать, увы.
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
S>>Я вот ника кне догоню, нафига вводить раздельно понятия сервисов и приложений, когда сам ASP.NET прекрасно и без этого огорода слов живет и работает? G>Service Applications позволяют частями масштабировать функциональность. например на серваках A и B работает excel services, а на B и C поиск. ASP.NET не позволяет все это делать, увы.
Я про services и service applications. Нафига их вводить как отдельные понятия и иметь для них разный UI для запуска/останова — вот чего я никак не догоняю.
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, senglory, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
S>>>Я вот ника кне догоню, нафига вводить раздельно понятия сервисов и приложений, когда сам ASP.NET прекрасно и без этого огорода слов живет и работает? G>>Service Applications позволяют частями масштабировать функциональность. например на серваках A и B работает excel services, а на B и C поиск. ASP.NET не позволяет все это делать, увы.
S>Я про services и service applications. Нафига их вводить как отдельные понятия и иметь для них разный UI для запуска/останова — вот чего я никак не догоняю.
Вкратце так:
Сервис (SPService) — некоторый модуль функциональности типа "профили пользователей", "поиск" или "хранилище метаданных", то есть тип функциональности.
Сервис-приложение (SPServiceApplication) — логический экземпляр функциональности — конкретное хранилище метаданных, обычно имеет свою БД (разные ServiceApplication одного типа — разные БД).
Экземпляр сервиса (SPServiceInstance) — физический экземпляр функциональности на конкретном сервере. При этом "запуск" экземпляра на сервере создает веб-сервисы (реальные webapp на iis) для всех service applications данного типа.
Прокси сервис приложения (SPServiceApplicationProxy) — конкретный класс для обращения к service application, промежуточный класс нужен в первую очередь чтобы делать балансировку нагрузки, так как физически каждый service app имеет несколько экземпляров на разных серверах.
Вся эта кухня нужна для масштабирования, мультитенантности и изоляции. Реально переусложнено очень сильно, оправдано такое усложнение в очень малом количестве случаев.
Как раз у МС и была цель продать эту кухню хостерам и поднять свое облако. Но вся эта сложность ложится на разработчиков, даже готовые шаблоны\генераторы не сильно помогают.
Кстати в 2013 уже как-бы не очень рекомендуется создавать по несколько ServiceApp, а пользоваться так называемым partitioning.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, senglory, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
G>>Реально переусложнено очень сильно
S>Я про то и говорю — шизофреники придумывали для других шизиков, а не для людей.
Ты же не все процитировал. Есть сценарии в которых такой уровень сложности является адекватным.
Если это проблема для твоего понимания, то это лишь твоя проблема.
Кстати тебя никто не заставляет все это использовать.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, senglory, Вы писали:
S>>Здравствуйте, gandjustas, Вы писали:
S>>>>Я вот ника кне догоню, нафига вводить раздельно понятия сервисов и приложений, когда сам ASP.NET прекрасно и без этого огорода слов живет и работает? G>>>Service Applications позволяют частями масштабировать функциональность. например на серваках A и B работает excel services, а на B и C поиск. ASP.NET не позволяет все это делать, увы.
S>>Я про services и service applications. Нафига их вводить как отдельные понятия и иметь для них разный UI для запуска/останова — вот чего я никак не догоняю.
G>Вкратце так: G>Сервис (SPService) — некоторый модуль функциональности типа "профили пользователей", "поиск" или "хранилище метаданных", то есть тип функциональности. G>Сервис-приложение (SPServiceApplication) — логический экземпляр функциональности — конкретное хранилище метаданных, обычно имеет свою БД (разные ServiceApplication одного типа — разные БД). G>Экземпляр сервиса (SPServiceInstance) — физический экземпляр функциональности на конкретном сервере. При этом "запуск" экземпляра на сервере создает веб-сервисы (реальные webapp на iis) для всех service applications данного типа. G>Прокси сервис приложения (SPServiceApplicationProxy) — конкретный класс для обращения к service application, промежуточный класс нужен в первую очередь чтобы делать балансировку нагрузки, так как физически каждый service app имеет несколько экземпляров на разных серверах.
бррррррр, тип запускать отдельно от приложения — это авторы идеи или оригинального описания что-то курнули, похоже.
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, senglory, Вы писали:
S>>Здравствуйте, gandjustas, Вы писали:
G>>>Реально переусложнено очень сильно
S>>Я про то и говорю — шизофреники придумывали для других шизиков, а не для людей.
G>Ты же не все процитировал. Есть сценарии в которых такой уровень сложности является адекватным. G>Если это проблема для твоего понимания, то это лишь твоя проблема.
... или официального описания, от к-рого веет шизофренией авторов. Все проскипаное описание можно было бы выразить при помощи понятий "тип сервиса", "экземпляр сервиса", "настройки экземпляра сервиса" и "прокси". Но сами их оригинальные слова указывают на буйную фантазию авторов.
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
I>Для этого нужно знать (и судя по всему весьма неплохо знать) SML, Haskell и т.д. Причем, как я понимаю, мало прочитать книжку — нужно на нем что-то написать реальное.
Ну, это, по-моему, серьезное преувеличение. Ни серьезного знания этих языков, ни, тем более, серьезного опыта их применения тут не требуется.
Просто вопрос был "что такое монады понятно, не понятно зачем они нужны" — вот я и ответил.
I>Вы можете объяснить что такое монады, используя базовую терминологию языков типа C++/C#/Java? (можно вводить новые понятия, но каждое понятие должно быть подкреплено реальными практическими примерами)
Попробую. Допустим, код в основном состоит из методов, возвращающих результаты, у которых — в свою очередь — вызываются методы, в которые передаются другие результаты и т.д.
foo.Where(pred).Select(f).ToBar()
Все вроде бы хорошо, но это работает только до тех пор пока соединение методов тривиально, т.е. перестает работать как раз тогда, когда простота становится особенно востребованной.
Допустим, что мы имеем методы, которые не обязательно возвращают что-то пригодное для вызова следующей функции конвеера, т.е. например, null. Можно, конечно, сразу кинутся вставлять в язык какой-нибудь
foo?Where(pred)?Select(f)?ToBar()
Но если подумать, вариантов проблемы может быть сколько угодно. Можно возвращать перечисление простых результатов, можно либо простой результат, либо объяснение, почему он не может быть получен, можно обещание вычислить простой результат в будущем, можно результат и какое-то промежуточное состояние, можно простой результат и недообработанные данные.
Вещи вроде бы разные и их обработка реализуются разными способами вроде вложенных if-ов, вложенных циклов, ожидания завершения всех потоков и т.д. но есть в них и что-то общее.
Короче говоря, есть группа функций такого вот общего вида
Func<Легко, НеВсеТак<Просто>>
Так вот, монады — это инструментарий организации конвееров, в которых на вход метода, требующего чтоб было Просто подается результат метода, возвращающего НеВсеТак<Просто>. При этом вся сантехническая обвязка из ифов и циклов пишется один раз для способа коммутации и задвигается за ширму, чтоб глаз программиста сразу выхватывал суть, а не путался во вспомогательных конструкциях.
Понятно, что есть варианты
Func<НеВсеТак<Легко>, НеВсеТак<Просто>>
и
Func<НеВсеТак<Легко>, Просто>
Производить методы первого вида из методов вида Func<Легко,Просто> можно единообразно, с помощью функторов, а собирать в конвееры методы второго вида можно с помощью комонад. Комонады не так популярны, как монады, потому, что практических применений у методов вида
Func<НеВсеТак<Легко>, Просто>
меньше, чем у
Func<Легко, НеВсеТак<Просто>>
Почему так происходит, думаю, понятно:
Из ЧтоТоПолезное всегда можно сделать ЧтоТоПолезное
либо Бесполезное (null) или СписокЧегоТоПолезного.
Но из Бесполезное Полезное всегда не сделать, как не всегда можно сделать его из пустого списка с полезным.
Короче говоря, для того, чтоб обобщенно работать со случаями Func<Легко, НеВсеТак<Просто>> нужно уметь писать функции с сигнатурой вида
НеВсеТак<Легко> СейчасВсеБудет<Легко, Просто, НеВсеТак>(this Легко x, Func<Легко, НеВсеТак<Просто>> f)
Камень преткновения здесь в выделенном. Такого система типов C# не позволяет. Для чего нам параметр типа, можно ведь унаследовать не все такое от НеВсеТак? Но это неудобно. Абстрагирование от конкретного "не всего такого" нам нужно только для устранения из кода обвязки, но сам код работает с конкретным не всем таким и пользуются конкретными свойствами и методами, которые для всех монад вовсе не общие. Т.е. мы абстрагировались как раз от того, что должно быть в основном коде — ради чего мы все и пишем. Следовательно, нам нужно обратно кастить вниз, к конкретному типу да еще и, чтоб не получить вместо лифта — гроб, а вместо холодильника — духовку, проверять каст в рантайме. Таким образом, мы снова получаем "обвязку", опутывающую код, на котором нам хотелось бы сконцентрироваться, иногда еще и похуже той, от которой только что избавились. Спрашивается, за что боролись?
В С# есть синтаксис для маскировки обвязки from x in xs from y in ys select f(x, y) , но особо значимого повторного использования кода тут не получить, ведь выделить такое выражение в обобщенную функцию нельзя:
?<ПрощеПростого> Lift<Легко, Просто, ПрощеПростого>(?<Легко> xs, ?<Просто> ys, Func<Легко, Просто, ПрощеПростого> f)
{
from x in xs from y in ys select f(x, y)
}
Что мы тут вместо вопросительных знаков напишем?
Вот потому найти применение для монад в гибридных языка вполне можно, вот только широко использовать их на практике — нельзя.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну, это, по-моему, серьезное преувеличение. Ни серьезного знания этих языков, ни, тем более, серьезного опыта их применения тут не требуется.
K>Просто вопрос был "что такое монады понятно, не понятно зачем они нужны" — вот я и ответил.
Шота не понял твой предыдущий ответ
В той части, что я скипнул, понятно еще меньше чем в предыдущем ответе
Мне кажется, объяснять монады нужно на практических задачах, которые встречаются повсеместно, и подходить не со стороны функциональщины, а со стороны дизайна, например сравнивать что в одном варианте дизайна, а что в другом.
P.S. В C# и jS применяю эти монады, а твои объяснения совершенно непонятны
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
DM>>В языках вроде C++ и Java ряд монад уже встроены. А хаскель просто такой примитивный и бедный язык, что там их забыли включить, приходится библиотечно решать те же задачи.
I>Ну вы же сами прекрасно понимаете что это не монады I>Ладно, на следующей неделе я постараюсь собрать всю инфу по монадам и сделаю отдельную тему, в которой изложу свое (возможно ошибочное) видение. А вы, если захотите, меня поправите
Ну что, где эта следующая неделя ?
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Шота не понял твой предыдущий ответ
Все правильно. Монадные туториалы (даже в такой зачаточной форме) не бывают понятными, единственное, что в монадах непонятного — это как раз туториалы.
I>P.S. В C# и jS применяю эти монады, а твои объяснения совершенно непонятны
Ну, строго говоря, вы там применяете то, что имело бы смысл обобщить как монады, но раз уж язык не позволяет — то нельзя. Так что монадами они являются только у программиста в голове.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
string s;
int v;
if(read(s)&&parse(s, v)) write(v);
И он будет отлично работать. Но можно попробовать намутить всякой фигни в функциональном стиле. Например взяв boost.optional в качестве структуры данных. Тогда добавив немного сахара типа:
Мы сможем записать тот же самый тривиальный код в виде:
F2O(read)>>parse>>write;
Лично мне оно не особо нравится, но фанаты функциональщины тащатся от подобного. ))) Кстати, важный нюанс в том, что наш сахар никак не завязан на конкретные функции или типы данных, так что он пишется один раз для всех случаев.
Да, и пока это у нас ещё не монады, а просто функторы. Чтобы потребовались монады, у нас например функция parse должна оказаться изначально написанной под boost.optional. Т.е. иметь прототип вида:
optional<int> parse(const string& s)
Чтобы наш код продолжил работать и с такой функцией, нам надо будет добавить (хотя в данном случае можно и заменить им старый вариант) ещё один вариант оператора>>:
optional<R> operator>>(optional<T> o, optional<R> (*f)(const T&))
{
return o?f(*o):optional<R>();
}
Это и будет та самая монада... Причём как видно, она даже проще чем обычные функторы.
K>Вот потому найти применение для монад в гибридных языка вполне можно, вот только широко использовать их на практике — нельзя.
Да легко оно всё делается на практике и здесь. Вот только польза крайне сомнительна...
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Да, и пока это у нас ещё не монады, а просто функторы. Чтобы потребовались монады, у нас например функция parse должна оказаться изначально написанной под boost.optional. Т.е. иметь прототип вида: _>
_>optional<int> parse(const string& s)
_>
_>Чтобы наш код продолжил работать и с такой функцией, нам надо будет добавить (хотя в данном случае можно и заменить им старый вариант) ещё один вариант оператора>>: _>
_>Это и будет та самая монада... Причём как видно, она даже проще чем обычные функторы.
Это будет монада, но это будет отстой, потому что в более менее серьезном приложении придется понавыписывать столько операторов, что вспотеешь только перечислять их.
Монады же нужны для того, что бы не надо было этим заниматься, то есть, вообще.
Собственно, в гибридах это достижимо, правда, не любую задачу можно толково завернуть в монады.
Re[13]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это будет монада, но это будет отстой, потому что в более менее серьезном приложении придется понавыписывать столько операторов, что вспотеешь только перечислять их.
С чего бы это? Все типы не фиксированы, так что достаточно одной версии.
I>Монады же нужны для того, что бы не надо было этим заниматься, то есть, вообще.
Это понятно. Не понятно другое — нафига нам вообще задаваться целью строить подобные конвейеры, если и без них всё отлично пишется. Причём код получается даже более простой и очевидный.
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
НеВсеТак<Легко> СейчасВсеБудет<Легко, Просто, НеВсеТак>(this Легко x, Func<Легко, НеВсеТак<Просто>> f)
K>Камень преткновения здесь в выделенном. Такого система типов C# не позволяет.
Не, при известном желании всё можно:
public interface IMonad<T, TMonad> where TMonad: IMonad<T, TMonad>
{
TMonad Make(T value);
TMonad Bind(TMonad monad, Func<T, T> apllyFunc);
T Get(TMonad monad);
}
public class Easy { }
public class Simple { }
public class NotSo<T>: IMonad<T, NotSo<T>>
{
public NotSo<T> Make(T value)
{
...
}
public NotSo<T> Bind(NotSo<T> monad, Func<T, T> apllyFunc)
{
...
}
public T Get(NotSo<T> monad)
{
...
}
}
static class Program
{
public static TOut Make<TIn, TOut, TOutMonad>(this TIn x, TOut y, Func<TIn, TOut, TOutMonad> f)
where TOutMonad: IMonad<TOut, TOutMonad>
{
...
}
static void Main(string[] args)
{
new Easy().Make(new Simple(), (e, s) => new NotSo<Simple>());
}
}
Зачем — это уже второй вопрос
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, include2h, Вы писали:
I>Здравствуйте, Klapaucius, Вы писали:
K>>Ну, я готов дать разъяснения, если есть конкретные вопросы.
I>Для этого нужно знать (и судя по всему весьма неплохо знать) SML, Haskell и т.д. Причем, как я понимаю, мало прочитать книжку — нужно на нем что-то написать реальное.
I>Вы можете объяснить что такое монады, используя базовую терминологию языков типа C++/C#/Java?
Ну вот смотри, в С++ есть исключения. В результате ты пишешь код, как будто их нет, зная, что выполнение автоматически прервется, если исключение будет сгенерировано. А если бы встроенных исключений не было, то пришлось бы городить лес из проверок errno после каждой строчки.
А теперь представь, что у тебя есть способ все эти ифы убрать с глаз долой. То есть код в результате будет выглядеть, как будто есть исключения, но под капотом он по-прежнему будет проверять errno. Вот такой способ — это и есть монада (одна из). Это просто способ связать вычисления, а уж как ты их хочешь связать — дело твое.
Тут тип не совсем правильный. Здесь
bind :: m t -> (t -> t) -> m t
а нужно
bind :: m t -> (t -> m r) -> m r
т.е. что-то вроде
RMonad Bind(TMonad monad, Func<T, RMonad> applyFunc);
где RMonad — некий тип R завернутый в Monad.
Re[14]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Это будет монада, но это будет отстой, потому что в более менее серьезном приложении придется понавыписывать столько операторов, что вспотеешь только перечислять их.
_>С чего бы это? Все типы не фиксированы, так что достаточно одной версии.
optional<R> operator>>(optional<T> o, optional<R> (*f)(const T&)
I>>Монады же нужны для того, что бы не надо было этим заниматься, то есть, вообще.
_>Это понятно. Не понятно другое — нафига нам вообще задаваться целью строить подобные конвейеры, если и без них всё отлично пишется. Причём код получается даже более простой и очевидный.
Проще
1 не всегда
2 только в сравнении с версией в языке, который не поддерживает монад
Скажем, optional очень хорошо помогает в больших выражениях. Я сильно сомневаюсь, что проверки каждого элемента в цепочке на null делают код простым и понятным.
Здравствуйте, Klapaucius, Вы писали:
K>Но если подумать, вариантов проблемы может быть сколько угодно. Можно возвращать перечисление простых результатов, можно либо простой результат, либо объяснение, почему он не может быть получен, можно обещание вычислить простой результат в будущем, можно результат и какое-то промежуточное состояние, можно простой результат и недообработанные данные.
Как я понял, это концепция заворачивания объектов в какие-то универсальные обертки, которые сами по себе влияют на поток выполнения (или определяют поток выполнения). Эти обертки дают оборачиваемым типам данных какие-то новые свойства, может быть даже порождают на их основе новые сущности (практически как шаблоны в С++). Отличие от шаблонов в том, что это не тупая кодогенерация новых типов путем подстановки, а некие интеллектуальные возможности прозрачной интеграции этих новых типов ВМЕСТО старых.
Если я правильно понял: Maybe — добавляет "нуллабельность" к типу, List — позволяет обрабатывать сразу много значений вместо одного, Future — вычисляет в другом потоке и обещает возвратить результат в будущем. Вероятно можно еще возвращать вместе с результатом какую-то дополнительную информацию, делать логирование и т.д. (кстати приведите еще примеры)
Теперь представим себе, что мы хотим ввести монады в простой си-подобный язык программирования.
Я пишу код, как-бы не думая о монадах. Если мне нужно написать функцию сложения двух чисел типа int, то я пишу простую функцию
int sum(int x, int y) { return x+y; }
Если мне в каком-то другом месте по смыслу программы нужно возвратить "nullable int", то я конкретно такой тип и возвращаю.
Maybe<int> foo() {/*..*/}
А монады, если я правильно понимаю, каким-то образом делают возможным прозрачную передачу типа Maybe<int> в функцию, принимающую int?
sum(foo(),100);
т.е. без всяких синтаксических ухищрений, а вот просто так взяли и передали, и на выходе вместо int получили Maybe<int> ?
Аналогично, если я передам в sum() объект List(), то я и на выходе получу List(), при этом sum() даже не узнает, что ее вызывают для целого списка чисел?
Здравствуйте, include2h, Вы писали:
I>Как я понял, это концепция заворачивания объектов в какие-то универсальные обертки, которые сами по себе влияют на поток выполнения (или определяют поток выполнения).
Вроде того. Как кто-то метко выразился, это способ переопределить оператор ";".
I>Теперь представим себе, что мы хотим ввести монады в простой си-подобный язык программирования. I>Я пишу код, как-бы не думая о монадах. Если мне нужно написать функцию сложения двух чисел типа int, то я пишу простую функцию I>
int sum(int x, int y) { return x+y; }
I>А монады, если я правильно понимаю, каким-то образом делают возможным прозрачную передачу типа Maybe<int> в функцию, принимающую int? I>
sum(foo(),100);
I>т.е. без всяких синтаксических ухищрений, а вот просто так взяли и передали, и на выходе вместо int получили Maybe<int> ? I>Аналогично, если я передам в sum() объект List(), то я и на выходе получу List(), при этом sum() даже не узнает, что ее вызывают для целого списка чисел?
Совсем прозрачно вряд ли получится, ибо во-первых это будет обманом пользователя (если я сказал, что ф-я принимает число, то разрешать передавать туда что-то другое без моего разрешения — прямое нарушение), хорошо бы все-таки в явном виде разрешить подобную перегрузку, а во-вторых это все-равно не будет работать, если разные аргументы окажутся в разных монадах.
В существующем языке Идрисе это выглядит так. Можно в явном виде сказать, что аргументы могут быть завернуты в произвольную монаду, и результат получается в ней же:
sum : (Monad m, Num a) => m a -> m a -> m a -- sum работает с любым числоподобным типов в любой монаде
sum x y =[| x + y |] -- такие скобочки называются idiom brackets и делают всю магию
Попробуем использовать ее в REPL'e:
> sum (Id 1) (Id 2)
Id 3 : Identity Integer
> sum (Just 1) (Just 2)
Just 3 : Maybe Integer
> sum [1] [2]
[3] : List Integer
> sum [1] (Just 2)
Can't unify
Maybe a
with
List a
Т.е. пока оба аргумента в одной и той же монаде, все работает нормально, и на выходе имеем то число, то Maybe число, то список чисел. Но стоит передать значения в разных монадах, как сказка заканчивается: нет никакого автоматического способа разрулить эту ситуацию. Как говорит нам теория категорий, монады не коммутируют.
Теоретически нечто подобное можно сделать и в си-подобном языке, и тогда хотя бы при одинакового типа аргументах sum будет полиморфна по используемой монаде. Но сначала придется вытащить из языка зашитую туда ранее монаду IO, т.е. сделать его чистым, а чистый си-подобный язык — то еще удовольствие.
Re[15]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>optional<R> operator>>(optional<T> o, optional<R> (*f)(const T&)
и? )
I>Проще I>1 не всегда I>2 только в сравнении с версией в языке, который не поддерживает монад
I>Скажем, optional очень хорошо помогает в больших выражениях. Я сильно сомневаюсь, что проверки каждого элемента в цепочке на null делают код простым и понятным.
Монада подобного типа встроена в большинство императивных языков — в них она называется "исключения". )))
Здравствуйте, include2h, Вы писали:
I>А монады, если я правильно понимаю, каким-то образом делают возможным прозрачную передачу типа Maybe<int> в функцию, принимающую int? I>...
I>Прокомментируйте плиз, прав я или нет.
Типа того. Только эта функция ещё обязательно должна возвращать Maybe<int> и соответственно концепция монад препятствует появлению сущностей типа Maybe<Maybe<int>>.
Re[16]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Скажем, optional очень хорошо помогает в больших выражениях. Я сильно сомневаюсь, что проверки каждого элемента в цепочке на null делают код простым и понятным.
_>Монада подобного типа встроена в большинство императивных языков — в них она называется "исключения". )))
Эта монада не исключение, а maybe
Re[17]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Эта монада не исключение, а maybe
Да не о том речь. Вот допустим если бы в моём пример выше функции были с прототипами:
string read();
int parse(string);
void write(int);
и при этом бросали исключения для невалидных данных и т.п. При таком раскладе мы можем нарисовать гораздо более симпатичный код, чем вариант с конвейером.
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Монады. Несколько раз подкатывал, без толку.
Я, кстати, раз делал доклад на семинаре по монадам и их реализации в Haskell. Получилась даже такая небольшая популярная статья. Если интересно, могу выслать.
Re[18]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Эта монада не исключение, а maybe
_>Да не о том речь. Вот допустим если бы в моём пример выше функции были с прототипами: _>
_>и при этом бросали исключения для невалидных данных и т.п. При таком раскладе мы можем нарисовать гораздо более симпатичный код, чем вариант с конвейером.
Чем он симпатичный? Тем что все неявное скрыто от читающего? Тем что для проверки корректности кода нужно дополнительно вникать что будет если наступит конец файлы или число не может быть распарсено?
Все эти неявные выходы усложняют анализ кода как человеком, так и компьютером. Если неявные эффектны делаем явными (выражаем в типах значений), то это упрощает анализ кода очень сильно. Проще анализ — меньше ошибок — выше скорость разработки.
С другой стороны выражение всех эффектов усложняет написание кода, но тут и помогают монады.
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, mefrill, Вы писали:
M>Я, кстати, раз делал доклад на семинаре по монадам и их реализации в Haskell. Получилась даже такая небольшая популярная статья. Если интересно, могу выслать.
Зачем нужны монады в хаскеле всем очевидно — там без них просто смерть. ))) Тут обсуждается совсем другой вопрос: зачем могут понадобиться монады в нормальных мультипарадигменных языках. Вот подобная статья была бы крайне интересной...
Re[18]: Есть ли вещи, которые вы прницпиально не понимаете...
_>и при этом бросали исключения для невалидных данных и т.п. При таком раскладе мы можем нарисовать гораздо более симпатичный код, чем вариант с конвейером.
Этот твой "симпатичный" на самом деле короткий, примерно так:
void DoAll()
Такая красота никому не нужна. Нужна возможность в одном небольшом фрагменте кода проанализировать все локальные проблемы. С исключениями ты так не сможешь сделать. Т.е. все важные эффекты кода должны быть явными.
Re[19]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Чем он симпатичный? Тем что все неявное скрыто от читающего? Тем что для проверки корректности кода нужно дополнительно вникать что будет если наступит конец файлы или число не может быть распарсено? G>Все эти неявные выходы усложняют анализ кода как человеком, так и компьютером. Если неявные эффектны делаем явными (выражаем в типах значений), то это упрощает анализ кода очень сильно. Проще анализ — меньше ошибок — выше скорость разработки. G>С другой стороны выражение всех эффектов усложняет написание кода, но тут и помогают монады.
Ну так в случае монад этот код всё равно остаётся скрытым, просто уже в самой монаде. Конечно если человек держит их все в уме, то код пишется/читается легко... Но он точно так же может держать в уме и сигнатуры используемого интерфейса api (с исключениями или без) и тогда код аналогично будет легко писаться/читаться.
Re[19]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Этот твой "симпатичный" на самом деле короткий, примерно так:
I>
I>void DoAll()
I>
Не, там будет что-то вроде:
try{
write(parse(read()));
}catch(...){}
Если сравнивать это с
F2O(read)>>parse>>write;
и с
string s;
int v;
if(read(s)&&parse(s, v)) write(v);
То совершенно не очевидно, где код проще для понимания. На самом деле самый понятный вариант последний, но он многословный. Первые два варианта одинаково скрывают часть логики, но при этом первый использует общепринятую в императивных языках схему...
I>Такая красота никому не нужна. Нужна возможность в одном небольшом фрагменте кода проанализировать все локальные проблемы. С исключениями ты так не сможешь сделать. Т.е. все важные эффекты кода должны быть явными.
При желание можно сделать красиво и понятно любым способом (и явным кодом и монадами и исключениями и думаю ещё можно много вариантов напридумывать). ))) Вопрос в том нафига плодить лишнюю сущность (монады), если в языке и так уже есть несколько путей для реализации подобного. Мы же тут не про Хаскель, в котором других путей просто нет...
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
_>То совершенно не очевидно, где код проще для понимания. На самом деле самый понятный вариант последний, но он многословный. Первые два варианта одинаково скрывают часть логики, но при этом первый использует общепринятую в императивных языках схему...
Если самый понятный последний вариант, то почему ты на ассемблере не пишешь ? Вот там уж точно всё понятно.
I>>Такая красота никому не нужна. Нужна возможность в одном небольшом фрагменте кода проанализировать все локальные проблемы. С исключениями ты так не сможешь сделать. Т.е. все важные эффекты кода должны быть явными.
_>При желание можно сделать красиво и понятно любым способом (и явным кодом и монадами и исключениями и думаю ещё можно много вариантов напридумывать). ))) Вопрос в том нафига плодить лишнюю сущность (монады), если в языке и так уже есть несколько путей для реализации подобного. Мы же тут не про Хаскель, в котором других путей просто нет...
Возьми что нибудь посложнее, например парсер. Хочется иметь полный контроль типов, поддержку компилятора и задавать грамматику в виде максимально близком к БНФ.
Re: Есть ли вещи, которые вы прницпиально не понимаете...
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Для меня загадка — современные алгоритмы шифрования (криптографии). Мат.аппарата не хватает
На практическом уровне — public key/private key понятно, но чо там внутри — чисто магия.
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Возьми что нибудь посложнее, например парсер. Хочется иметь полный контроль типов, поддержку компилятора и задавать грамматику в виде максимально близком к БНФ.
Ну если посмотреть на код выдаваемый yacc+flex, то там монады довольно сложно найти))) Другое дело, что этот код и не предназначен для разглядывания...
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Dair, Вы писали:
D>Для меня загадка — современные алгоритмы шифрования (криптографии). Мат.аппарата не хватает
D>На практическом уровне — public key/private key понятно, но чо там внутри — чисто магия.
Да ладно, если говорить о принципах, то там же всё вообще тривиально.
Вот смотри, предположим у нас есть функция y=exp(x); и соответственно обратная ей x=ln(y); Причём (и это ключевой момент) ln вычисляется намного дольше, чем exp. Кстати, это и для обычных exp и ln справедливо, а в асимметричной криптографии используется спец. вариант, в котором ln вычисляется годами... Теперь, при наличие пары таких функций, мы можем тривиально наладить защищённый канал.
Вот предположим у нас есть два человека (1 и 2) с каждый стороны и ещё третий, прослушивающий канал. 1 и 2 генерируют по одному случайному числу k1 и k2. Затем считают от них p1=exp(k1) и p2=exp(k2). И отсылают друг другу. В итоге у первого есть k1 и p2, у второго k2 и p1, а у прослушивающего p1 и p2. Теперь первые два считают число z=p2^k1=p1^k2=exp(k1*k2) — теперь у них есть некий общий секрет z, который они могут использовать например как ключ для обычного блочного шифрования данных и спокойно обмениваться ими. Ну а бедный подслушивающий будет занят вычислениями ln(p1) или ln(p2), для того чтобы получить тот же самый z...
А весь так называемый крутой мат. аппарат там как раз сводится к доказательствам, что все современные методы математики не умеют быстро посчитать ln... )))
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Чем он симпатичный? Тем что все неявное скрыто от читающего? Тем что для проверки корректности кода нужно дополнительно вникать что будет если наступит конец файлы или число не может быть распарсено? G>>Все эти неявные выходы усложняют анализ кода как человеком, так и компьютером. Если неявные эффектны делаем явными (выражаем в типах значений), то это упрощает анализ кода очень сильно. Проще анализ — меньше ошибок — выше скорость разработки. G>>С другой стороны выражение всех эффектов усложняет написание кода, но тут и помогают монады.
_>Ну так в случае монад этот код всё равно остаётся скрытым, просто уже в самой монаде. Конечно если человек держит их все в уме, то код пишется/читается легко... Но он точно так же может держать в уме и сигнатуры используемого интерфейса api (с исключениями или без) и тогда код аналогично будет легко писаться/читаться.
Неверно. В монаде скрыт control flow для unhappy path, но не присутствие unhappy path. С исключениями скрывается именно присутствие неявных выходов, которые кроме как чтением документации не определить.
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, Greeter, Вы писали:
G>>Или не до конца понимаете в программировании?
D>Монады. Несколько раз подкатывал, без толку.
Истинно так. Тот еще монстр.
Мне иногда кажется, что я их чуть-чуть понимаю
И даже больше, я могу попытаться объяснить их, на примерах. Может меня кто-то поправит и расскажет, что я нифига не понимаю. Тоже польза.
Вводная:
Linq операторы (Select, Where, Group, ...) -- это все монады (к этому я пришел читая какую-то статью типа "монады в картинках").
async/await из C# 5 -- это тоже монада (это я узнал от самого Эрика Майера (Erik Meijer) на курсе https://www.coursera.org/course/reactive)
Это было из серии "зачем могут понадобиться монады в нормальных мультипарадигменных языках".
Как я себе объясняю монады
Для себя, в голове, я представляю монаду как объект, который состоит из Объекта и Функции. Эта Функция может что-то сделать с Объектом по запросу пользователя, но пока не делает(такое вот обещание сделать что-то с объектом). Если вернуться к Linq, то Объект это таблица в базе, а функция, это, например, условие where salary > 5.
Когда пользователю нужны данные, то он может эти данные у монады получить. Тогда монада применяет Функцию к Объекту и возвращает результат (вот тут я точно наврал, но моя модель в голове без этого пункта не рабоает).
Круть заключается в том, что монады можно объединять, дополнять и выстраивать в цепочки.
Это все делается оператором, кот. в определении называется bind ((M t)->(t->M u)->(M u)). Суть его (опять же в моей голове) заключается вот в чем. Он говорит: представь, что результат монады уже посчитан, напиши функцию, которая что-то делает с этим результатом и передай мне. Я отдам тебе новую монаду, которая сделает то что должна была моя монада, плюс применит твою функцию к результату (тут все не полно, потому как не объясняет как из Users.Where().Select() получается один запрос, а не 2. Но у меня "простого" объяснения этому нет).
Вернемся к linq и async/await
Разбираем цепочку:
Users.Where(u=>u.Salary > 5).SelectMany(u=> Departments).OrderBy((u, d) => d.Name).Select((u, d)=> {u.Name, d.Name}).ToList()
Users =>
это монада состоящая из "таблицы в БД" (Объект) и "запроса" (функция) { UsersTable, "Select * from UsersTable"} Users.Where(u=>u.Salary > 5) =>
произошла бинд магия, которая знает, что "Select *" и "where" можно объединить в один запрос => { UsersTable, "Select * from UsersTable u where u.Salary > 5"} Users.Where(u=>u.Salary > 5).SelectMany(u=> Departments) =>
к объекту монады добавился еще один, а селект дополнился джоином => { {UsersTable, DepartmentsTable} , "Select * from UsersTable u join Departments d where u.Salary > 5"}
Вот тут моя абстракция потекла, потому как я понимаю, что в случае с обычным SQL нам нафик нужны две таблицы в Объекте и там может быть сразу вся база, но дело в том, что там у нас не sql, а список из ExpressionTree и нам нужны эти объекты, чтобы построить запрос.
Users.Where(u=>u.Salary > 5).SelectMany(u=> Departments).OrderBy((u, d) => d.Department) => { {UsersTable, DepartmentsTable} , "Select * from UsersTable u join Departments d where u.Salary > 5 order by d.Name"}
Users.Where(u=>u.Salary > 5).SelectMany(u=> Departments).OrderBy((u, d) => d.Name).Select((u, d)=> {u.Name, d.Name}) => ... идея понятна, надеюсь.
Как-то так, надеюсь хоть кто-то понял, что я только что написал Предлагаю ЭТО теперь обсудить.
А еще лучше перевести мой поток мыслей на нормальный человеческй язык.
СУВ, Aikin
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Неверно. В монаде скрыт control flow для unhappy path, но не присутствие unhappy path. С исключениями скрывается именно присутствие неявных выходов, которые кроме как чтением документации не определить.
Да, всё правильно, подходы у этих принципов абсолютно различные. Но ключевое преимущество (по сравнению с вариантом в лоб) у них общее — количество кода на обработку особой ситуации не зависит от количества операций в цепочке.
Ну а то, что придётся читать документацию для использования некого api — это вроде как абсолютно нормально. )))
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Возьми что нибудь посложнее, например парсер. Хочется иметь полный контроль типов, поддержку компилятора и задавать грамматику в виде максимально близком к БНФ.
Вместо всяких ">>" используется ".", код в целом пошумнее, но в общем выходит похоже на те парсер-комбинаторы, с которыми приходилось иметь дело на хаскеле и окамле.
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Aikin, Вы писали:
A>Linq операторы (Select, Where, Group, ...) -- это все монады (к этому я пришел читая какую-то статью типа "монады в картинках"). A>async/await из C# 5 -- это тоже монада (это я узнал от самого Эрика Майера (Erik Meijer) на курсе https://www.coursera.org/course/reactive)
A>Это было из серии "зачем могут понадобиться монады в нормальных мультипарадигменных языках".
Это теоретически может служить аргументом, но только для тех, кто считает что в linq и async/await есть какой-то смысл...
A>Для себя, в голове, я представляю монаду как объект, который состоит из Объекта и Функции.
Ключевая ошибка. Причём там же прямо дальше по тексту есть практически правильный кусок "монада применяет Функцию к Объекту". Как она могла бы это делать, если и функция и объект — это её части? ) Сама на себя действует что ли? ))) Очевидно же даже прямо из этого текста, что объект и функция являются как бы параметрами монады, т.е. она является отдельной от них сущностью. Более того, монада — это чистая абстракция и не имеет прямого отображения на какие-то сущности языка. Ну разве что сопоставить ей саму строчку кода вида read>>parse>>write (ну или Linq выражение).
Собственно фраза "монада — это применение функции к объекту" — это и есть неплохое определение. ))) Только надо ещё уточнить, что применение особым образом и не произвольную функцию к произвольному объекту (иначе например банальная функция map была бы монадой), а вполне конкретных типов. А именно, речь идёт о функциях вида optional<R> F<T, R>(T). Optional — это естественно только для примера, а могут быть и совсем другие типы. Так вот монада умеет применить такую функцию F к объекту вида optional<T> (а не просто T!). И как раз благодаря этому и получается строить цепочки произвольной длины.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Собственно фраза "монада — это применение функции к объекту" — это и есть неплохое определение. )))
Ключевая проблема всех неплохих определений монады в том, что ими весь инет забит. Но все равно непонятно что это за зверь.
СУВ, Aikin
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Aikin, Вы писали:
A>И даже больше, я могу попытаться объяснить их, на примерах. Может меня кто-то поправит и расскажет, что я нифига не понимаю. Тоже польза. A>Linq операторы (Select, Where, Group, ...) -- это все монады (к этому я пришел читая какую-то статью типа "монады в картинках"). A>async/await из C# 5 -- это тоже монада (это я узнал от самого Эрика Майера (Erik Meijer) на курсе https://www.coursera.org/course/reactive)
Вот мой вариант "монады за две минуты".
Мысль 1. Всякий обычный императивный код
Делай то;
Делай сё
это на самом деле
r1 = Делай то;
r2 = Делай сё
где результаты r1 и r2 могут быть типа void.
Мысль 2. Каждую строчку можно считать функцией, принимающей результат вычисления предыдущей (может его использовать, может не использовать), и производящей какой-то свой результат. Т.е. код выше можно переписать как
Поскольку нам доступен результат не только предыдущей строчки, но и более ранних, то когда строчек много, получаются вложенные функции, замыкания.
Поэтому в обычном императивном коде символ ";" между предложениями это по сути волшебный оператор, у которого слева некоторое значение, а справа — функция, использующая это значение. Но если в языках вроде Си этот оператор жестко определен самым простым способом — передать значение в функцию, то в более интересных языках мы можем его переопределить и придумать ему более интересное содержание. Например, он может передавать значение в функцию не всегда, а только когда это не None. Это Maybe. Или он может получать значение-список, применять переданную функцию к каждому элементу, а полученные результаты склеивать в один список. Это List. Или может не передавать значение сразу, а запомнить функцию и переключиться на выполнение другой, а эту вызвать когда переданное слева значение "созреет". Это async. Или может переданную справа функцию заменить другой, обращающейся к базе. Это LINQ 2 SQL. Все волшебство происходит как следствие того, что мы монолитный код разбили на дерево из множества маленьких функций и позволили в явном виде этими кусочками оперировать как данными.
Всякое такое хитрое переопределение ";", простой передачи значения в функцию, назовем эффектом.
Мысль 3. Откуда берутся законы монады. Азы теорката: категория — это, грубо говоря, такой потенциально бесконечный ориентированный граф, узлы в нем называются объектами, а грани — стрелками, и в нем должны быть выполнены простые правила:
1) из всякой вершины есть стрелка в нее же, id : a -> a
2) если из А есть стрелка в Б, а из Б есть стрелка в В, то должна существовать стрелка из А в В, их композиция.
3) композиция id с любой стрелкой f (неважно в каком порядке) есть сама стрелка f.
Так вот, если в качестве объектов взять типы (Int, String, Bool...), а в качестве стрелок — функции (int_to_string, not, is_zero...), то получается как раз категория. Теперь, выше мы видели, что вместо простого применения функций мы можем захотеть хитрого применения — с эффектами. Возьмем и заменим все стрелки вида a -> b на стрелки с эффектами a -> m b. Чтобы у нас опять была категория, эти стрелки с эффектами должны подчиняться тем же трем законам категории. Осталось их аккуратно выписать, и получим законы монады для m.
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Aikin, Вы писали:
A>Ключевая проблема всех неплохих определений монады в том, что ими весь инет забит. Но все равно непонятно что это за зверь.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Неверно. В монаде скрыт control flow для unhappy path, но не присутствие unhappy path. С исключениями скрывается именно присутствие неявных выходов, которые кроме как чтением документации не определить.
_>Да, всё правильно, подходы у этих принципов абсолютно различные. Но ключевое преимущество (по сравнению с вариантом в лоб) у них общее — количество кода на обработку особой ситуации не зависит от количества операций в цепочке.
Да, монады и сахар в языках для них для этого и были придуманы.
_>Ну а то, что придётся читать документацию для использования некого api — это вроде как абсолютно нормально. )))
Только это никто не делает. Поэтому явно выражать все в типах гораздо эффективнее, чем разбираться почему уже оно падает.
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Aikin, Вы писали:
A>Ключевая проблема всех неплохих определений монады в том, что ими весь инет забит. Но все равно непонятно что это за зверь.
Хм, ну на мой взгляд даже в банальной википедии вполне понятная формулировка)
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Да, монады и сахар в языках для них для этого и были придуманы.
Ну так в итоге и получается, что в классических императивных языках уже заложено большая часть самых полезных монад. В виде конструкций языка, библиотечных функций и т.п. Соответственно не особо понятно зачем пытаться строить тоже самое, но только в максимально классическом "хаскелевском" виде и руками — теперь осознания что типа "я могу создавать монады"? )))
G>Только это никто не делает. Поэтому явно выражать все в типах гораздо эффективнее, чем разбираться почему уже оно падает.
Так это смотря в каком языке) Если говорить например про Жабку, то там вообще IDE автоматом определит что в каком-том месте кидаются исключения, сама вставит их импорт и код обработки. )))
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Возьми что нибудь посложнее, например парсер. Хочется иметь полный контроль типов, поддержку компилятора и задавать грамматику в виде максимально близком к БНФ.
_>Ну если посмотреть на код выдаваемый yacc+flex, то там монады довольно сложно найти))) Другое дело, что этот код и не предназначен для разглядывания...
При чем здесь yacc ?
Ты или не в теме или усиленно притворяешься Решай сам.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>При чем здесь yacc ? _>А ты предлагаешь писать парсер сложной грамматики (для простой то и boost.spirit сойдёт) руками и с нуля? )))
Полагаю, выше речь шла о монадных парсер-комбинаторах — классическом применении монад (см. parsec и еще 197638 пакетов на hackage в разделе parsing). Но если парсер можно сделать на монадах, это не значит, что те же монады есть в любом другом парсере.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ключевая ошибка. Причём там же прямо дальше по тексту есть практически правильный кусок "монада применяет Функцию к Объекту". Как она могла бы это делать, если и функция и объект — это её части? ) Сама на себя действует что ли? )))
— Весь этот разговор довольно примитивен. Мы ведь начали с того, кто я по своей природе. Если угодно, я полагаю себя... Ну скажем, монадой. В терминах Лейбница.
— А кто тогда тот, кто полагает себя этой монадой?
— Монада и полагает, — ответил я, твердо решив держать себя в руках.
(с) Пелевин, Чапаев и Пустота
Извините, Лейбницем навеяло.
P.S. Опечатка в цитате — моя.
Перекуём баги на фичи!
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Вот мой вариант "монады за две минуты".
<> DM>Мысль 2. Каждую строчку можно считать функцией, принимающей результат вычисления предыдущей (может его использовать, может не использовать), и производящей какой-то свой результат. Т.е. код выше можно переписать как
<>
Это не "монады за 2 минуты", а "продолжения за 2 минуты".
DM>Мысль 3. Откуда берутся законы монады. Азы теорката: категория — это, грубо говоря, такой потенциально бесконечный ориентированный граф, узлы в нем называются объектами, а грани — стрелками, и в нем должны быть выполнены простые правила: DM>1) из всякой вершины есть стрелка в нее же, id : a -> a DM>2) если из А есть стрелка в Б, а из Б есть стрелка в В, то должна существовать стрелка из А в В, их композиция. DM>3) композиция id с любой стрелкой f (неважно в каком порядке) есть сама стрелка f. DM>Так вот, если в качестве объектов взять типы (Int, String, Bool...), а в качестве стрелок — функции (int_to_string, not, is_zero...), то получается как раз категория. Теперь, выше мы видели, что вместо простого применения функций мы можем захотеть хитрого применения — с эффектами. Возьмем и заменим все стрелки вида a -> b на стрелки с эффектами a -> m b. Чтобы у нас опять была категория, эти стрелки с эффектами должны подчиняться тем же трем законам категории. Осталось их аккуратно выписать, и получим законы монады для m.
Вот интересно, какой теоретический минимум необходим для объяснения монад на пальцах?
Теория множеств, поскольку Set — категория, хорошо иллюстрирующая и законы монад, и нотацию (do-нотация — это обобщение и развитие set comprehension)
Абстрактная алгебра, поскольку (>>=) это обобщение композиции функций (законы группы с нулём и единицей) — только вместо группы функций над однородным множеством (f,g : a->a, f.g : a->a) или над всеми типами (f : b->c, g : a->b, f.g : a->c) у нас двухслойное пространство (f : b->c', g : a->b', g>>=f : a->c') — соответственно, каждому b требуется привести в соответствие b'
Собственно, законы монад — это законы группы с единицей.
1) "в группе есть единица"
2) "группа замкнута"
3) "единица является нейтральным множителем как слева, так и справа"
4) ассоциативный закон, кстати!
Отсюда стремительно вытекает вопрос: а нет ли в этой группе нуля, который является идемпотентным множителем? (А он обычно есть — функция fail)
А если у нас есть 0 и 1, то нельзя ли сделать полукольцо со сложением? (А можно — класс MonadPlus)
В обоих случаях теоркат только выглядывает из-за угла и не пугает раньше времени.
Перекуём баги на фичи!
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>При чем здесь yacc ?
_>А ты предлагаешь писать парсер сложной грамматики (для простой то и boost.spirit сойдёт) руками и с нуля? )))
Ну то есть у тебя только два варианта — или yacc или спирит ? Я даже не знаю, что и сказать
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>При чем здесь yacc ?
_>А ты предлагаешь писать парсер сложной грамматики (для простой то и boost.spirit сойдёт) руками и с нуля? )))
Давай внимательно посмотрим, чего твой спирит и yacc умеют
Покажи на yacc или спирит аналог вот такого кода
static void Main()
{
var random = new Random();
var values = Observable
.Interval(TimeSpan.FromSeconds(1))
.Select(_ => random.Next(1, 50));
var ticks = values
.Scan(StockTick.Empty, (acc, cur) => new StockTick(cur, cur - acc.Value))
.Publish();
var alerts = ticks.Parse(parser =>
from next in parser
let ups = next.Where(tick => tick.Change > 0)
let downs = next.Where(tick => tick.Change < 0)
let downAlert = from manyUps in ups.AtLeast(2).ToList()
from reversalDown in downs.NonGreedy()
where reversalDown.Change <= -11
select new StockAlert(manyUps, reversalDown)
let upAlert = from manyDowns in downs.AtLeast(2).ToList()
from reversalUp in ups.NonGreedy()
where reversalUp.Change >= 21
select new StockAlert(manyDowns, reversalUp)
select downAlert.Or(upAlert).Ambiguous(untilCount: 1));
using (ticks.Subscribe(WriteTick))
using (alerts.Subscribe(WriteAlert))
using (ticks.Connect())
{
Console.ReadKey();
}
}
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали: К>Собственно, законы монад — это законы группы с единицей. К>1) "в группе есть единица" К>2) "группа замкнута" К>3) "единица является нейтральным множителем как слева, так и справа" К>4) ассоциативный закон, кстати!
Извините, что придираюсь, но не группы, а полугруппы с единицей, т.е. моноида.
В группе еще должен быть обратный элемент.
К>Отсюда стремительно вытекает вопрос: а нет ли в этой группе нуля, который является идемпотентным множителем? (А он обычно есть — функция fail) К>А если у нас есть 0 и 1, то нельзя ли сделать полукольцо со сложением? (А можно — класс MonadPlus)
Может я туплю, но в начале у нас был аддитивный моноид, в котором нейтральный элемент почему-то назывался единицей.
Потом откуда-то появилась непонятно как определеная операция умножения и какой-то ноль в группе (нейтральный элемент то в группе только один, и раз уж его назвали единицей, то либо это не ноль, либо это не группа).
И что может быть ноль в полукольце, который не является идемпотентным множителем?
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, HrorH, Вы писали:
HH>Извините, что придираюсь, но не группы, а полугруппы с единицей, т.е. моноида. HH>В группе еще должен быть обратный элемент.
Да, конечно, моноид. С группой я поторопился.
К>>Отсюда стремительно вытекает вопрос: а нет ли в этой группе нуля, который является идемпотентным множителем? (А он обычно есть — функция fail) К>>А если у нас есть 0 и 1, то нельзя ли сделать полукольцо со сложением? (А можно — класс MonadPlus)
HH>Может я туплю, но в начале у нас был аддитивный моноид, в котором нейтральный элемент почему-то назывался единицей.
Почему это аддитивный? Нейтральный элемент "единица" намекает на иное.
Перекуём баги на фичи!
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>Вот интересно, какой теоретический минимум необходим для объяснения монад на пальцах?
Кстати говоря, тут дискуссия была совсем о другом. Во всяком случае на тот момент, когда я присоединился к ней. Тут стоял вопрос о пользе от применения монад в классических мультипарадигменных языках, а не в языках подобных Хаскелю, где без них просто никак. И для такой дискуссии подобную математику по идее можно даже и не вспоминать, потому как иначе для сравнения придётся в начале перевести на язык математики все остальные фишки классических языков. )))
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
К>>Вот интересно, какой теоретический минимум необходим для объяснения монад на пальцах?
_>Кстати говоря, тут дискуссия была совсем о другом. Во всяком случае на тот момент, когда я присоединился к ней. Тут стоял вопрос о пользе от применения монад в классических мультипарадигменных языках, а не в языках подобных Хаскелю, где без них просто никак. И для такой дискуссии подобную математику по идее можно даже и не вспоминать, потому как иначе для сравнения придётся в начале перевести на язык математики все остальные фишки классических языков. )))
Тут два потока дискуссии: как понять и зачем использовать.
Про "как понять" я считаю, что теоркат избыточен, а командный подход (monkey see — monkey do!) ущербен. Но это мнение сложилось уже после вкуривания в теоркат.
Про "зачем использовать" — монады — это, во многом, идиома.
Прямое заимствование чужой идиомы в язык, где то же самое принято решать иными способами, (пусть и со скрипом, раз мы захотели позаимствовать что-то новое), — труд тяжёлый и странный.
Вот, к примеру, нуль. Его можно тремя способами протащить:
— через тип, поддерживающий нулевое значение (пустой контейнер, нулевой указатель, сигнальное значение вида NaN) и операции, толерантные к таким значениям
— через явное изменение потока управления (возврат и проверка кода ошибки и/или нулевых значений, соответствующее ветвление)
— через бросок и ловлю исключений
Любой из этих способов может оказаться эврикой! в конкретном месте программы.
Например, ветвился-ветвился, а потом сделал на монаде и превратил всё в линейный код.
Или гонял-гонял пустые строки по конвееру, а потом навтыкал throw по всей длине кода, и сразу выросла производительность.
Или кидал исключения на каждый чих, а потом переписал на if'ах, и производительность ещё круче выросла.
То есть, чужая идиома — это источник вдохновения, в первую очередь.
Перекуём баги на фичи!
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Покажи на yacc или спирит аналог вот такого кода _>Эм, а можно подробное описание задачи, которую решает этот код? ) А то я не настолько в курсе библиотек .net'a, что бы с ходу понять это.
Имитация простейшего отслеживания изменения цен на акции — выдаёт предупреждения при "изменении" тренда.
Разумеется, промышленный код выглядит слегка иначе и пример (вот исходник) на практике полезен не больше, чем ray tracer на linq.
При чём здесь yacc/spirit — я понять решительно отказываюсь. Подозреваю, это просто первый попавшийся страшный код по ключевому слову "Parse".
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Покажи на yacc или спирит аналог вот такого кода
_>Эм, а можно подробное описание задачи, которую решает этот код? ) А то я не настолько в курсе библиотек .net'a, что бы с ходу понять это.
"The lab defines an observable stock ticker using the Rx operators: Interval, Select, Scan and Publish. Then it calls the Rxx Parse operator and defines an in-line grammar that matches particular reversal trends, projecting them into an observable sequence of alerts."
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinix, Вы писали:
S>Имитация простейшего отслеживания изменения цен на акции — выдаёт предупреждения при "изменении" тренда.
S>Разумеется, промышленный код выглядит слегка иначе и пример (вот исходник) на практике полезен не больше, чем ray tracer на linq.
Не всем же на бирже торговать. Рейтрейсеру понятно нужно быстродействие. А вот "измненение тренда" есть не только в HFT
S>При чём здесь yacc/spirit — я понять решительно отказываюсь. Подозреваю, это просто первый попавшийся страшный код по ключевому слову "Parse".
yacc/spirit позволяют сделать парсер. Теоретически, идейка рабочая, получили парсер, прогнали данные и дело в шляпе. Только фокус в том, что yacc/spirit умеют парсить только строчки, что делает эту хрень бесполезной.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не всем же на бирже торговать. Рейтрейсеру понятно нужно быстродействие. А вот "измненение тренда" есть не только в HFT
Так и я не про биржу Для простых случаев там сам парсер по-моему нафиг не нужен, достаточно пары Observable.Scan() — для вычисления дельты и для определения смены знака дельты.
Для чего-то сложнее — сходу не скажу, надо будет предметно смотреть, но что-то я очень сомневаюсь в удобстве Rxx для действительно сложных случаев.
S>>При чём здесь yacc/spirit — я понять решительно отказываюсь. Подозреваю, это просто первый попавшийся страшный код по ключевому слову "Parse". I>yacc/spirit позволяют сделать парсер. Теоретически, идейка рабочая, получили парсер, прогнали данные и дело в шляпе. Только фокус в том, что yacc/spirit умеют парсить только строчки, что делает эту хрень бесполезной.
Не, фокус в том, что парсеры ЯП и parser combinators (а rxx — это именно последнее) — две ортогональные вещи. Парсеры ЯП могут внутри использовать произвольные подходы, а parser combinators могут быть использованы не только для разбора структурированного текста.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>Почему это аддитивный? Нейтральный элемент "единица" намекает на иное.
Тогда не понимаю... Откуда там берется полукольцо?
Чтобы было полукольцо должен быть моноид относительно операции сложения, полугруппа по умножению, дистрибутивность и ноль.
Если взять в качестве полугруппы по умножению например функции fi :a->a с композицией в качестве произведения,
то непонятно, какая будет аддитивная операция в этом полукольце?
А если взять функции f:b->c', g: a->b', то это вообще не группоид, потому что не определена композиция g(f(x)).
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, HrorH, Вы писали:
HH>Тогда не понимаю... Откуда там берется полукольцо? HH>Чтобы было полукольцо должен быть моноид относительно операции сложения, полугруппа по умножению, дистрибутивность и ноль. HH>Если взять в качестве полугруппы по умножению например функции fi :a->a с композицией в качестве произведения, HH>то непонятно, какая будет аддитивная операция в этом полукольце? HH>А если взять функции f:b->c', g: a->b', то это вообще не группоид, потому что не определена композиция g(f(x)).
Так, секундочку.
Элементы нашего полукольца — функции вида (x -> m y), а не просто (x), (m x) или функции (m x -> m y).
Изначально у нас моноид с умножением (a·b) x = (a x >>= b) и единицей return
return·f = f·return = f
f·(g·h) = (f·g)·h
Добавляем ноль: decline x = mzero или decline x = fail ""
decline·f = f·decline = decline
Добавляем сложение (a¦b) x = (a x `mplus` b x)
decline¦f = f¦decline= f
(f¦g)¦h = f¦(g¦h)
Вот насчёт дистрибутивности что-то сомненья погрызли, но вроде бы должна выполняться
f·(g¦h) ?= (f·g)¦(f·h)
Перекуём баги на фичи!
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>Про "как понять" я считаю, что теоркат избыточен, а командный подход (monkey see — monkey do!) ущербен. Но это мнение сложилось уже после вкуривания в теоркат.
Мне кажется, что проще всего объяснять на примерах из реально существующего ПО. Их не так много, но они есть. В основном во всяческих конвейерных штуках, типа DirectShow/GStreamer или boost.range/linq. Т.е. когда человек видит очень разные вещи, но за которыми стоит некая общая абстракция, он начинает её видеть сам на интуитивном уровне.
К>Любой из этих способов может оказаться эврикой! в конкретном месте программы. К>Например, ветвился-ветвился, а потом сделал на монаде и превратил всё в линейный код. К>Или гонял-гонял пустые строки по конвееру, а потом навтыкал throw по всей длине кода, и сразу выросла производительность. К>Или кидал исключения на каждый чих, а потом переписал на if'ах, и производительность ещё круче выросла.
К>То есть, чужая идиома — это источник вдохновения, в первую очередь.
Т.е. считать монады всего лишь одним из специфических паттернов проектирование? Причём реализуемом практически в любом языке программирования, но нужным на практике весьма редко? У меня сейчас такой взгляд на всё это...
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Мне кажется, что проще всего объяснять на примерах из реально существующего ПО. Их не так много, но они есть. В основном во всяческих конвейерных штуках, типа DirectShow/GStreamer или boost.range/linq. Т.е. когда человек видит очень разные вещи, но за которыми стоит некая общая абстракция, он начинает её видеть сам на интуитивном уровне.
Ну вообще, разнообразные конвееры — это необязательно монады, а ещё и аппликативные функторы.
_>Т.е. считать монады всего лишь одним из специфических паттернов проектирование? Причём реализуемом практически в любом языке программирования, но нужным на практике весьма редко? У меня сейчас такой взгляд на всё это...
Каждому языку свои паттерны.
Мне вот set comprehension очень нравится как паттерн, при написании всяких скриптов-числодробилок на питоне и даже на коммандкоме. Но только до тех пор, пока это зрительно можно охватить. То есть, явное декартово произведение — пожалуйста, ленивый конвеер — туда-сюда (на шелле — больше сюда, внутри питона — меньше), а комбинирующие их функции высшего порядка, теряющие в наглядности — это уже пас.
А на С++ так и в конвееры играть не особо хочется.
Перекуём баги на фичи!
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>"The lab defines an observable stock ticker using the Rx operators: Interval, Select, Scan and Publish. Then it calls the Rxx Parse operator and defines an in-line grammar that matches particular reversal trends, projecting them into an observable sequence of alerts."
Я уже понял всё из ссылки Sinix'а. Мдааа, очень смешной пример товарищи сделали...))) Всё тоже самое, что сделали они, делается обычным линейным кодом (причём вообще без библиотек каких-то) намного короче и проще — реально какой-то антипример получается...
Да, а если говорить не о данном конкретном примере, а вообще об идее, то тут у нас наблюдается банальный конечный автомат. Т.е. берём например boost.statechart и делаем точно такую же обобщённую хрень. И кстати для данного конкретного примера она опять же будет заметно страшнее линейного кода. )))
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>Ну вообще, разнообразные конвееры — это необязательно монады, а ещё и аппликативные функторы.
Ну да, в подобных библиотека там вообще каша из всего этого. Собственно я предполагаю, что их авторы даже и не задумывались о своих продуктах в подобных терминах.
К>Каждому языку свои паттерны. К>Мне вот set comprehension очень нравится как паттерн, при написании всяких скриптов-числодробилок на питоне и даже на коммандкоме. Но только до тех пор, пока это зрительно можно охватить. То есть, явное декартово произведение — пожалуйста, ленивый конвеер — туда-сюда (на шелле — больше сюда, внутри питона — меньше), а комбинирующие их функции высшего порядка, теряющие в наглядности — это уже пас. К>А на С++ так и в конвееры играть не особо хочется.
Так это если говорить о "голом" языке. А если накрутить специальную толстую библиотеку поддержки подобной вещи, то будет удобно в любом языке. Другое вопрос кто потратить своё время на написание такой библиотеки...
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
К>>Ну вообще, разнообразные конвееры — это необязательно монады, а ещё и аппликативные функторы. _>Ну да, в подобных библиотека там вообще каша из всего этого. Собственно я предполагаю, что их авторы даже и не задумывались о своих продуктах в подобных терминах.
Это характерный путь развития.
В тех же базах данных — сперва придумали такую штуку, как "база", даже язык Кобол сделали, а потом уже началось — ER, реляционная модель, нормальные формы и прочая, прочая, с математическим аппаратом.
Хотя возможно, что математики изобрели РСУБД в то же самое время, но где-то в горах Пало-Альто или в подземном бункере ЦЕРН — но дальше астроядерных исследований у них не пошло.
Перекуём баги на фичи!
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я уже понял всё из ссылки Sinix'а. Мдааа, очень смешной пример товарищи сделали...))) Всё тоже самое, что сделали они, делается обычным линейным кодом (причём вообще без библиотек каких-то) намного короче и проще — реально какой-то антипример получается...
В этом примере смешная генерация событий. Все остальное вполне нормально.
_>Да, а если говорить не о данном конкретном примере, а вообще об идее, то тут у нас наблюдается банальный конечный автомат. Т.е. берём например boost.statechart и делаем точно такую же обобщённую хрень. И кстати для данного конкретного примера она опять же будет заметно страшнее линейного кода. )))
Здесь получается контекстно свободная грамматика, которая, известно, не сводится к конечному автомату.
Вобщем не надо слов, покажи код, я хочу увидеть это чудо — линейный код который будет проще и понятнее БНФ грамматики.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Здесь получается контекстно свободная грамматика, которая, известно, не сводится к конечному автомату.
Вообще то как раз сводится, только не любая, а определённый подвид. )
I>Вобщем не надо слов, покажи код, я хочу увидеть это чудо — линейный код который будет проще и понятнее БНФ грамматики.
Эээ, ты хочешь сказать, что вот тот страшный ужас — это типа БНФ так задаётся? ))) Жуть какая... ) Собственно не удивительно, когда люди пытаются протащить какой-то свой инструмент вообще везде.
Насчёт кода... Я там до конца не разобрался с ним (лень читать их документацию), но насколько я понял по поверхностному взгляду линейным аналогом их кода будет что-то вроде:
Здравствуйте, alex_public, Вы писали:
I>>Здесь получается контекстно свободная грамматика, которая, известно, не сводится к конечному автомату.
_>Вообще то как раз сводится, только не любая, а определённый подвид. )
Ога, которая называется регулярная грамматика.
I>>Вобщем не надо слов, покажи код, я хочу увидеть это чудо — линейный код который будет проще и понятнее БНФ грамматики.
_>Эээ, ты хочешь сказать, что вот тот страшный ужас — это типа БНФ так задаётся? ))) Жуть какая... ) Собственно не удивительно, когда люди пытаются протащить какой-то свой инструмент вообще везде.
В примере нет никакого БНФ, но это можно сделать.
_>Насчёт кода... Я там до конца не разобрался с ним (лень читать их документацию), но насколько я понял по поверхностному взгляду линейным аналогом их кода будет что-то вроде:
Не надо было себя утруждать. Ты говорил, что yacc или спирит это на раз умеют.
Ну и ты задачу не решил, у тебя нет нигде обработки эвентов.
Вот похожая задача, есть некоторые эвенты, begin, end и тд. Они, понятно, соответсвуют друг другу. Могут быть вложеными. Нужно найти пару самого нижнего уровня, взять из нее какие то значения и бросить еще какой нибудь эвент
Покажи, как твой yacc и spirit смогут с эти справиться.
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Тут стоял вопрос о пользе от применения монад в классических мультипарадигменных языках, а не в языках подобных Хаскелю, где без них просто никак.
Но это не верно. В "языках подобных Хаскелю" без монад можно обходится точно так же, как и не в подобных. И нужны они в этих языках для одного и того же. Никакого разделения по признаку "подобие Хаскелю" тут нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>получается, что в классических императивных языках уже заложено большая часть самых полезных монад. В виде конструкций языка, библиотечных функций и т.п.
Нет, не получается. Монады можно использовать как инструмент обобщенной работы с изменяемыми переменными и исключениями (не для всяких исключений будут выполнятся законы, так что только с некоторыми разновидностями). Т.е. если можно писать (и типизировать) обобщенный код — значит монады скорее всего есть. Если же просто есть изменяемые переменные, исключения, списки и т.д., но работа с ними никак не обобщается — то нет никаких оснований говорить о том, что монады есть, "заложены" и т.д.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Это и будет та самая монада...
В данном случае вы сделали что-то Maybe-подобное, но механизм обобщения не показан. На самом деле понятно, как это предполагается использовать обобщенно, но проблема тут будет в том, что это обобщение не типизировано. Родственная проблема — семантическая неопределенность. Про (=<<) можно много чего сказать не зная ничего о конкретной имплементации, про ваш перегруженный сдвиг ничего сказать нельзя.
_>Да легко оно всё делается на практике и здесь. Вот только польза крайне сомнительна...
Ненужность чего угодно вообще легко обосновывается. Следите за руками:
1) На C++ пишется нечто, что автор реализации согласен считать X.
2) Реализация чего угодно на C++ выглядит, как правило, достаточно страшно, чтоб убедить, что с "нечто" лучше не связываться.
3) Раз уж имплементатор считает, что "нечто" — это X, то почему бы ему не поверить? Он же имплементатор — ему виднее.
4) Легко видеть, что польза X — крайне сомнительна.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
и всё.
I>Ну и ты задачу не решил, у тебя нет нигде обработки эвентов.
Есть там всё, просто для краткости внутри одного цикла. А так, для формализма, можешь раскинуть генерацию чисел и их анализ в две разные функции.
I>Вот похожая задача, есть некоторые эвенты, begin, end и тд. Они, понятно, соответсвуют друг другу. Могут быть вложеными. Нужно найти пару самого нижнего уровня, взять из нее какие то значения и бросить еще какой нибудь эвент
Что значит "есть"? ) У нас есть список объектов для анализа или что? )
I>Покажи, как твой yacc и spirit смогут с эти справиться.
Они вообще не для этих целей. Они обычно идут на предыдущем уровне — разбора текста в некие структуры. А анализ этих структур выполняется уже на следующем уровне другими инструментами.
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Но это не верно. В "языках подобных Хаскелю" без монад можно обходится точно так же, как и не в подобных. И нужны они в этих языках для одного и того же. Никакого разделения по признаку "подобие Хаскелю" тут нет.
Интересно будет посмотреть на работу с системными функциями в Хаскеле без монад. ) Т.е. и без IO и т.п... )
Re[13]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В данном случае вы сделали что-то Maybe-подобное, но механизм обобщения не показан. На самом деле понятно, как это предполагается использовать обобщенно, но проблема тут будет в том, что это обобщение не типизировано. Родственная проблема — семантическая неопределенность. Про (=<<) можно много чего сказать не зная ничего о конкретной имплементации, про ваш перегруженный сдвиг ничего сказать нельзя.
В каком это смысле не типизировано?
K>Ненужность чего угодно вообще легко обосновывается. Следите за руками:
Эм, вообще то в данной темке я не пытался это доказать, а наоборот просил народ имеющий большой опыт в этом привести побольше практических примеров подобной пользы. Т.е. мне самому интересно. Однако что-то никто практических ничего не предложил. Более того, несколько редких существующих известных примеров привёл опять же я. Из всего этого вывод о малой нужности сам собой напрашивается... Однако если кто-то приведёт интересные полезные примеры, то я (да и многие в этой темке) буду только рад. )
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не надо было себя утруждать. Ты говорил, что yacc или спирит это на раз умеют.
_>Не надо подделывать мои слова. Я говорил по поводу данного примера вот это http://www.rsdn.ru/forum/philosophy/5400854
yacc и spirit про то же. Только тебе сейчас неудобно говорить про парсинг, потому что yacc и spirit в таких задачах сосут не нагибаясь, они вообще для текста заточены.
I>>Ну и ты задачу не решил, у тебя нет нигде обработки эвентов.
_>Есть там всё, просто для краткости внутри одного цикла. А так, для формализма, можешь раскинуть генерацию чисел и их анализ в две разные функции.
Ого, и давно циклы в с++ стали реактивными ?
I>>Вот похожая задача, есть некоторые эвенты, begin, end и тд. Они, понятно, соответсвуют друг другу. Могут быть вложеными. Нужно найти пару самого нижнего уровня, взять из нее какие то значения и бросить еще какой нибудь эвент
_>Что значит "есть"? ) У нас есть список объектов для анализа или что? )
Нет никакого списка, есть, считай, один колбек или эвент, который файрится все время работы приложения.
I>>Покажи, как твой yacc и spirit смогут с эти справиться.
_>Они вообще не для этих целей. Они обычно идут на предыдущем уровне — разбора текста в некие структуры. А анализ этих структур выполняется уже на следующем уровне другими инструментами.
Правильно, об чем и речь. А с монадическими парсерами можно одним и тем же кодом разбирать как текст, так и любые потоковые данные, в т.ч. эвенты.
Re[14]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Эм, вообще то в данной темке я не пытался это доказать, а наоборот просил народ имеющий большой опыт в этом привести побольше практических примеров подобной пользы. Т.е. мне самому интересно. Однако что-то никто практических ничего не предложил. Более того, несколько редких существующих известных примеров привёл опять же я. Из всего этого вывод о малой нужности сам собой напрашивается... Однако если кто-то приведёт интересные полезные примеры, то я (да и многие в этой темке) буду только рад. )
У тебя вроде как позиция такая : "Я всё это могу на с++ (тупо императивно, yacc, spirit) наколбасить, следовательно монады не нужны"
К>for x in xs :
К> for y in foo(x) :
К> for z in bar(y) :
К> # вот тебе, бабушка, и флэтмап!
К>
Правильнее будет так:
for x in xs :
for y in foo(x) :
for z in bar(y) :
# вот тебе, заказчик-падла, и n²!
# А будешь выпендриваться перейду на рекурсию и будет тебе экспонента!
К>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>yacc и spirit про то же. Только тебе сейчас неудобно говорить про парсинг, потому что yacc и spirit в таких задачах сосут не нагибаясь, они вообще для текста заточены.
Это приблизительно тоже самое, что сказать "gcc сосёт у javac на компиляции java кода".
I>Ого, и давно циклы в с++ стали реактивными ?
Причём тут цикл то вообще? ) Он в данном случае относится к генерации набора значений (или эвентов в твоей терминологии), а не к анализу. Я же тебе говорю, можно из того кода выделить отдельно функцию анализа и указать её как обработчик сообщений — тогда никаких циклов не будет.
I>Нет никакого списка, есть, считай, один колбек или эвент, который файрится все время работы приложения.
А как мы тогда можем понять, что достигли самой глубокой вложенности? ) Может в следующем вызове будет ещё глубже? )
I>Правильно, об чем и речь. А с монадическими парсерами можно одним и тем же кодом разбирать как текст, так и любые потоковые данные, в т.ч. эвенты.
Обычный парсер (переводит текст в объектную структуру) можно написать и с монадам и без них. Какой-то там анализатор объектной структуры тоже можно написать и с монадами и без. Не понятно что ты всё же хочешь сказать то. )
Re[15]: Есть ли вещи, которые вы прницпиально не понимаете...
I>У тебя вроде как позиция такая : "Я всё это могу на с++ (тупо императивно, yacc, spirit) наколбасить, следовательно монады не нужны"
Если при этом императивно получится затратить такие же или меньшие усилия, то действительно монады не нужны. А если с ними можно быстрее добиться результата, то соответственно нужны. И у меня в этой темке как раз и был основной интерес в том, чтобы посмотреть на какие-то реальные примеры, на которых монады дают преимущество. Естественно не в Хаскеле, а в мультипарадигменных языках типа C++.
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Но это не верно. В "языках подобных Хаскелю" без монад можно обходится точно так же, как и не в подобных. И нужны они в этих языках для одного и того же. Никакого разделения по признаку "подобие Хаскелю" тут нет.
_>Интересно будет посмотреть на работу с системными функциями в Хаскеле без монад. )
Ничего интересного. Просто не будет повторного использования кода, написанного для монад. Все комбинаторы будут специализированными, только для IO. Либо, как вариант, будут использовать какую-нибудь альтернативный иерархии Functor-Applicative-Monad набор классов. Стрелки, к примеру.
_>Т.е. и без IO и т.п... )
Еще раз, "без монад" не означает "без IO".
Монады (в числе прочего) появляются только тогда, когда хотим работать с IO тем же набором инструментов, как с чем-нибудь другим.
Допустим у нас есть функция последовательного выполнения действий:
Если же под "без монад" вы подразумеваете "без использования того, что можно обобщить с помощью монад", то нет, нельзя. К примеру, обычные функции (a -> b) — это монада Reader.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>yacc и spirit про то же. Только тебе сейчас неудобно говорить про парсинг, потому что yacc и spirit в таких задачах сосут не нагибаясь, они вообще для текста заточены.
_>Это приблизительно тоже самое, что сказать "gcc сосёт у javac на компиляции java кода".
Удивительно, но это ты предложил yacc и spirit а не я
I>>Ого, и давно циклы в с++ стали реактивными ?
_>Причём тут цикл то вообще? )
И мне хочется узнать, ведь это ты его всунул в свое решение.
> Он в данном случае относится к генерации набора значений (или эвентов в твоей терминологии), а не к анализу. Я же тебе говорю, можно из того кода выделить отдельно функцию анализа и указать её как обработчик сообщений — тогда никаких циклов не будет.
В данном случае у тебя вообще все в цыкле, так что пример даже на псевдокод не тянет.
I>>Нет никакого списка, есть, считай, один колбек или эвент, который файрится все время работы приложения.
_>А как мы тогда можем понять, что достигли самой глубокой вложенности? ) Может в следующем вызове будет ещё глубже? )
А что тебя смущает ? Текстовый парсер как то справляется с такими задачами. Почему с другими данными должно быть иначе ?
I>>Правильно, об чем и речь. А с монадическими парсерами можно одним и тем же кодом разбирать как текст, так и любые потоковые данные, в т.ч. эвенты.
_>Обычный парсер (переводит текст в объектную структуру) можно написать и с монадам и без них. Какой-то там анализатор объектной структуры тоже можно написать и с монадами и без. Не понятно что ты всё же хочешь сказать то. )
Я тебе страшное скажу — любую вычислимую функцию можно написать на любом тьюринг-полном языке. Потому твои аргументы неинтересно читать.
Я привел пример монадического парсера а ты начал цепляться то к языку, хотя и ежу ясно, что в ветке речь не про C#, то еще к чему то
Вобщем сформулируй еще раз, что тебе не нравится и приведи, наконец, решение на yacc или спирите, и обоснуй чего ты хотел сказатьЮ только главное, не забудь мой аргумент про полноту по тьюрингу.
Re[16]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
>А если с ними можно быстрее добиться результата, то соответственно нужны. И у меня в этой темке как раз и был основной интерес в том, чтобы посмотреть на какие-то реальные примеры, на которых монады дают преимущество. Естественно не в Хаскеле, а в мультипарадигменных языках типа C++.
Да чет не похоже. Пример был, ты чего то при спирит и yacc говорил, потом привел полу-код, который ни на что не годится
Re[14]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В каком это смысле не типизировано?
В прямом. Напишите, к примеру, liftM и подумайте какой у нее тип.
_>Эм, вообще то в данной темке я не пытался это доказать, а наоборот просил народ имеющий большой опыт в этом привести побольше практических примеров подобной пользы. Т.е. мне самому интересно. Однако что-то никто практических ничего не предложил. Более того, несколько редких существующих известных примеров привёл опять же я. Из всего этого вывод о малой нужности сам собой напрашивается... Однако если кто-то приведёт интересные полезные примеры, то я (да и многие в этой темке) буду только рад. )
По поводу накидывания примеров, у меня позиция такая. Если по известным примерам человек не может оценить потенциал, то добавление примеров тут ничем не поможет, отношение никак не изменится.
_>Если при этом императивно получится затратить такие же или меньшие усилия, то действительно монады не нужны. А если с ними можно быстрее добиться результата, то соответственно нужны. И у меня в этой темке как раз и был основной интерес в том, чтобы посмотреть на какие-то реальные примеры, на которых монады дают преимущество. Естественно не в Хаскеле, а в мультипарадигменных языках типа C++.
Если под "мультипарадигменным языком" понимается C++ то нет, такие примеры привести нельзя потому, что усилия понадобятся существенно больше тех, которые нужны для написания идиоматического кода. Никакой поддержки ФП в C++ нет, а потому ничего кроме борьбы с языком, заканчивающейся неизбежным проигрышем это не даст. Когда рудиментарная поддержка ФП появляется — уже могут быть варианты, но в целом, как я уже сказал, в мультипарадигменном языке бенефиты запросто могут не стоить затраченных усилий. Это напрямую зависит от уровня поддержки ФП в языке.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
Да, я вот приблизительно про такое и писал. Это же всё довольно мрачновато выглядит... ) В то время как на других языках (которые тут обсуждали) всё наоборот и подобный код чаще всего выглядит проще варианта с монадами.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Удивительно, но это ты предложил yacc и spirit а не я
Что-то ты стал постоянно перевирать мои слова. Для этой задачи я предложил конечный автомат, а не yacc или spirit. Ну это если хочется обобщения, а так лично я бы просто в лоб написал, как и показал выше.
I>В данном случае у тебя вообще все в цыкле, так что пример даже на псевдокод не тянет.
Какой ещё псевдокод? ) Оно компилируется и работает. И выглядит (если раскидать на функции) в виде:
for(;;) Analyze(Generate());
А если хочешь через сообщения, то будет так (с той же функцией):
OnEvent(Event e){Analyze(e.value);}
И в чём проблема?
I>А что тебя смущает ? Текстовый парсер как то справляется с такими задачами. Почему с другими данными должно быть иначе ?
Текстовый парсер аналогично может решить подобную задачку, только если у него сразу есть все данные целиком.
I>Я привел пример монадического парсера а ты начал цепляться то к языку, хотя и ежу ясно, что в ветке речь не про C#, то еще к чему то
Где я к языку цеплялся? )
А насчёт парсера (хотя привёл ты пример совсем не парсера, а скорее некоторого анализатора коллекций, но это уже вопрос терминологии) на монадах как бы никто и не говорил что такое нельзя написать. Так же как, думаю, очевидно, что парсер без проблем пишется и без монад (собственно большинство так и написано). Но суть получаемого от монад преимущества ты не раскрыл вообще нигде.
Re[15]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В прямом. Напишите, к примеру, liftM и подумайте какой у нее тип.
Вообще то в том моём примере с boost.optional был как раз буквально этот код. И я что-то не увидел каких-то проблем с ним.
K>По поводу накидывания примеров, у меня позиция такая. Если по известным примерам человек не может оценить потенциал, то добавление примеров тут ничем не поможет, отношение никак не изменится.
Так речь идёт не о тестовых примерах придуманных для этого форума, а о реальной практике. Т.е. например о каких-то известных библиотеках или архитектурах. Но опять же на определённых языках.
K>Если под "мультипарадигменным языком" понимается C++ то нет, такие примеры привести нельзя потому, что усилия понадобятся существенно больше тех, которые нужны для написания идиоматического кода.
Ну а если скажем Питон возьмём? )
K>Никакой поддержки ФП в C++ нет, а потому ничего кроме борьбы с языком, заканчивающейся неизбежным проигрышем это не даст.
А чего конкретно в C++ не хватает для поддержки подобной функциональщины?
K>Когда рудиментарная поддержка ФП появляется — уже могут быть варианты, но в целом, как я уже сказал, в мультипарадигменном языке бенефиты запросто могут не стоить затраченных усилий. Это напрямую зависит от уровня поддержки ФП в языке.
Ага, т.е. в итоге похоже что вы согласны с моей оценкой пользы от монад...
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В данном случае у тебя вообще все в цыкле, так что пример даже на псевдокод не тянет.
_>Какой ещё псевдокод? ) Оно компилируется и работает. И выглядит (если раскидать на функции) в виде: _>И в чём проблема?
Не хочу за тебя додумывать. Очевидно, реактивная обработка у тебя не получилась, ты скипнул основную часть, так шта
I>>А что тебя смущает ? Текстовый парсер как то справляется с такими задачами. Почему с другими данными должно быть иначе ?
_>Текстовый парсер аналогично может решить подобную задачку, только если у него сразу есть все данные целиком.
Это заблуждение. Самый глубокий блок == листовой блок, т.е. тот у которого нет других блоков. Здесь нужен простейший автомат с магазином. Очевидно, все что нужно, это получить закрывающий токен, ни больше, ни меньше. Все что после этого токена никого не интересует.
I>>Я привел пример монадического парсера а ты начал цепляться то к языку, хотя и ежу ясно, что в ветке речь не про C#, то еще к чему то
_>Где я к языку цеплялся? )
Насколько коряво выглядит грамматика в query comprehension С# не имеет никакого отношения к монадам, вообще.
_>А насчёт парсера (хотя привёл ты пример совсем не парсера, а скорее некоторого анализатора коллекций, но это уже вопрос терминологии) на монадах как бы никто и не говорил что такое нельзя написать. Так же как, думаю, очевидно, что парсер без проблем пишется и без монад (собственно большинство так и написано). Но суть получаемого от монад преимущества ты не раскрыл вообще нигде.
Ты пока не показал никакого релевантного кода, вообще. Если так будет и дальше, мой вариант окажется наилучшим
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>получается, что в классических императивных языках уже заложено большая часть самых полезных монад. В виде конструкций языка, библиотечных функций и т.п.
K>Нет, не получается. Монады можно использовать как инструмент обобщенной работы с изменяемыми переменными и исключениями (не для всяких исключений будут выполнятся законы, так что только с некоторыми разновидностями). Т.е. если можно писать (и типизировать) обобщенный код — значит монады скорее всего есть. Если же просто есть изменяемые переменные, исключения, списки и т.д., но работа с ними никак не обобщается — то нет никаких оснований говорить о том, что монады есть, "заложены" и т.д.
А вот интересно было бы увидеть эдакий хит-парад монад, используемых в коде на хаскеле, отсортированный по частоте использования. Вроде: "из 12345 модулей на hackage 96% используют монаду List, 90% используют IO для ввода-вывода, 85% используют ST для мутабельных векторов, 61% использует Reader" и т.д.
Не удивлюсь, если 83% использованных монад придутся как раз на те вещи, что в императивных языках встроены.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>А вот интересно было бы увидеть эдакий хит-парад монад, используемых в коде на хаскеле, отсортированный по частоте использования. Вроде: "из 12345 модулей на hackage 96% используют монаду List, 90% используют IO для ввода-вывода, 85% используют ST для мутабельных векторов, 61% использует Reader" и т.д. DM>Не удивлюсь, если 83% использованных монад придутся как раз на те вещи, что в императивных языках встроены.
Такой хит-парад будет осмыслен только в сопоставлении с альтернативами:
— n1% используют монаду List во всей полноте
— n2% — ограничиваются синтаксисом set comprehension
— n3% — фолд-мап-фильтр
— n4% упорствуют в ереси и пишут на хаскелле, как на лиспе 50-х, с рукодельной рекурсией
— n1% используют функции высшего порядка над IO
— n2% — do-нотацию, шоб красиво было
— n3% — конвеер-панки, пишут >>= \_ -> ...
— n4% — хакают ввод-вывод, вручную расставляя энергичные вызовы сишных функций
— n1% используют Reader для протягивания неявных параметров
— n2% протягивают параметры вручную
— n3% обвязывают всё в гигантские let-выражения или ещё как-то выкручиваются
и т.д.
Тогда будет видно — где именно истинная сосисочность монады востребованы, а где земная оболочка бездумный синтаксический сахар.
Перекуём баги на фичи!
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не хочу за тебя додумывать. Очевидно, реактивная обработка у тебя не получилась, ты скипнул основную часть, так шта
Так это и не было темой обсуждения) Однако, как ты сам увидел, это делается даже ещё короче цикла. )
I>Это заблуждение. Самый глубокий блок == листовой блок, т.е. тот у которого нет других блоков. Здесь нужен простейший автомат с магазином. Очевидно, все что нужно, это получить закрывающий токен, ни больше, ни меньше. Все что после этого токена никого не интересует.
Ну конечно. )))
begin
begin
end//вот у нас тут листовой блок и что?
begin
begin
end//ещё листовой и вот он самый глубокий
end
end
I>Насколько коряво выглядит грамматика в query comprehension С# не имеет никакого отношения к монадам, вообще.
Тут дело как раз в в query comprehension, а не в C#. Я думаю что можно даже на C# (там же хотя бы переопределение операторов то есть) реализовать задание БНФ намного красивее, чем тот дикий ужас.
I>Ты пока не показал никакого релевантного кода, вообще. Если так будет и дальше, мой вариант окажется наилучшим
Под тот конкретный пример очевидно же что даже линейный код (и без всяких библиотек) вышел проще. Но это на самом деле довольно бредовое сравнение не имеющее особого смысла для нашей дискуссии и являющиеся лишь следствием плохого выбора примера (пример использование библиотеки явно должен быть удонее тупого кода в лоб). Реально же для подобного сравнения надо взять какую-то библиотеку для подобного же анализа коллекций, но реализованную не через монады (причём лучше на том же C#, чтобы влияние разницы языков не влезало). И сравнить удобство их использования.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну конечно. )))
Именно так — листовые.
I>>Насколько коряво выглядит грамматика в query comprehension С# не имеет никакого отношения к монадам, вообще.
I>>Ты пока не показал никакого релевантного кода, вообще. Если так будет и дальше, мой вариант окажется наилучшим
_>Под тот конкретный пример очевидно же что даже линейный код (и без всяких библиотек) вышел проще.
Твой линейный ни о чем. Код который я тебе дал он рабочий, надо только референсы на сборки добавить и запустить. А у тебя мусор.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Именно так — листовые.
Ну так тебе нужные листовые элементы или же один самый глубокий? Если первое, то нафига тебе вообще какие-то парсеры, если достаточно завести одну булеву переменную и всё. А если второе, то опиши как твой парсер будет работать не имея весь набор данных.
I>Твой линейный ни о чем. Код который я тебе дал он рабочий, надо только референсы на сборки добавить и запустить. А у тебя мусор.
Этот тоже можно запустить и получить такой же результат, причём он даже ни одной левой библиотеки не использует. )))
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Именно так — листовые.
_>Ну так тебе нужные листовые элементы или же один самый глубокий?
А что, слово "листовые" оставляет какие то варианты ?
>Если первое, то нафига тебе вообще какие-то парсеры, если достаточно завести одну булеву переменную и всё.
Пудозреваю "одну булеву переменную и всё" == автомат с магазином + одна булева переменная.
I>>Твой линейный ни о чем. Код который я тебе дал он рабочий, надо только референсы на сборки добавить и запустить. А у тебя мусор.
_>Этот тоже можно запустить и получить такой же результат, причём он даже ни одной левой библиотеки не использует. )))
Да, допилить напильником и дописать основную логику.
Re[16]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то в том моём примере с boost.optional был как раз буквально этот код. И я что-то не увидел каких-то проблем с ним.
Так я про обобщенный liftM2, sequence и т.д. а не специализированный для optional
_>Так речь идёт не о тестовых примерах придуманных для этого форума, а о реальной практике. Т.е. например о каких-то известных библиотеках или архитектурах. Но опять же на определённых языках.
Так Ikemefula вам привел пример — Reactive Extensions. Библиотека реальная, используемая на практике. И это в языке, в котором пользы от монад можно получить самый минимум. На момент написания этого поста ее установили nuget-ом 144788 раз.
_>Ну а если скажем Питон возьмём? )
Если возьмем Питон — тоже ничего хорошего не получится.
_>А чего конкретно в C++ не хватает для поддержки подобной функциональщины?
Да, собственно, всего. Там даже Upward Funarg Problem не решена. А это самый минимум, необходимый для того, чтоб вообще можно было о какой-то поддержке ФП говорить. Это даже в C# есть.
_>Ага, т.е. в итоге похоже что вы согласны с моей оценкой пользы от монад...
У нас с вами есть расхождение по вопросу их необходимости в чистом ФЯ. В Хаскеле монады используют потому, что могут. И они не существуют как-то изолированно — это только один из элементов общего принятого там "алгебраического" подхода к дизайну библиотек. И этот подход может быть полезен везде (хоть и в разной степени, потому что полагается на реализацию преимуществ, которые не во всех языках есть). Применение монад в гибридных языках не вопрос их (монад) полезности, а вопрос реализуемости в них (языках) такого подхода.
Просто декларируемая "гибридность" зачастую остается только декларацией, не подкрепленной чем-то практическим. В большинстве таких языков ФП-фичи существуют "для галочки"
Здравствуйте, D. Mon, Вы писали:
DM>Не удивлюсь, если 83% использованных монад придутся как раз на те вещи, что в императивных языках встроены.
"Встроены" не самое подходящее слово. Оно создает ложное впечатление о том, что обеспечивается равноценная монадам функциональность. Но песок — неважная замена овсу, в данном случае "встроенность" — красивое слово для обозначения того, что таких монад там нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Это же всё довольно мрачновато выглядит... ) В то время как на других языках (которые тут обсуждали) всё наоборот и подобный код чаще всего выглядит проще варианта с монадами.
Вопрос в том, насколько он подобный? Это декларативный код, который отличается от кода на "других языках", как код на прологе отличается от кода на фортране. Одно дело система контроля за эффектами и их комбинирования (оставляющая желать много лучшего, на самом деле), другое дело — отсутствие какого-то контроля и комбинирования.
Также, IO/ST код на хаскеле часто выглядит мрачно из-за "карательного" подхода. Т.е. функции для работы с ST-ссылками называются в стиле написаниеНазванияЭтойФункцииЯвляетсяНаказаниемЗаИспользованиеИзменяемыхСсылок, синтаксическая поддержка откровенно убогая/страшная (особенно в период, когда не было Monad Comprehensions, а Idiom Brackets и сейчас нет) и т.д. "Карательный" подход — это глупость, конечно, но это все решаемые проблемы.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[17]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Так я про обобщенный liftM2, sequence и т.д. а не специализированный для optional
Не вижу никаких проблем и с liftM2 в C++ — пишется в пару строк. Естественно подразумевая свою реализацию под каждый вид монад (например для optional). Если же подразумевается написать liftM2 подходящий для любой монады и просто использующий для непосредственной работы код liftM (который уже свой для каждого вида монад), то такое действительно сложно написать на C++. Но хочу заметить, что для многих монад прямая реализация liftM2 (а при большем числе аргументов тем более) будет более эффективна чем последовательное применение. Скажем для optional это может означать один if вместо двух. )
K>Так Ikemefula вам привел пример — Reactive Extensions. Библиотека реальная, используемая на практике. И это в языке, в котором пользы от монад можно получить самый минимум. На момент написания этого поста ее установили nuget-ом 144788 раз.
Если мы говорим про базовую идею Reactive Extension, то естественно к ней нет никаких претензий — это же один из самых известных паттернов проектирования (и кстати монады тут вообще ни при чём). Правда его очень часто реализуют в своём коде (там десятка строк достаточно на всё), а не подключают какие-то внешние библиотеки. Но и так тоже не плохо. Было бы... Если бы они не задумали притащить и сюда этот кривой linq синтаксис, который всё портит. Это же уже мания какая-то, пытаться всунуть его везде, даже если он и близко не подходит. Вот как раз на примере Ikemefula это очень хорошо видно. Там прослеживается попытка записать что-то типа БНФ через linq подобный синтаксис — так это же дикая жуть вышла! В то время как можно было придумать какой-то красивый способ задания БНФ (например использовать перегрузку операторов), взять тот же самый паттерн Наблюдатель и получить в итоге на том же C# красивый и удобный код. Правда монад тут скорее всего не было бы тогда... Так что пример Ikemefula для меня выглядит скорее как антипример. )))
K>Если возьмем Питон — тоже ничего хорошего не получится.
Ну так а хотя бы один подходящий мультипарадигменный язык есть?
K>Да, собственно, всего. Там даже Upward Funarg Problem не решена. А это самый минимум, необходимый для того, чтоб вообще можно было о какой-то поддержке ФП говорить. Это даже в C# есть.
Правильнее сказать, что решение не зашито жёстко в язык, а отдано на выбор программиста, т.к. различные решения могут иметь разную эффективность в разных условиях.
K>У нас с вами есть расхождение по вопросу их необходимости в чистом ФЯ. В Хаскеле монады используют потому, что могут. И они не существуют как-то изолированно — это только один из элементов общего принятого там "алгебраического" подхода к дизайну библиотек. И этот подход может быть полезен везде (хоть и в разной степени, потому что полагается на реализацию преимуществ, которые не во всех языках есть). Применение монад в гибридных языках не вопрос их (монад) полезности, а вопрос реализуемости в них (языках) такого подхода.
Хех, похоже что дискуссия о пользе монад в различных языках всё же не возможна, пока не определимся с вопросом пользы монад вообще. Потому как допустим у нас есть два противоположных тезиса:
1. В C++ монады редко используются из-за того, что язык не подходящий (подразумевая что сами по себе монады крайне полезные везде, но C++ такой убогий, что не позволяет удобно использовать их везде).
2. В Хаскеле монады используются постоянно из-за того, что без них совсем грустно (подразумевая что сами по себе монады нафиг не нужны, но Хаскель такой убогий, что без них заниматься реальной работой очень неудобно).
Какой из них ближе к истине? ) Зависит как раз от вопроса применимость самой концепции монад к реальному миру. Лично по моим ощущениям: задачи отлично ложащиеся на концепцию монад в природе есть, но их совсем не много.
K>Просто декларируемая "гибридность" зачастую остается только декларацией, не подкрепленной чем-то практическим. В большинстве таких языков ФП-фичи существуют "для галочки"
Здравствуйте, Klapaucius, Вы писали:
K>Также, IO/ST код на хаскеле часто выглядит мрачно из-за "карательного" подхода. Т.е. функции для работы с ST-ссылками называются в стиле написаниеНазванияЭтойФункцииЯвляетсяНаказаниемЗаИспользованиеИзменяемыхСсылок, синтаксическая поддержка откровенно убогая/страшная (особенно в период, когда не было Monad Comprehensions, а Idiom Brackets и сейчас нет) и т.д. "Карательный" подход — это глупость, конечно, но это все решаемые проблемы.
Так тут возможно и кроется один из ключевых моментов дискуссии: монады широко используются в Хаскеле потому что он это позволяет или же потому что он к этому принуждает (без них намного неудобнее)?
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
DM>>Не удивлюсь, если 83% использованных монад придутся как раз на те вещи, что в императивных языках встроены. K>"Встроены" не самое подходящее слово. Оно создает ложное впечатление о том, что обеспечивается равноценная монадам функциональность.
Нет, я на такое не намекаю даже. Встроены состояния, встрен ввод-вывод, встроены исключения. Т.е. не сами именно монады, но те вещи, ради которых монады, возможно, задействованы в 83% кода на хаскеле. Не пишут же монадный код ради самих монад, ими решают какие-то определенные нужды.
K> Но песок — неважная замена овсу, в данном случае "встроенность" — красивое слово для обозначения того, что таких монад там нет.
В данном случае нам нужен именно песок (ввод-вывод, состояния..).
Re[18]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Если же подразумевается написать liftM2 подходящий для любой монады
Да, именно это и подразумевается.
_>и просто использующий для непосредственной работы код liftM (который уже свой для каждого вида монад), то такое действительно сложно написать на C++.
Вообще-то liftM2 с помощью только liftM не написать, хоть на C++, хоть на чем угодно другом. Тем не менее, написать liftM2 для любой монады, разумеется, можно.
_>один if вместо двух.
Да, если оптимизатора нормального нету.
_>Если мы говорим про базовую идею Reactive Extension, то естественно к ней нет никаких претензий — это же один из самых известных паттернов проектирования
Нет, базовая идея — это комбинаторы для этого "одного из самых известных паттернов проектирования" и в них же — комбинаторах — весь его смысл.
_>Ну так а хотя бы один подходящий мультипарадигменный язык есть?
Подходящий для чего?
_>Правильнее сказать, что решение не зашито жёстко в язык, а отдано на выбор программиста, т.к. различные решения могут иметь разную эффективность в разных условиях.
Вот только лучшего и наиболее практичного решения среди вариантов выбора для программиста на C++ нет. А то, что есть — вообще трудно считать "решениями UFP".
_>1. В C++ монады редко используются из-за того, что язык не подходящий (подразумевая что сами по себе монады крайне полезные везде, но C++ такой убогий, что не позволяет удобно использовать их везде). _>2. В Хаскеле монады используются постоянно из-за того, что без них совсем грустно (подразумевая что сами по себе монады нафиг не нужны, но Хаскель такой убогий, что без них заниматься реальной работой очень неудобно).
Моя позиция близка к 1) с той поправкой, что вместо "редко используются" будет "не используются".
_>задачи отлично ложащиеся на концепцию монад в природе есть, но их совсем не много.
Вот уж точно. Возвращать что-то из одних функций и потом передавать в другие — это крайне экзотическая задача. В реальной жизни этого, разумеется, программисты никогда не делают.
_>Возможно. Но думаю что будущее всё равно за гибридами.
В краткосрочной перспективе — да, в среднесрочной — нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так тут возможно и кроется один из ключевых моментов дискуссии: монады широко используются в Хаскеле потому что он это позволяет или же потому что он к этому принуждает (без них намного неудобнее)?
Вы не поняли, "карательный" подход сдерживает использование IO/ST. А данная ветка дискуссии вообще о том, что "использовать IO" и "использовать монады" — это не одно и то же. Хаскельная базовая библиотека действительно так спроектирована, что она с одной стороны принуждает использовать IO/ST, а с другой — сдерживает их использования для пресечения "злоупотребления" или аналогичного сомнительного повода. Но монады-то тут причем?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Нет, я на такое не намекаю даже. Встроены состояния, встрен ввод-вывод, встроены исключения. Т.е. не сами именно монады, но те вещи, ради которых монады, возможно, задействованы в 83% кода на хаскеле. Не пишут же монадный код ради самих монад, ими решают какие-то определенные нужды.
Монады задействованы для того, чтоб повторно использовать код. А IO/ST, вне зависимости от того, были бы они монадами или нет, для того, чтоб в языке были нормальные комбинирующиеся комбинаторы при сохранении возможности пользоваться изменяемым состоянием (без которого все рано никак нельзя). Они для того, чтоб можно было писать чистый код и оптимизировать его, а не для того, чтоб массив менять по месту. Потому, что второе и без них можно, а вот первое — нельзя (упрощенно говоря, понятно, что есть другие способы получить это, помимо IO/ST). Поэтому говорить, что IO/ST в хаскеле существуют для того же, для чего в императивных языках состояния, по моему, в корне неверно.
Из этого заблуждения все подобные разговоры и растут. Понятно, что человек ставит вопрос таким образом: "IO/ST нужны для того, чтоб было изменяемое состояние" и потом недоумевает: "но в моем Алгол++ изменяемое состояние есть без всяких IO/ST, как же так?". Ну а IO/ST на самом деле нужно для того, чтоб в языке были функции, которых в Алгол++ как раз и нет — одни процедуры.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[19]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K> Тем не менее, написать liftM2 для любой монады, разумеется, можно.
Ну правильно, весь вопрос в том, где будет браться информация об особенностях конкретной монады. Кстати здесь какой вариант подразумевался?
K>Нет, базовая идея — это комбинаторы для этого "одного из самых известных паттернов проектирования" и в них же — комбинаторах — весь его смысл.
Ага, на базе sql-подобного языка (он для коллекций то даже далеко не идеал, а уж тут вообще молчу) — в топку!
_>>Ну так а хотя бы один подходящий мультипарадигменный язык есть? K>Подходящий для чего?
Для широкого использования монад.
K>Вот уж точно. Возвращать что-то из одних функций и потом передавать в другие — это крайне экзотическая задача. В реальной жизни этого, разумеется, программисты никогда не делают.
А причём тут монады? )))
Re[13]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Вы не поняли, "карательный" подход сдерживает использование IO/ST. А данная ветка дискуссии вообще о том, что "использовать IO" и "использовать монады" — это не одно и то же. Хаскельная базовая библиотека действительно так спроектирована, что она с одной стороны принуждает использовать IO/ST, а с другой — сдерживает их использования для пресечения "злоупотребления" или аналогичного сомнительного повода. Но монады-то тут причем?
Монады тут при том, что хотя они не обязательны, они сильно облегчают работу. Кстати, когда я когда смотрел примеры работы на Хаскеле с системными задачами (например работа с неким gui фреймворком), то там обычно вообще всё приложение занимала одна гигантская IO монада! Мне кажется, что всё же авторы языка подразумевали несколько иные пропорции. Но как видим при столкновение с практическими, а не академическими задачками, мы получаем вот такую реальность...
Так вот лично мне вся эта ситуация всё же кажется следствием недостатков Хаскеля (которые монады слегка подправляют), а не преимуществом позволяющим свободно использовать монады. )))
Хотя для чистоты эксперимента нам нужна всего лишь один простой пример: язык программирования в котором монады реализуются так же легко, как и в Хаскеле, но при этом не имеющий вышеописанных проблем Хаскеля. Соответственно, если мы увидим, что и в нём люди используют монады на каждом шагу, то это будет означать их реальную повсеместную пользу. Ну а если же нет, то... )))
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Нахлобуч, Вы писали:
G>>Или не до конца понимаете в программировании? Н>Не совсем программирование, но все же. Не могу понять, в чем такая прелесть vi/emacs (если пользователи не врут).
Там довольно мощные средства обработки текста.
Я сейчас для работы с кодом перелез на MSVS, но время от времени использую vim для вспомогательных задач. Например, сейчас я работаю с исходниками, обрабатывающими tsv-файлы. Часто бывает нужно, например, найти все строки, где в нужном столбце заданное значение. Или добавить ко всем значениям в определённом столбце порядковый индекс. Или поменять столбцы местами. Ну и т.д.
Очень часто бывает нужно вставить кусок текста в юниттест, при этом нужно экранировать все кавычки.
vim имеет удобно интегрированную поддержку регулярных выражений, что позволяет легко и быстро производить такую обработку текста.
vim я использовал для кодинга на с/с++/erlang/tcl/python/bash много лет. Потом решил освоить emacs, но за несколько лет так и не смог отучить его от некоторых неприятных особенностей поведения. Главной неприятностью оказалась его принципиальная однопоточность, а следовательно всякие медленные операции вроде парсинга исходников нельзя перевести в фон. Поэтому лет 5 назад перелез на Eclipse, а сейчас на MSVS, т.к. пишу на шарпе.
С уважением, Artem Korneev.
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>> Тем не менее, написать liftM2 для любой монады, разумеется, можно. _>весь вопрос в том, где будет браться информация об особенностях конкретной монады.
liftM2 можно написать для любой монады безотносительно ее особенностей.
_>Ага, на базе sql-подобного языка
Не обязательно.
_>(он для коллекций то даже далеко не идеал, а уж тут вообще молчу) — в топку!
Непонятно, почему вам не нравится именно query expressions. Они как то выделяются из всего остального что ли? По моему, в C# синтаксис буквально всего страшнее атомной войны. Ну так даже query expressions часто лучше, чем лямбда-лапша.
_>Для широкого использования монад.
Есть широкий спектр языков в которых можно какую-то пользу от монад в какой-то форме получать. Ну ее и получают.
K>>Вот уж точно. Возвращать что-то из одних функций и потом передавать в другие — это крайне экзотическая задача. В реальной жизни этого, разумеется, программисты никогда не делают. _>А причём тут монады? )))
При том, что вот для этого монады и применяются. Т.е. если вы пишете на брейнфаке, например, то практической пользы от монад не будет. Как только появляются какое-то подобие функций, так сразу можно и какую-то пользу извлекать и по мере того, как подобие функций становится функцией — все больше и больше.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Dair, Вы писали:
D>>Для меня загадка — современные алгоритмы шифрования (криптографии). Мат.аппарата не хватает
D>>На практическом уровне — public key/private key понятно, но чо там внутри — чисто магия.
_>Да ладно, если говорить о принципах, то там же всё вообще тривиально.
_>Вот смотри, предположим у нас есть функция y=exp(x); и соответственно обратная ей x=ln(y); Причём (и это ключевой момент) ln вычисляется намного дольше, чем exp. Кстати, это и для обычных exp и ln справедливо, а в асимметричной криптографии используется спец. вариант, в котором ln вычисляется годами... Теперь, при наличие пары таких функций, мы можем тривиально наладить защищённый канал.
_>Вот предположим у нас есть два человека (1 и 2) с каждый стороны и ещё третий, прослушивающий канал. 1 и 2 генерируют по одному случайному числу k1 и k2. Затем считают от них p1=exp(k1) и p2=exp(k2). И отсылают друг другу. В итоге у первого есть k1 и p2, у второго k2 и p1, а у прослушивающего p1 и p2. Теперь первые два считают число z=p2^k1=p1^k2=exp(k1*k2) — теперь у них есть некий общий секрет z, который они могут использовать например как ключ для обычного блочного шифрования данных и спокойно обмениваться ими. Ну а бедный подслушивающий будет занят вычислениями ln(p1) или ln(p2), для того чтобы получить тот же самый z...
Насколько я понимаю — это все работает только в том случае, если третий человек умеет только читать канал, но не умеет в него писать?? Потому что если он умеет писать, то он банально перехватит от юзера1 его p1 и заменит на p1_fake=exp(k1_fake). для юзера2 тоже самое, его p2 меняется на p2_fake=exp(k2_fake) и отправляется юзеру1.
В результате слушатель может читать сообщения и того и другого юзера. ПРичему например полученное от юзера1 сообщение он может зашифровать используя p2^k1_fake и отправить юзеру2 и оба юзера будут думать, что они друг с другом разговаривают.
От этого же как то защищаются, вроде всякие сертификаты как раз для это?? Можно на таком же уровне, для дошкольников, объяснить как они работают??
Re[14]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Монады тут при том, что хотя они не обязательны, они сильно облегчают работу.
И в чем, по вашему, специфика этого облегчения? Почему тут вы видите, что они облегчают, а относительно других языкуов у вас сомнения?
_>Кстати, когда я когда смотрел примеры работы на Хаскеле с системными задачами (например работа с неким gui фреймворком), то там обычно вообще всё приложение занимала одна гигантская IO монада!
Что за гигантская монада? И что значит "все приложение занимает"? Вы это можете как-то расшифровать?
_>Мне кажется, что всё же авторы языка подразумевали несколько иные пропорции. Но как видим при столкновение с практическими, а не академическими задачками, мы получаем вот такую реальность...
Ну так IO и нужно для "системных задач". Если вы пишете вычисления факториалов, то никакой пользы от контроля за эффектами нет, тут какой-нибудь ML не хуже чистого языка. Ну, а чем больше "системных задач", тем больше пользы от системы контроля за эффектами, в случае хаскеля — от IO/ST.
_>Хотя для чистоты эксперимента нам нужна всего лишь один простой пример: язык программирования в котором монады реализуются так же легко, как и в Хаскеле, но при этом не имеющий вышеописанных проблем Хаскеля. Соответственно, если мы увидим, что и в нём люди используют монады на каждом шагу, то это будет означать их реальную повсеместную пользу. Ну а если же нет, то... )))
О каких проблемах идет речь? Об использовании IO для того, для чего IO предназначено? И где тут проблема? Вы свои претензии как-то более конкретно выразите, без "больших монад", которые "место занимают".
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Dair,
D>Для меня загадка — современные алгоритмы шифрования (криптографии). Мат.аппарата не хватает
D>На практическом уровне — public key/private key понятно, но чо там внутри — чисто магия.
Мне понравилась аналогия с красками и часами. Если мне придётся кому-нибудь объяснять эти вещи, я тоже воспользуюсь этими аналогиями — настолько они интуитивны.
LCR>Вот очень (имхо) наглядное и понятное видео, всего лишь 5 минут: LCR>http://www.youtube.com/watch?v=3QnD2c4Xovk
LCR>Мне понравилась аналогия с красками и часами. Если мне придётся кому-нибудь объяснять эти вещи, я тоже воспользуюсь этими аналогиями — настолько они интуитивны.
С красками понимал и до этого, а вот с числами — вот, щёлкнуло и встало на правильное место в мозгу.
Огромное спасибо!
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Greeter,
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Здравствуйте, lazy/cjow/rhrr, Вы писали:
LCR>Я не понимаю Теорию Категорий
Я тоже не понимаю. Читая введение в какой-то книжке, мне очень понравился магический переход от совокупности объектов и стрелок к совокупности только стрелок. Нет объектов, есть только связи, бритва оккама в терминальной стадии.
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>liftM2 можно написать для любой монады безотносительно ее особенностей.
То, что для любой можно — это без сомнения. Вопрос в том, как мы будем учитывать индивидуальные особенности этой монады. Можно это сделать написав код liftM2 для каждого вида монад отдельно (это кстати наиболее оптимизированный по быстродействию, но затратный по разработке вариант). А можно вынести учёт особенностей в отдельную абстракцию (и эти сущности уже должны быть под каждый тип монад) и тогда соответственно можно написать как бы единый код liftM2 для всех типов монад. Вот я соответственно и спрашиваю, в какой конкретно абстракции предлагается скрывать особенности реализации конкретного вида монад.
K>Непонятно, почему вам не нравится именно query expressions. Они как то выделяются из всего остального что ли? По моему, в C# синтаксис буквально всего страшнее атомной войны. Ну так даже query expressions часто лучше, чем лямбда-лапша.
Неее, мне не именно query expressions. Ведь это всего лишь вариант записи. Но даже если мы записываем через лямбды, то всё равно набор базовых примитивов остаётся как раз полностью соответствующим sql. И вот он то мне и не нравится. Собственно он и для баз данных мне не особо, но там ещё можно терпеть по определённым причинам (хотя в последнее время nosql стараюсь использовать — намного удобнее). А уж когда это суют не только в базы данных, а буквально везде (в c# мире я имею в виду), то получается реальный ужас.
K>Есть широкий спектр языков в которых можно какую-то пользу от монад в какой-то форме получать. Ну ее и получают.
А есть ли среди этого широкого спектра хотя быть один язык со следующими свойствами:
— компилируется в нативный код
— поддерживает императивную парадигму
— не совсем маргинальный.
У меня один подобный язык есть на примете (на букву O который ), но я если честно не в курсе как там обстоят дела с монадами. ))) Я когда игрался с ним, то ничего подобного вроде не встречал.
K>При том, что вот для этого монады и применяются. Т.е. если вы пишете на брейнфаке, например, то практической пользы от монад не будет. Как только появляются какое-то подобие функций, так сразу можно и какую-то пользу извлекать и по мере того, как подобие функций становится функцией — все больше и больше.
Безусловно. Но только в тех случаях (на мой взгляд совсем не частых), когда реальная задача хорошо ложится на концепцию монад. Однако в некоторых языка монады используются явно гораздо чаще этого. И я предполагаю, что это не от хорошей жизни, а как раз от того, что там кругом "только функции". )
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Jack128, Вы писали:
J>Насколько я понимаю — это все работает только в том случае, если третий человек умеет только читать канал, но не умеет в него писать?? Потому что если он умеет писать, то он банально перехватит от юзера1 его p1 и заменит на p1_fake=exp(k1_fake). для юзера2 тоже самое, его p2 меняется на p2_fake=exp(k2_fake) и отправляется юзеру1. J>В результате слушатель может читать сообщения и того и другого юзера. ПРичему например полученное от юзера1 сообщение он может зашифровать используя p2^k1_fake и отправить юзеру2 и оба юзера будут думать, что они друг с другом разговаривают.
Не совсем. Просто задачи шифрования канала передачи данных (не обмениваясь при этом секретом в реале) и задача проверки личности собеседника — это в общем то никак не связанные между собой задачи. Т.е. теоретически возможно первое само по себе, возможно второе само по себе. И возможен вариант когда обе техники вместе работают — это как раз вариант SSL.
J>От этого же как то защищаются, вроде всякие сертификаты как раз для это?? Можно на таком же уровне, для дошкольников, объяснить как они работают??
Да там всё очень просто. С одной стороны (которую требуется идентифицировать) присылается не просто p1=exp(k1), а: он же, плюс информация о ресурсе m и плюс электронная подпись s с помощью некоторого ключа c. Электронная подпись s — это всего лишь некий хэш от m и p1, зашифрованный (что-то типа s=exp(h(m, p1)*c); ) ключoм c. А ключ c — это опять же некое случайное число, хранящееся в главном сейфе (типа мегаценность!) центра сертификации. При этом r=exp(c) (так называемый корневой сертификат этого центра) предустановлен в поставке браузера (если мы например про https говорим). Собственно набор p1, m, s и образуют "сертификат" (хотя там ещё куча всякой служебной информации есть, типа сроков, имени центра и т.п., но это уже не главное). Соответственно дальше действия простые — другая сторона получив p1, m, s и имея у себя r путём простейшей проверки может гарантированно убедиться, что p1 честно соответствует m (а это обычно что-то вроде текста "ООО Рога и Копыта"). Очевидно, что прислать другой p1 для того же m невозможно, без знания какого-то нибудь из c. Т.е. при условии, что ни один официальных центров сертификации не занимается жульничеством, система даёт гарантию, что никто не влезет посередине подобного соединения.
Re[15]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И в чем, по вашему, специфика этого облегчения? Почему тут вы видите, что они облегчают, а относительно других языкуов у вас сомнения?
Потому как частенько они облегчают решение не проблем реального мира, а проблем данного языка.
K>Что за гигантская монада? И что значит "все приложение занимает"? Вы это можете как-то расшифровать?
Ну практически весь код приложения расположен внутри монады IO. Т.е. как бы красивого декларативного ленивого кода Хаскеля, которым он вроде как и хорош, в приложение уже считай что нет вообще.
K>Ну так IO и нужно для "системных задач". Если вы пишете вычисления факториалов, то никакой пользы от контроля за эффектами нет, тут какой-нибудь ML не хуже чистого языка. Ну, а чем больше "системных задач", тем больше пользы от системы контроля за эффектами, в случае хаскеля — от IO/ST.
Да, только если классический ленивый декларативный Хаскель (там где он такой применим) обычно обходит другие языки по выразительности, то его монадная часть (подразумевая IO/ST) скорее наоборот, заметно менее удобна, чем аналоги из других языков.
Т.е. как я понимаю, авторы языка задумывали концепцию вида "максимально красивый язык по большей части и плюс небольшие островки неудобного кода, концентрирующие в себе работу с нехорошими вещами". Но при столкновение с реальностью (программированием сильно системных вещей) оказалось, что эти неудобные островки расширяются до размера всего приложения, а места для красивого кода уже и не остаётся вовсе.
Но это всё на самом деле уже совсем другая тема. Это я по сути заговорил уже о самом Хаскеле, а не о монадах.
K>О каких проблемах идет речь? Об использовании IO для того, для чего IO предназначено? И где тут проблема? Вы свои претензии как-то более конкретно выразите, без "больших монад", которые "место занимают".
Проблемы "хаскеля без монад" отлично продемонстрировали вы сами в том примере, где показали реализацию IO/ST без монад. Жуть же полная, хотя да, работает...
Проблемы "хаскеля с монадами" я изложил выше.
И естественно это всё актуально не для любого софта, а для интенсивно работающего с системой. Т.е. скажем для какого-нибудь конвертера запускающегося из командной строки и состоящего на 95% из сложного алгоритма такие проблемы точно не актуальны. Только вот в современном мире подобное ПО — это же скорее исключение...
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Этот тоже можно запустить и получить такой же результат, причём он даже ни одной левой библиотеки не использует. )))
Прямо такой же — не получится. Потому, что в исходном коде подразумевается реактивность. Т.е. ваша задача — не энергичный цикл (который встанет в ожидании следующего события, заморозив нативный поток и отожрав мегабайт address space процесса), а как раз функция OnEvent(Event e){Analyze(e.value);}.
Когда вы её напишете, можно будет сравнить объём и понятность кода.
В простых случаях у вас будет получаться более-менее понятный код. Примерно как в обработчике события MouseClick, который отлавливает Double Click путём сравнения текущего клика с предыдущим. Ну, только надо будет руками декларировать все переменные состояния — скалярные в случае тикера/тренда и стек в случае обработчика листьев дерева. А с монадами и прочими автогенераторами стейт-машина генерируется автоматически компилятором.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>То, что для любой можно — это без сомнения. Вопрос в том, как мы будем учитывать индивидуальные особенности этой монады.
Зачем учитывать какие-то особенности? _>Можно это сделать написав код liftM2 для каждого вида монад отдельно (это кстати наиболее оптимизированный по быстродействию, но затратный по разработке вариант).
То есть вы заранее полагаете, что компилятор хуже вас разбирается в оптимизациях, и хотите делать всё вручную. Почему?
_>А можно вынести учёт особенностей в отдельную абстракцию (и эти сущности уже должны быть под каждый тип монад)
А это ещё зачем? Все особенности монады уже есть в самой монаде. Никакие дополнительные сущности под каждый тип не нужны. Вы же не пишете какие-то дополнительные сущности под каждый тип коллекции, чтобы разрешить алгоритмам из STL работу с ними.
_>Неее, мне не именно query expressions. Ведь это всего лишь вариант записи. Но даже если мы записываем через лямбды, то всё равно набор базовых примитивов остаётся как раз полностью соответствующим sql. И вот он то мне и не нравится. Собственно он и для баз данных мне не особо, но там ещё можно терпеть по определённым причинам (хотя в последнее время nosql стараюсь использовать — намного удобнее). А уж когда это суют не только в базы данных, а буквально везде (в c# мире я имею в виду), то получается реальный ужас.
Вы по-прежнему не понимаете основной идеи RX. Вот, скажем, когда вы пишете императивный код, который энергично процессит какие-то структуры, вы почему-то мало заботитесь о том, что нужно учитывать все эти ваши локальные переменные, их scope, частоту обращений, и прочее. Регистры за вас прекрасно выбирает компилятор. Вы пишете код типа x[i] = yy[i*aWidth+yoffset+j]*MulY + xx[i*aHeight+xoffset+j]*MulX и не паритесь о том, что на самом деле это элементарно записывается в обратной польской записи, и там даже можно сэкономить на лишних push и pop, подбирая порядок операций. Это привычно и удобно.
А вот когда речь идёт о коде, в котором, к примеру, поток управления диктуется снаружи, вы теряетесь. Попробуйте представить себе код, вычисляющий x[i], в котором нет возможности обратиться к "переменным" типа yy[...], а вместо них приходят внешние вызовы вроде set_yoffset(), set_MulY(), set_i().
При этом про порядок этих вызовов вы знаете не очень много — т.е. он сегодня один, а завтра другой. Конечно же, для каждого случая формулы и порядка прихода значений "легко" написать стейт-машину — вот только при "традиционной" реализации стейт-машины объём её кода будет несопоставим с приведённой формулой, и восстановить её логику крайне тяжело. Как вы поймёте, что делает эта стейт-машина, читая кусочки методов?
RX — это попытка записать подобные штуки в понятном виде. Т.е. вы пишете как бы активный код, который "сам" превращается в реактивный. А уж в каком виде вам удобнее писать предикаты и проекции — ваше дело. Если вам хочется иметь минимум синтаксического мусора, то query comprehensions — ваш выбор. Если вас раздражает SQL (а судя по вашим комментариям про NoSQL это именно так), то вам подойдёт лямбда-синтаксис, с явным выписыванием всех этих (previousEvent, currentEvent) => { return previousEvent.ClickPoint.InRect(new Rect(0, 0, 5, 5).Offset(currentEvent.ClickPoint.X, currentEvent.ClickPoint.Y);}.
С моей точки зрения это та же ручная state machine, вид сбоку.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вот я соответственно и спрашиваю, в какой конкретно абстракции предлагается скрывать особенности реализации конкретного вида монад.
Вы переводите разговор в плоскость цены абстракции? Ну, я считаю, что если существует такая возможность улучшить производительность, как выделение некоего сочетания операций и переписывание их определенным образом, то ее неплохо использовать, написав правило перезаписи, в соответствии с которым компилятор перепишет паттерн в более эффективный код автоматически. В конце концов, чистые функции и "алгебраизация" библиотек в том числе для этого и нужны.
Т.е., например, liftM2 для списков дает после специализации два concatMap, которые "фьюзятся" какой-нибудь build/foldr техникой.
_>Но даже если мы записываем через лямбды, то всё равно набор базовых примитивов остаётся как раз полностью соответствующим sql. И вот он то мне и не нравится.
Не понятно, о каких "базовых примитивах" идет речь если мы используем ФВП и лямбды?
_>А есть ли среди этого широкого спектра хотя быть один язык со следующими свойствами: _>- компилируется в нативный код _>- поддерживает императивную парадигму _>- не совсем маргинальный. _>У меня один подобный язык есть на примете (на букву O который ), но я если честно не в курсе как там обстоят дела с монадами. ))) Я когда игрался с ним, то ничего подобного вроде не встречал.
Зависит от того, что понимать под словом "маргинальный". Если вопрос сводится к тому, есть ли польза от использования монад в окамле — то ответ: да, есть.
_>Безусловно. Но только в тех случаях (на мой взгляд совсем не частых), когда реальная задача хорошо ложится на концепцию монад. Однако в некоторых языка монады используются явно гораздо чаще этого. И я предполагаю, что это не от хорошей жизни, а как раз от того, что там кругом "только функции". )
Моя позиция заключается в том, что везде, где нужно возвращать данные из одних функций и передавать в другие польза от монад есть. Но недостатки языка могут сделать использование монад проблематичным в том или ином случае. Поэтому, не от хорошей жизни, они будут использованы не везде, где от этого была бы польза, а только там, где она компенсирует неприятности, связанные с ограничениями языка.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, Wolverrum, Вы писали:
W>А я вот в упор не понимаю, почему такой ппц навороченный оракл не умеет нормальных средств автоматизации?
Все просто. Там внутри такой жуткий индусокод судя по всему, что там что то поменять просто нереально. Чудо что это вообще работает. Уже костыли настолько внутри огромны, что совершенно невозможно без переписывания всей системы с нуля написать хотя бы инсталлятор, чтобы не было дикого геморроя с созданием базы к которой легко подключиться. Про автоматизацию вообще можно молчать — там наверняка внутри архитектура "все связано со всем", и чтоб что то там сделать — нужно это скопипастить в тысячу мест. Проекту уже не один десяток лет, писался толпой индусов — кто то думает что в этом можно разобраться?
Грамотный маркетинг у этого Оракла и ничего более. В результате те, у кого много денег, думают что без оракла невозможно создать даже вебмагазин на 100 товаров, и само слово Оракл сделает продукт безглючным просто оттого, что будет использоваться.
Re[16]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Потому как частенько они облегчают решение не проблем реального мира, а проблем данного языка.
Нельзя ли конкретнее? О каких проблемах языка в данном случае идет речь?
_>Ну практически весь код приложения расположен внутри монады IO.
Не совсем понятно, что в данном случае понимается под "весь код внутри IO". Все функции, какую детальную декомпозицию мы не предприняли бы имеют сигнатуры вида a -> IO b ? Так не бывает. Все функции вызываются, возможно, через ряд промежуточных функций, из функции вида a -> IO b ? Ну так все программы на хаскеле такие.
_>Т.е. как бы красивого декларативного ленивого кода Хаскеля, которым он вроде как и хорош, в приложение уже считай что нет вообще.
С точки зрения красоты и декларативности функции a -> IO b не являются функциями второго сорта.
K>>Ну так IO и нужно для "системных задач". Если вы пишете вычисления факториалов, то никакой пользы от контроля за эффектами нет, тут какой-нибудь ML не хуже чистого языка. Ну, а чем больше "системных задач", тем больше пользы от системы контроля за эффектами, в случае хаскеля — от IO/ST. _>Да, только если классический ленивый декларативный Хаскель (там где он такой применим) обычно обходит другие языки по выразительности, то его монадная часть (подразумевая IO/ST) скорее наоборот, заметно менее удобна, чем аналоги из других языков.
Вы сначала вроде бы соглашаетесь с моим доводом, говоря "да", а потом пишете нечто противоположного смысла. Видимо я недостаточно понятно выразился.
Нет никакой пропасти между "классическим" и "монадным" хаскелем, по крайней мере, если я правильно понял, что вы имели в виду.
Как раз наоборот, при написании вычислителей факториалов и чисел Фибоначчи хаскель не имеет принципиального преимущества перед ML-ями. Ну ладно, имеет благодаря ленивости, и это даже в некотором смысле благодаря IO, но сейчас разговор не об этом. При работе с таким кодом и в ML-ях применим equational reasoning (с оговорками, но это и в хаскеле так, их там немногим меньше), и вообще это, в основном, хороший ФП код.
Совсем другое дело, когда дело доходит до решения системных задач. Тут разница принципиальна и выразительность и контроль над сложностью у хаскеля существенно выше, чем у языков, где контроля эффектов нет. Потому, что в хаскеле эффекты первоклассны, типизированны (не достаточно легковесно, правда) и комбинируемы (с оговорками, как принципиального характера, так и связанными с убогостью хаскеля — его системы типов в первую очередь). Поймите меня правильно, система контроля за эффектами хаскеля имеет множество недостатков, критиковать ее можно и нужно, но с позиции других, превосходящих систем контроля за эффектами, а не с позиции отсутствия такой системы. Тут разница, как между языками типизированными и бестиповыми — это разные лиги, тут даже сравнивать нечего.
_>Т.е. как я понимаю, авторы языка задумывали концепцию вида "максимально красивый язык по большей части и плюс небольшие островки неудобного кода, концентрирующие в себе работу с нехорошими вещами". Но при столкновение с реальностью (программированием сильно системных вещей) оказалось, что эти неудобные островки расширяются до размера всего приложения, а места для красивого кода уже и не остаётся вовсе.
Нет, вы поняли неправильно. "Нехорошие функции" есть, например, в ML. Хорошая функция вычисляет факториал — она ведет себя как функция. Мы можем как-то о ней рассуждать и т.д. "Нехорошая функция" возвращает случайное число. Она не только сама не функция, и не позволяет о себе рассуждать но и заражает все, где используется. Делает все функции с которыми контактирует "нехорошими". Хуже того, она еще и труднораспознаваема и претворяется хорошей.
Одна из основных инноваций хаскеля и задумка авторов как раз в том, чтоб "нехороших функций" вообще не было. И не в том смысле в каком это было до хаскеля, когда было просто нельзя делать что-то. Хорошие функции могут делать все то же самое, что и "плохие функции", но при этом остаются хорошими. Все функции хорошие (точнее, считаются таковыми).
Т.е. хаскель делался не для красивого вычисления факториалов — это просто и почти везде возможно, а для того, чтоб о функциях, делающих что-то полезное, можно было рассуждать как о функциях в математическом смысле. В языках без контроля эффектов такая возможность, начинаясь с факториалов как в хаскеле, на факториалах же и заканчивается.
_>Проблемы "хаскеля без монад" отлично продемонстрировали вы сами в том примере, где показали реализацию IO/ST без монад. Жуть же полная, хотя да, работает...
Не могли бы вы пояснить, в чем именно жуть. И какая тут связь с монадами (на всякий случай поясню, что то, что я описывал реализовано именно так и в "хаскеле с монадами", в чем собственно и был весь пойнт моего сообщения)?
_>Проблемы "хаскеля с монадами" я изложил выше.
Никакого изложения проблем выше не было. Вы просто делали загадочное лицо говоря, что какие-то проблемы есть, но что это за проблемы так и не развернули.
_>И естественно это всё актуально не для любого софта, а для интенсивно работающего с системой. Т.е. скажем для какого-нибудь конвертера запускающегося из командной строки и состоящего на 95% из сложного алгоритма такие проблемы точно не актуальны. Только вот в современном мире подобное ПО — это же скорее исключение...
Ну, об этом, собственно, и речь. Вы будете смеяться, но "конвертер запускающийся из командной строки" скорее выявит недостаток хаскеля. В данный момент в нем отсутствует удобный/легковесный способ лифтнуть код без эффектов. Т.е. если вы написали функцию вычисляющую факториал, но внезапно решили добавить в нее зависимость от фазы луны — может понадобится существенная переработка всей функции. В типичном хаскельном софте, "интенсивно работающем с системой" и представляющим собой стек трансформеров с IO в основании, все уже, в основном, лифтнуто куда надо и фазы луны легко добавляются.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Прямо такой же — не получится. Потому, что в исходном коде подразумевается реактивность. Т.е. ваша задача — не энергичный цикл (который встанет в ожидании следующего события, заморозив нативный поток и отожрав мегабайт address space процесса), а как раз функция OnEvent(Event e){Analyze(e.value);}. S>Когда вы её напишете, можно будет сравнить объём и понятность кода.
1. Мы в том той ветке дискуссии обсуждали именно парсеры (хотя я бы скорее назвал это некими анализаторами коллекций всё же, ну да ладно), а не реактивность. И код парсера вообще никак не зависит от метода его запуска. Цикл это или же функции обратного вызова — это всё в любом случае относится к коду "генератора данных", а не анализатора.
Т.е. то, что я написал код вида
auto generator=MakeGenerator(rand, chrono::seconds(1));
generator.Subscribe(Analyzer);
generator.Start();
абсолютно никак не поменяло обсуждаемую функцию Analyzer.
2. Если мы всё же говорим, что основной смысл Rx — это реализация паттерна Наблюдатель для коллекций, а не некие последующие linq-подобные извращения, то тогда у меня к Rx нет ни малейших претензий. Ну разве что кроме того, что обычно подобное проще написать самому, чем подключать стороннюю библиотеку.
S>В простых случаях у вас будет получаться более-менее понятный код. Примерно как в обработчике события MouseClick, который отлавливает Double Click путём сравнения текущего клика с предыдущим. Ну, только надо будет руками декларировать все переменные состояния — скалярные в случае тикера/тренда и стек в случае обработчика листьев дерева. А с монадами и прочими автогенераторами стейт-машина генерируется автоматически компилятором.
Ну так если нам нужен конечный автомат, то для этого есть отличные специализированные инструменты, причём без всяких ужасов типа попытки записать некое подобие БНФ через linq синтаксис. Т.е. для простейших случаев пишем линейный код, а для сложных берём удобный конечный автомат (например boost.statechart). И это всё находится внутри функции Analyzer, которую опять же можно вызывать и внутри цикла и реактивным способом.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Зачем учитывать какие-то особенности?
Нуу если не надо, то тогда можно показать пример реализации liftM2 без учёта вида монады? )
S>То есть вы заранее полагаете, что компилятор хуже вас разбирается в оптимизациях, и хотите делать всё вручную. Почему?
Потому как у него недостаточно данных для этого. Например в зависимости от значения одного аргумента, "распаковка" второго может вообще не потребоваться... )
S>А это ещё зачем? Все особенности монады уже есть в самой монаде. Никакие дополнительные сущности под каждый тип не нужны. Вы же не пишете какие-то дополнительные сущности под каждый тип коллекции, чтобы разрешить алгоритмам из STL работу с ними.
Хы, да не важно внутри или снаружи (хотя в языках с навязанным ООП только первый вариант и проходит). Главное что оно зависит от конкретного вида.
S>Вы по-прежнему не понимаете основной идеи RX. Вот, скажем, когда вы пишете императивный код, который энергично процессит какие-то структуры, вы почему-то мало заботитесь о том, что нужно учитывать все эти ваши локальные переменные, их scope, частоту обращений, и прочее. Регистры за вас прекрасно выбирает компилятор. Вы пишете код типа x[i] = yy[i*aWidth+yoffset+j]*MulY + xx[i*aHeight+xoffset+j]*MulX и не паритесь о том, что на самом деле это элементарно записывается в обратной польской записи, и там даже можно сэкономить на лишних push и pop, подбирая порядок операций. Это привычно и удобно. S>А вот когда речь идёт о коде, в котором, к примеру, поток управления диктуется снаружи, вы теряетесь. Попробуйте представить себе код, вычисляющий x[i], в котором нет возможности обратиться к "переменным" типа yy[...], а вместо них приходят внешние вызовы вроде set_yoffset(), set_MulY(), set_i(). S>При этом про порядок этих вызовов вы знаете не очень много — т.е. он сегодня один, а завтра другой. Конечно же, для каждого случая формулы и порядка прихода значений "легко" написать стейт-машину — вот только при "традиционной" реализации стейт-машины объём её кода будет несопоставим с приведённой формулой, и восстановить её логику крайне тяжело. Как вы поймёте, что делает эта стейт-машина, читая кусочки методов?
Плохой пример тут выбрали, потому как вычисления вида x[i] = yy[i*aWidth+yoffset+j]*MulY + xx[i*aHeight+xoffset+j]*MulX в любом случае не являются управляемыми снаружи и не требуют никаких конечных автоматов. По одной простой причине — для вычислений требуется наличие всех данных. Т.е. в коде "реакций" у нас не будет никаких действий, а только сохранение данных.
А вот если мы посмотрим на пример требующий реального конечного автомата (типа того же примера в этой темке, хотя там автомат такой простой, что линейный код всё равно проще вышел), то увидим что на RX он выглядит уже совсем не так красиво как просто формулка выше. Точнее он выглядит просто ужасно. )))
S>RX — это попытка записать подобные штуки в понятном виде. Т.е. вы пишете как бы активный код, который "сам" превращается в реактивный. А уж в каком виде вам удобнее писать предикаты и проекции — ваше дело. Если вам хочется иметь минимум синтаксического мусора, то query comprehensions — ваш выбор. Если вас раздражает SQL (а судя по вашим комментариям про NoSQL это именно так), то вам подойдёт лямбда-синтаксис, с явным выписыванием всех этих (previousEvent, currentEvent) => { return previousEvent.ClickPoint.InRect(new Rect(0, 0, 5, 5).Offset(currentEvent.ClickPoint.X, currentEvent.ClickPoint.Y);}. S>С моей точки зрения это та же ручная state machine, вид сбоку.
Согласен. Но при этом написание конечного автомата через sql операторы (не важно записанные через пробел или через точку) — это ужасная дикость, которая приводит страшнейшему коду. Ну а если забыть про этот "нюанс", то конечно же паттерн Наблюдатель в сочетание с конечным автоматом дают удобное решение многих задач.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Вы переводите разговор в плоскость цены абстракции? Ну, я считаю, что если существует такая возможность улучшить производительность, как выделение некоего сочетания операций и переписывание их определенным образом, то ее неплохо использовать, написав правило перезаписи, в соответствии с которым компилятор перепишет паттерн в более эффективный код автоматически. В конце концов, чистые функции и "алгебраизация" библиотек в том числе для этого и нужны.
Нет, вопрос производительности я пока вообще особо не затрагиваю, т.к. это зависит уже больше от языков и их компиляторов, а не от общетеоретических вещей, которые мы сейчас обсуждаем.
Пока что меня интересует пример универсальной реализации liftM2 и как в неё попадает информация о типе монады. А то возможно, что мы говорим немного о разных вещах, и я слишком поспешно согласился, что такое трудно написать на языках типа C++.
K>Не понятно, о каких "базовых примитивах" идет речь если мы используем ФВП и лямбды?
Не важно как мы записываем sql операторы, через пробел или через точку, они всё равно остаются собой по смыслу.
K>Зависит от того, что понимать под словом "маргинальный". Если вопрос сводится к тому, есть ли польза от использования монад в окамле — то ответ: да, есть.
Ага, отлично... А теперь ключевой вопрос: насколько интенсивно используются монады в ocaml'е?
K>Моя позиция заключается в том, что везде, где нужно возвращать данные из одних функций и передавать в другие польза от монад есть.
Ну вот например sin(exp(x)). В чём тут может быть польза от монад? )
Re[17]: Есть ли вещи, которые вы прницпиально не понимаете...
Не буду отвечать с цитированием, а попробую подвести некий общий итог.
Насколько я понимаю, вы считаете что реализация IO/ST в Хаскеле приносит некие серьёзные плюсы по отношению к другим языкам. И то, что при этом код реализации вроде как той же задачи выглядит намного страшнее (что с монадами, что без), чем в других языка, это всё равно окупается теми самыми плюсами. Я правильно изложил?
В таком случае, хотелось бы увидеть пример демонстрирующий именно эти самые плюсы, т.к. я их не особо заметил при изучение Хаскеля, а вот страшность подобного кода заметил очень хорошо.
Да, и по поводу примеров "весь код приложения — одна монада"... Можно взглянуть на примеры из того же wxHaskell — там оно в полный рост. )))
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, вопрос производительности я пока вообще особо не затрагиваю, т.к. это зависит уже больше от языков и их компиляторов, а не от общетеоретических вещей, которые мы сейчас обсуждаем. _>Пока что меня интересует пример универсальной реализации liftM2 и как в неё попадает информация о типе монады.
Не понятно, зачем вам может понадобиться "информация о типе монады" если не для специфических для данной монады оптимизаций. Если коротко, то эта информация в liftM2 никак не попадает — это называется "абстракция".
_>Не важно как мы записываем sql операторы, через пробел или через точку, они всё равно остаются собой по смыслу.
Все еще не понимаю, что вам не нравится. Что Filter называется Where не смотря на то, что смысл у него не совсем тот либо совсем не тот, что у sql-ного where?
_>А теперь ключевой вопрос: насколько интенсивно используются монады в ocaml'е?
Не знаю, я на окамле не пишу. Но вот компания, которая пишет — Jane Street — выпускала и монадические библиотеки вроде Async и синтаксические расширения для монад, а значит, по всей видимости, использует.
_>Ну вот например sin(exp(x)). В чём тут может быть польза от монад? )
Зависит от того, что у вас возвращает exp. Я же вроде понятно написал выше по ветке для комбинирования функций какого вида нужны монады.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[18]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Насколько я понимаю, вы считаете что реализация IO/ST в Хаскеле приносит некие серьёзные плюсы по отношению к другим языкам.
Да почти все плюсы хаскеля на уровне value language, не на тайплевеле конечно, благодаря им и возможны. Давольно давно уже ничего нового в языках без контроля эффектов не сделать.
_>И то, что при этом код реализации вроде как той же задачи выглядит намного страшнее (что с монадами, что без), чем в других языка, это всё равно окупается теми самыми плюсами. Я правильно изложил?
Я не согласен, что это выглядит намного страшнее, чем в других языках (если не считать упомянутые мной "карательные" наименования, которые легко исправить). Монадический код часто, но не всегда, требует синтаксической обвязки для "стыковки" в отличие от функций вида a -> b в хаскеле, и потому код с мутабельными ссылками/массивами может выглядеть многословнее, чем хаскель-код с иммутабельными. Но в большинстве языков обычно наворочено столько синтаксического мусора без всякого смысла вообще, что на этом фоне и монадический хаскель-код выглядит вполне пристойно. Потому и вопрос — что это за язык такой, по сравнению с которым хаскельный код выглядит намного страшнее.
_>В таком случае, хотелось бы увидеть пример демонстрирующий именно эти самые плюсы,
Да любой код, про который вы решите, что он лучше кода на языке икс — лучше, в конечном счете, как раз потому, что в хаскеле есть IO/ST
_>т.к. я их не особо заметил при изучение Хаскеля, а вот страшность подобного кода заметил очень хорошо.
Ну, приведите этот самый "страшный код", а рядом код на том самом загадочном языке, где это все лучше выглядит.
_>Да, и по поводу примеров "весь код приложения — одна монада"... Можно взглянуть на примеры из того же wxHaskell — там оно в полный рост. )))
Я видел код на wxHaskell, не уверен, правда, что тот же самый, что и вы. Вопрос о том, что означают ваши слова "весь код приложения — одна монада" остается, ответте на него вашими же словами, а не отсылкой на некий неназванный код, который вы когда-то видели.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Не понятно, зачем вам может понадобиться "информация о типе монады" если не для специфических для данной монады оптимизаций. Если коротко, то эта информация в liftM2 никак не попадает — это называется "абстракция".
Совершенно верно. Вот я и хочу увидеть конкретный вид этой абстракции, чтобы оценить почему имеются проблемы (если имеются) с её реализацией на языках типа C++.
K>Все еще не понимаю, что вам не нравится. Что Filter называется Where не смотря на то, что смысл у него не совсем тот либо совсем не тот, что у sql-ного where?
Имя не принципиально. Даже если переименовать sql, он всё равно останется со своей огромной кучей проблем и ограничений. Для узкого круга задач (типа работы с таблицами и то желательно без join'ов) он ещё более менее подходит, но linq то позиционируется гораздо шире...
K>Не знаю, я на окамле не пишу. Но вот компания, которая пишет — Jane Street — выпускала и монадические библиотеки вроде Async и синтаксические расширения для монад, а значит, по всей видимости, использует.
Не, ну так специализированные библиотеки под особые задачи с концепциями типа монад есть и на C++. Но применяются то они только в этих самых особых случаях. В то время как в том же Хаскеле трудно найти приложение без монад.
K>Зависит от того, что у вас возвращает exp. Я же вроде понятно написал выше по ветке для комбинирования функций какого вида нужны монады.
Возращает double. Но не в этом суть. Так получается что уже не для всех случаев полезны монады? )))
Re[19]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Да любой код, про который вы решите, что он лучше кода на языке икс — лучше, в конечном счете, как раз потому, что в хаскеле есть IO/ST
Ну так можно какой-нибудь пример увидеть? ) Т.е. дело даже не в конкретном коде, а в конкретном позитивном эффекте, который возникает от этих возможностей.
K>Я видел код на wxHaskell, не уверен, правда, что тот же самый, что и вы. Вопрос о том, что означают ваши слова "весь код приложения — одна монада" остается, ответте на него вашими же словами, а не отсылкой на некий неназванный код, который вы когда-то видели.
Отвечу здесь на всё остальное.
С wxWidgets всегда идёт в поставке куча примеров. Что в оригинальной (которая на C++), что в wxHaskell. Так вот если мы откроем эти примеры, то мы увидим:
1. код примеров из wxHaskell очень не похож на классический красивый Хаскель, который обычно показывают в учебниках (да, да, те самые факториалы и не только).
2. код примеров из wxHaskell выглядит менее симпатично чем их точных аналогов из примеров wxWidgets.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Вы не написали такого кода. Вы написали совсем другой код, в котором никакого Analyze нету, и который построен на разрушающих изменениях локального состояния.
_>абсолютно никак не поменяло обсуждаемую функцию Analyzer.
Пока что никакой функции нету. Есть гипотетическая функция, которая конкурирует в обсуждении с конкретным, уже работающим кодом.
_>2. Если мы всё же говорим, что основной смысл Rx — это реализация паттерна Наблюдатель для коллекций, а не некие последующие linq-подобные извращения, то тогда у меня к Rx нет ни малейших претензий. Ну разве что кроме того, что обычно подобное проще написать самому, чем подключать стороннюю библиотеку.
Rx — это реализация паттерна "произвольные выражения" для цепочек событий.
_>Ну так если нам нужен конечный автомат, то для этого есть отличные специализированные инструменты, причём без всяких ужасов типа попытки записать некое подобие БНФ через linq синтаксис. Т.е. для простейших случаев пишем линейный код, а для сложных берём удобный конечный автомат (например boost.statechart). И это всё находится внутри функции Analyzer, которую опять же можно вызывать и внутри цикла и реактивным способом.
Нам не нужен конечный автомат. Точно так же, как нам не нужен стек для арифметики — удобнее просто писать арифметические выражения в школьной нотации.
Конечный (или бесконечный) автомат — это деталь реализации. А нам нужна возможность записать реакцию на события в понятном виде.
Ваш оппонент просто пытается вам объяснить, что с точки зрения декларативной семантики парсинг активно-читаемого текста и анализ цепочек событий — одно и то же, поэтому рулят системы, которые отделяют запись правил анализа от механизмов получения данных, и даже от активности/пассивности стиля получения данных.
А вы по-прежнему рассказываете про то, что лучше писать всё каждый раз руками, или использовать готовые монолитные библиотеки. Это как если бы фанат С рассказывал, что шаблонные коллекции — это какой-то непонятный механизм, и что ему нетрудно руками написать compare_values(x, y) для каждого нужного ему типа, либо вообще использовать готовую библиотеку, которая сразу умеет читать массивы double из файла и сортировать их оптимальным образом.
Меня вот, к примеру, бесит, что все механизмы по работе с XML, к примеру, построены на DOM модели. Это означает, что я не могу написать эффективный код по потоковому разбору приезжаюшего на сервер потока в реактивном режиме. Точнее, могу — если перейду на SAX парсер и буду всё читать руками. Ничего из готового кода по десериализации, валидации, или XPath работать не будет. Там всё построено на том, что надо активно дрючить Document, который обязан быть готов к моменту начала работы. А я бы хотел иметь всё наоборот — чтобы у меня был реактивный XPath Expression, который выплёвает найденную Node в виде события каждый раз, как только она готова; чтобы он работал поверх SAX-парсера, который запихивает в этот XPath прочитанные элементы в виде событий, и тоже работает поверх "обратного streamreader", который запихивает в парсер читаемый текст по мере готовности. И, естественно, streamreader тоже должен работать "наоборот", т.е. не вызывать stream.Read(), а ждать от реактивного stream события DataArrived.
Всё это можно сделать, вот только
1. объём работы огромен: процитированная иерархия — это чуть менее, чем "до хрена" кода, при этом переписать его в реактивном стиле не вполне тривиально.
2. результат работы — дубирование кода. То есть надо будет править ошибки параллельно в двух реализациях StreamReader, XmlDocument, и XPathExpression.
Хочется обратного: чтобы я написал код в понятном виде. А уже среда/библиотеки/хрен его знает что автоматически сгенерировала хоть активную, хоть реактивную версии.
Вот Rx — это первый известный мне подход к весу.
Он, к сожалению, никак не отвечает на многие конкретные вопросы. В частности, запись правил парсинга на нём далеко не идеальна, хоть и лучше многих альтернативных вариантов. Или, скажем, попытаться написать на нём хотя бы реактивный RegEx я бы не взялся.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Возращает double. Но не в этом суть. Так получается что уже не для всех случаев полезны монады? )))
Суть в том, что если у вас нету монад, то при желании уметь отложенное вычисление sin и exp вам придётся писать отдельную функцию exp(Promise<double>) и sin(Promise<double>).
А с монадами у вас есть универсальный способ написать только double-версию sin() и exp(), и бесплатно получить sin(exp(List<double>), sin(exp(Promise<double>)), sin(exp(Promise<List<double>>)) и так далее.
Частный случай такого отжига — lifted operators — встроен в C#. То есть вам не нужно руками писать операторы сравнения для Nullable<MyType>, потому что их вы получите бесплатно из написанных вами операторов сравнения для MyType.
Монады позволяют получить то же счастье для любых типов, а не только для оборудованных compiler magic.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Совершенно верно. Вот я и хочу увидеть конкретный вид этой абстракции, чтобы оценить почему имеются проблемы (если имеются) с её реализацией на языках типа C++.
liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b
Реализовать ее в принципе можно, я-то говорил, что у нее будет несодержательный с точки зрения практической пользы тип (по крайней мере пока в C++ концептов нет).
_>Имя не принципиально. Даже если переименовать sql, он всё равно останется со своей огромной кучей проблем и ограничений. Для узкого круга задач (типа работы с таблицами и то желательно без join'ов) он ещё более менее подходит, но linq то позиционируется гораздо шире...
Тогда я вообще не понимаю, о чем вы говорите. Где LINQ и где SQL? Какое отношения ограничения sql-я имеют к linq? Какие-там базовые примитивы — если комбинаторы самому писать можно?
_>Не, ну так специализированные библиотеки под особые задачи с концепциями типа монад есть и на C++. Но применяются то они только в этих самых особых случаях. В то время как в том же Хаскеле трудно найти приложение без монад.
Ну так я объяснил почему: неудобств связанных с применением монад и вообще написанием обобщенного кода в хаскеле меньше.
_>Возращает double. Но не в этом суть. Так получается что уже не для всех случаев полезны монады? )))
Суть как раз в этом. Если у вас exp возвращает double, то принимая числа даже меньше 1000 он уже возвращает ерунду. Просто система обработки ерунды встроена в операции с плавучкой. Понятно, что для большинства типов такой автоматической обработки нет и ее нужно организовывать. Кроме того, я сразу написал, что монады нужны для комбинирования функций вида a -> m b, и там же написал что полезно для комбинирования функций других видов. Мне теперь это повторять в каждом предложении?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так можно какой-нибудь пример увидеть? ) Т.е. дело даже не в конкретном коде, а в конкретном позитивном эффекте, который возникает от этих возможностей.
Ну вы же сами видели пример и даже уже его высоко оценили. Вот вы пишете: "классический ленивый декларативный Хаскель (там где он такой применим) обычно обходит другие языки по выразительности", т.е. тот код, который вы называете "классическим ленивым декларативным" обходит главным образром потому, что в хаскеле эффекты под контролем. Без этого невозможно было бы ни сделать удобное комбинирование функций, ни обеспечить более-менее разумную производительность для такого кода. Вы считаете, что "его монадная часть (подразумевая IO/ST) скорее наоборот, заметно менее удобна", но на эту монадную часть распространяются основные плюсы: о функциях можно рассуждать как о функциях, легко преобразовывать код как вручную, так и правилами перезаписи и т.д.
_>С wxWidgets всегда идёт в поставке куча примеров. Что в оригинальной (которая на C++), что в wxHaskell. Так вот если мы откроем эти примеры, то мы увидим:
_>1. код примеров из wxHaskell очень не похож на классический красивый Хаскель, который обычно показывают в учебниках (да, да, те самые факториалы и не только). _>2. код примеров из wxHaskell выглядит менее симпатично чем их точных аналогов из примеров wxWidgets.
Ну и где сравнение про которое я спрашивал. Чтоб слева код на хаскеле, а справа, на чудо-языке в котором код существенно лучше. Вы с первого айфона что-ли пишете, или где там еще копипаст не доступен?
Допустим, вот учебный пример, использующий wxHaskell:
{-----------------------------------------------------------------------------
reactive-banana-wx
Example:
Asteroids, adapted from
http://www.haskell.org/haskellwiki/WxAsteroids
The original example has a few graphics issues
and I didn't put much work into correcting them.
For more, see also
https://github.com/killerswan/wxAsteroids/issues/1
http://comments.gmane.org/gmane.comp.lang.haskell.wxhaskell.general/1086
------------------------------------------------------------------------------}
{-# LANGUAGE ScopedTypeVariables #-} -- allows "forall t. Moment t"import Graphics.UI.WX hiding (Event)
import Graphics.UI.WXCore as WXCore
import Reactive.Banana
import Reactive.Banana.WX
import System.Random
import Paths (getDataFile)
{-----------------------------------------------------------------------------
Main
------------------------------------------------------------------------------}
-- constants
height, width, diameter :: Int
height = 300
width = 300
diameter = 24
chance :: Double
chance = 0.1
rock, burning, ship :: Bitmap ()
rock = bitmap $ getDataFile "rock.ico"
burning = bitmap $ getDataFile "burning.ico"
ship = bitmap $ getDataFile "ship.ico"
explode :: WXCore.Sound ()
explode = sound $ getDataFile "explode.wav"
main :: IO ()
main = start asteroids
{-----------------------------------------------------------------------------
Game Logic
------------------------------------------------------------------------------}
-- main game function
asteroids :: IO ()
asteroids = do
ff <- frame [ text := "Asteroids"
, bgcolor := white
, resizeable := False ]
status <- statusField [text := "Welcome to asteroids"]
set ff [statusBar := [status]]
t <- timer ff [ interval := 50 ]
game <- menuPane [ text := "&Game" ]
new <- menuItem game [ text := "&New\tCtrl+N", help := "New game" ]
pause <- menuItem game [ text := "&Pause\tCtrl+P"
, help := "Pause game"
, checkable := True
]
menuLine game
quit <- menuQuit game [help := "Quit the game"]
set new [on command := asteroids]
set pause [on command := set t [enabled :~ not]]
set quit [on command := close ff]
set ff [menuBar := [game]]
pp <- panel ff []
set ff [ layout := minsize (sz width height) $ widget pp ]
set pp [ on (charKey '-') := set t [interval :~ \i -> i * 2]
, on (charKey '+') := set t [interval :~ \i -> max 10 (div i 2)]
]
-- event networklet networkDescription :: forall t. Frameworks t => Moment t ()
networkDescription = do-- timer
etick <- event0 t command
-- keyboard events
ekey <- event1 pp keyboard
let eleft = filterE ((== KeyLeft ) . keyKey) ekey
eright = filterE ((== KeyRight) . keyKey) ekey
-- ship positionlet
bship :: Behavior t Int
bship = accumB (width `div` 2) $
(goLeft <$ eleft) `union` (goRight <$ eright)
goLeft x = max 0 (x - 5)
goRight x = min (width-30) (x + 5)
-- rocks
brandom <- fromPoll (randomRIO (0,1) :: IO Double)
let
brocks :: Behavior t [Rock]
brocks = accumB [] $
(advanceRocks <$ etick) `union`
(newRock <$> filterE (< chance) (brandom <@ etick))
-- draw the game state
sink pp [on paint :== stepper (\_dc _ -> return ()) $
(drawGameState <$> bship <*> brocks) <@ etick]
reactimate $ repaint pp <$ etick
-- status barlet bstatus :: Behavior t String
bstatus = (\r -> "rocks: " ++ show (length r)) <$> brocks
sink status [text :== bstatus]
network <- compile networkDescription
actuate network
-- rock logictype Position = Point2 Int
type Rock = [Position] -- lazy list of future y-positions
newRock :: Double -> [Rock] -> [Rock]
newRock r rs = (track . floor $ fromIntegral width * r / chance) : rs
track :: Int -> Rock
track x = [point x (y - diameter) | y <- [0, 6 .. height + 2 * diameter]]
advanceRocks :: [Rock] -> [Rock]
advanceRocks = filter (not . null) . map (drop 1)
-- draw game state
drawGameState :: Int -> [Rock] -> DC a -> b -> IO ()
drawGameState ship rocks dc _view = do
let
shipLocation = point ship (height - 2 * diameter)
positions = map head rocks
collisions = map (collide shipLocation) positions
drawShip dc shipLocation
mapM (drawRock dc) (zip positions collisions)
when (or collisions) (play explode)
collide :: Position -> Position -> Bool
collide pos0 pos1 =
let distance = vecLength (vecBetween pos0 pos1)
in distance <= fromIntegral diameter
drawShip :: DC a -> Point -> IO ()
drawShip dc pos = drawBitmap dc ship pos True []
drawRock :: DC a -> (Point, Bool) -> IO ()
drawRock dc (pos, collides) =
let rockPicture = if collides then burning else rock
in drawBitmap dc rockPicture pos True []
Можете вы пояснить, что тут так не похоже на "классический" хаскель и "красивый код в учебниках" (ну, кроме того, что автор по какой-то причуде использует let in вместо where), что тут конкретно нужно поменять, чтоб это выглядело также как некий не называемый красивый код?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Да любой код, про который вы решите, что он лучше кода на языке икс — лучше, в конечном счете, как раз потому, что в хаскеле есть IO/ST
_>Ну так можно какой-нибудь пример увидеть? ) Т.е. дело даже не в конкретном коде, а в конкретном позитивном эффекте, который возникает от этих возможностей.
В кратце это будет реактивный/асинхронный паттерн матчинг. Тебе по идее в курсе, для чего нужен сам паттерн матчинг ?
Вот прямо сейчас есть хрень с логированием. Задача простая — разгрести логи что бы вместо хрензнаетсколькомегабайтной простыни было ровно то, что требуется, а именно — "callStack" некоторых асинхронных операций
Приходят эвенты кусочками, в них есть всякое, json, прямо код на джаваскрипте а так же всякая штукенция навроде begin-end только вариантов много, ибо старался каждый как мог, например Init -Destroy или on-un, startSync-endSync
Соответсвенно для каждой пары надо сделать небольшой процессинг, отдельно json и javascript обработать
Фокус в том, что приходит это кусочками, как построчно, так и простынями, вперемешку с мусоров от самых разных подсистем, т.е. надо
1 фильтровать-преобразовывать на уровне блоков
2 фильтровать-преобразовывать на уровне строк
3 фильтровать-преобразовывать на уровне подсистем
4 уметь работать с полу-языками
5 уметь работать с json
6 уметь работать с javascript
вот например идет такой блок
function name(value){
...
}
Он будет перемешан с кучей мусора и мусор может быть и в начале и в конце строке
надо оставить только name, если он внутри блока pir который унутре startSync-endSync
фокус такой — блок придет не одной строкой,а несколькими
т.е. может прийти function name а потом () { потом кусочками тело, потом вклинится лог какой нибудь хрени потом остаток тела и }
примерно так
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 66: startSync { ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80: pir:function ts:123374637463
I/Web Console(11863): sync:getSyncStatus ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80: pir: something ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80:() { ts:123374637463
I/Web Console(11863): sync:getSyncStatus ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80:.... ) { ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 80: } ) { ts:123374637463
I/Web Console(11863): sync:getSyncStatus ts:123374637463
D/Web Console(11254) content://jsHybugger.org/jshybugger.js: Line 66:endSync { ts:123374637463
надо получить something, при том что брать нужно только функцию верхнего уровня, на вложеные забить
С реактивным парсингом это не составляет никаких проблем:
Вот упрощенное решение
var text = pattern('D/Web Console($number()$) content://jsHybugger.org/jshybugger.js: Line $number()$:');
// text теоретически можно задать регэкспом, но это будет выглядеть крайне коряво и трудно ловить ошибкиvar systemId = word('D/Web Console');
//тоже самое
filter(systemId)
.strip(text)
.strip(timeStamp())
.takeWhen(between(word('startSync'),optional(second('pir', jsFunction('takeName()'))),word('endSync')))
.next(sendTo(screen()).color('blue'))
Итого отфильтровать по ид подсистемы, стрипнуть мусор по паттерну, остаток взять если подходит подходит под паттерн startSync — endSync и унутре у него будет function name() {...}
Далее кинуть всё в консоль покрасив синим цветом
Вот и нарисовался асинхронный паттерн матчинг/ процессинг на парсер комбинаторах. Если мне нужно чтото другое, я тут же поменял текст и не надо приседать с lexx, yacc или boost.spirit, всё прямо в консоли
Покажи хотя бы примерно, как ты будешь решать ту же задачу, если, скажем, лог идет постоянно, не выключаясь и нужно видеть актуальное состояние прямо сейчас.
Ну и напиши приблизительный конечный скрипт который будет делать ровно то, что я описал выше
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Он, к сожалению, никак не отвечает на многие конкретные вопросы. В частности, запись правил парсинга на нём далеко не идеальна, хоть и лучше многих альтернативных вариантов. Или, скажем, попытаться написать на нём хотя бы реактивный RegEx я бы не взялся.
Смотря что надо, вот парсер чисел в формате с плавающей запятой
/*
Число = ["+"|"-"]НатЧисло["."[НатЧисло]][("e"|"E")["+"|"-"]НатЧисло].
НатЧисло = Цифра{Цифра}.
Цифра = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9".
*/
// грамматика + преобразования в строку, чисто для тестаvar digit = range('0..9');
var natNumber = rep1(digit).map(toString);
var sign = anyOrNone('+-');
var fraction = optional(all(char('.'), natNumber)).map(toString);
var exp = optional(all(anyOrNone('eE'), sign, natNumber)).map(toString);
var number = all(sign, natNumber, fraction, exp).map(toString);
// парсинг var stream = Stream.from('-012.12E-10zzzzz'.split(''));
stream.parse(number).on('next', function(result){
// ассерты
assert(result != null);
assert(result.value == '-012.12E-10');
assert(result.rest == 'zzzzz');
});
stream.fire();
Либа, правда, для продакшна не готова, на досуге я на ней монады отращиваю Собтсвенно реактивность сильно слабая, куча косяков, багов и прочих вещей, стыдно даже показывать
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Вы не написали такого кода. Вы написали совсем другой код, в котором никакого Analyze нету, и который построен на разрушающих изменениях локального состояния.
Естественно, потому как при использование for'a вынесение кода в отдельную функцию не приносит никакой пользы. Но мне почему-то казалось, что на данном форуме ни у кого не может быть проблем с мысленным преобразованием такого кода
Ну если кому-то это сложно, то сорри... )
S>Пока что никакой функции нету. Есть гипотетическая функция, которая конкурирует в обсуждении с конкретным, уже работающим кодом.
Этот тоже работающий — я другой не показываю. )))
S>Нам не нужен конечный автомат. Точно так же, как нам не нужен стек для арифметики — удобнее просто писать арифметические выражения в школьной нотации. S>Конечный (или бесконечный) автомат — это деталь реализации. А нам нужна возможность записать реакцию на события в понятном виде. S>Ваш оппонент просто пытается вам объяснить, что с точки зрения декларативной семантики парсинг активно-читаемого текста и анализ цепочек событий — одно и то же, поэтому рулят системы, которые отделяют запись правил анализа от механизмов получения данных, и даже от активности/пассивности стиля получения данных.
1. Ну так вообще то как раз я и показывал вариант, в котором всё разделено. Имеем функцию Analyze. Её можно вызвать хоть из цикла (активно), хоть как реакцию на сообщения (реактивно). Далее, в самой функции мы можем и написать ручной код (в простых случаях), и вставить мощный конечный автомат на базе какой-то библиотеки, и вставить вообще готовое решения для анализа данных на базе какого-то удобного синтаксиса задания грамматики. Вот это действительно раздельная архитектура, обеспечивающая гибкость и удобство. А как раз Rx на фоне этого выглядит монолитной хренью заточенной только под один узкий вариант.
2. Если говорить конкретно о процессе анализа, то идея записывать "грамматику" через sql операторы — это на мой взгляд полная дикость.
S>Меня вот, к примеру, бесит, что все механизмы по работе с XML, к примеру, построены на DOM модели. Это означает, что я не могу написать эффективный код по потоковому разбору приезжаюшего на сервер потока в реактивном режиме. Точнее, могу — если перейду на SAX парсер и буду всё читать руками. Ничего из готового кода по десериализации, валидации, или XPath работать не будет. Там всё построено на том, что надо активно дрючить Document, который обязан быть готов к моменту начала работы. А я бы хотел иметь всё наоборот — чтобы у меня был реактивный XPath Expression, который выплёвает найденную Node в виде события каждый раз, как только она готова; чтобы он работал поверх SAX-парсера, который запихивает в этот XPath прочитанные элементы в виде событий, и тоже работает поверх "обратного streamreader", который запихивает в парсер читаемый текст по мере готовности. И, естественно, streamreader тоже должен работать "наоборот", т.е. не вызывать stream.Read(), а ждать от реактивного stream события DataArrived. S>Всё это можно сделать, вот только S>1. объём работы огромен: процитированная иерархия — это чуть менее, чем "до хрена" кода, при этом переписать его в реактивном стиле не вполне тривиально. S>2. результат работы — дубирование кода. То есть надо будет править ошибки параллельно в двух реализациях StreamReader, XmlDocument, и XPathExpression.
Несколько сомнительная идея. Потому как непонятно о чём должны сигнализировать сообщения парсера. Если о приходе узлов, то как бы всё равно получится что придёт только одно сообщение на документ, причём опять же только после прихода всего документа. Если же парсер будет сигнализировать о "начале узла", то тогда это получается только небольшая часть анализа и непонятно зачем такое вообще может быть нужно.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Суть в том, что если у вас нету монад, то при желании уметь отложенное вычисление sin и exp вам придётся писать отдельную функцию exp(Promise<double>) и sin(Promise<double>). S>А с монадами у вас есть универсальный способ написать только double-версию sin() и exp(), и бесплатно получить sin(exp(List<double>), sin(exp(Promise<double>)), sin(exp(Promise<List<double>>)) и так далее.
Вообще то это у нас описание функторов, а не монад. Но даже если бы это были монады... Какой смысл в протягивание этой дополнительной сущности между sin(exp()), когда можно это сделать по "краям"? )
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Давай чуток усложним задачу — есть 10 потоков или асинхронных ниток и каждая должна трекать определенный источник.
С моим примером все в порядке, а твой надо переписывать
Это понятно или надо объяснять ?
Далее интереснее, алёрты надо кидать
1 скорость изменения сигнала
2 ускорение изменения сигнала
3 текущий уровень всех потоков выше или ниже определенного уровня
4 максимальный пик между двумя максимальными спадами.
5 плато
Опиши хотя бы что тебе понядобится и насколько код усложнится.
S>>Пока что никакой функции нету. Есть гипотетическая функция, которая конкурирует в обсуждении с конкретным, уже работающим кодом.
_>1. Ну так вообще то как раз я и показывал вариант, в котором всё разделено. Имеем функцию Analyze. Её можно вызвать хоть из цикла (активно), хоть как реакцию на сообщения (реактивно). Далее, в самой функции мы можем и написать ручной код (в простых случаях), и вставить мощный конечный автомат на базе какой-то библиотеки, и вставить вообще готовое решения для анализа данных на базе какого-то удобного синтаксиса задания грамматики. Вот это действительно раздельная архитектура, обеспечивающая гибкость и удобство. А как раз Rx на фоне этого выглядит монолитной хренью заточенной только под один узкий вариант.
Наоборот, это у тебя только один вариант. Твоя функция Analyze это полностью энергичный код, а у меня она ленивая. Соответсвенно скорость посчитать очень легко, а тебе надо приседать и приседать.
S>>2. результат работы — дубирование кода. То есть надо будет править ошибки параллельно в двух реализациях StreamReader, XmlDocument, и XPathExpression.
_>Несколько сомнительная идея. Потому как непонятно о чём должны сигнализировать сообщения парсера. Если о приходе узлов, то как бы всё равно получится что придёт только одно сообщение на документ, причём опять же только после прихода всего документа. Если же парсер будет сигнализировать о "начале узла", то тогда это получается только небольшая часть анализа и непонятно зачем такое вообще может быть нужно.
Очень просто — например тебе надо на лету стрипать определенный контент. Что это может быть и в каких узлах — дело десятое. Например xml читается одним источником, обрабатывается и тут же отдаётся куда нибудь, все это делается одновременно. DOM здесь не поможет, т.е. данные целиком никогда не будут загружены.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
K>liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b
Ага... Ну так тут мы используем знания о типе конкретной монады используя определённый для неё оператор >>=. Если в C++ определить для каждого типа монад такой же оператор, то не будет вообще никаких проблем в аналогичной записи liftM2.
Т.е. например для boost.optional мы определим >>= как
template<typename T, typename F>
auto operator>>=(optional<T> o, F f)->decltype(f(*o)){return f(*o);}
K>Реализовать ее в принципе можно, я-то говорил, что у нее будет несодержательный с точки зрения практической пользы тип (по крайней мере пока в C++ концептов нет).
И в чём несодержательность то? ) Обе функции выглядят один в один, разве что вариант на C++ имеет гораздо больше всякие скобочек и т.п. Если основная претензия к этому, то я в общем то соглашусь. ))) Но насчёт несодержательности непонятно что-то... )
K>Тогда я вообще не понимаю, о чем вы говорите. Где LINQ и где SQL? Какое отношения ограничения sql-я имеют к linq? Какие-там базовые примитивы — если комбинаторы самому писать можно?
Писать то можно... Только кто это делает? ) Почему я вижу определение грамматики через select, where и т.п.? )
K>Суть как раз в этом. Если у вас exp возвращает double, то принимая числа даже меньше 1000 он уже возвращает ерунду. Просто система обработки ерунды встроена в операции с плавучкой. Понятно, что для большинства типов такой автоматической обработки нет и ее нужно организовывать. Кроме того, я сразу написал, что монады нужны для комбинирования функций вида a -> m b, и там же написал что полезно для комбинирования функций других видов. Мне теперь это повторять в каждом предложении?
Суть в том, что на практике монады как раз нужны достаточно редко. А их частое использование в Хаскеле всего лишь следствие некоторых неудобностей языка (которые являются ценой за некоторые особенности, возможно приносящие плюсы, а возможно и нет — это мы так и не выяснили пока).
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну вы же сами видели пример и даже уже его высоко оценили. Вот вы пишете: "классический ленивый декларативный Хаскель (там где он такой применим) обычно обходит другие языки по выразительности", т.е. тот код, который вы называете "классическим ленивым декларативным" обходит главным образром потому, что в хаскеле эффекты под контролем. Без этого невозможно было бы ни сделать удобное комбинирование функций, ни обеспечить более-менее разумную производительность для такого кода. Вы считаете, что "его монадная часть (подразумевая IO/ST) скорее наоборот, заметно менее удобна", но на эту монадную часть распространяются основные плюсы: о функциях можно рассуждать как о функциях, легко преобразовывать код как вручную, так и правилами перезаписи и т.д.
Да, правильно, код внутри монад будет доступен из окружающего его кода в том же самом красивом режиме. Но что если у нас практически весь код приложения находится в монадах? ) Тогда в общем то эти плюсы пропадают в никуда.
А когда я говорил о заметно меньшем удобстве, то подразумевался процесс написания кода внутри монад. Причём он на мой взгляд хуже и обычного хаскеля и императивных аналогов...
K>Ну и где сравнение про которое я спрашивал. Чтоб слева код на хаскеле, а справа, на чудо-языке в котором код существенно лучше. Вы с первого айфона что-ли пишете, или где там еще копипаст не доступен? K>Допустим, вот учебный пример, использующий wxHaskell:
В этом примере ещё не всё так страшно, т.к. некая часть программы занята логикой, которая выражается "нормальным" хаскелем. В реальном системном ПО или же тех же примеров из самого wxHaskell соотношение такого кода гораздо хуже. Но даже здесь хорошо видна разница между этими областями в приложение. Ну а если мы сравним этот пример с его аналогом на C++, то будет всё совсем печально.
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В кратце это будет реактивный/асинхронный паттерн матчинг. Тебе по идее в курсе, для чего нужен сам паттерн матчинг ?
Ага, только непонятно какое это вообще имеет отношение к плюсам возникающим из-за особенности реализации IO/ST в Хаскеле, которые мы тут обсуждали? ))) Rx то не касается этих гипотетических (пока для меня, т.к. Klapaucius пока не показал ни одного примера) плюсов ни в малейшей степени.
I>Покажи хотя бы примерно, как ты будешь решать ту же задачу, если, скажем, лог идет постоянно, не выключаясь и нужно видеть актуальное состояние прямо сейчас. I>Ну и напиши приблизительный конечный скрипт который будет делать ровно то, что я описал выше
Ну я промолчу про подобную систему логирования... Предположим, что нам очень не повезло в жизни и реально надо возиться с подобным. Решение выглядит очевидно. Что-то вроде (это не протестированный псевдо код):
static bool show=false;
match what;
if(regex_match(str, what, regex)){//regex вырезает данные между "D/Web Console(ххххх) content://jsHybugger.org/jshybugger.js: Line хх:" и "ts:хххххххххххх"if(find(what[1], "endSync")) show=false;
if(show) cout<<what[1];
if(find(what[1], "startSync")) show=true;
}
Это без pir, т.к. я не очень понял значения кода там с optional, second и т.п. Но предполагаю, что после разъяснения постановки задачи, добавление нужного кода сведётся к одному дополнительному if'у или чему-то вроде этого. )))
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Давай чуток усложним задачу — есть 10 потоков или асинхронных ниток и каждая должна трекать определенный источник. I>С моим примером все в порядке, а твой надо переписывать I>Это понятно или надо объяснять ?
Если нам надо иметь несколько параллельных парсеров, то просто переделываем глобальную функцию, в функцию-член некого класса и всё. Стандартная техника и кстати код функции при этом править не надо. )))
I>Далее интереснее, алёрты надо кидать I>1 скорость изменения сигнала I>2 ускорение изменения сигнала I>3 текущий уровень всех потоков выше или ниже определенного уровня I>4 максимальный пик между двумя максимальными спадами. I>5 плато
I>Опиши хотя бы что тебе понядобится и насколько код усложнится.
Не вижу вообще ничего сложного. Даже конечный автомат не нужен или какие-то другие библиотеки. Просто пишем соответствующий код под каждый алерт и всё. В чём проблема то? ) Там по одной строчке вычисления на каждое текущее значение, плюс по одному if'у на алерт. )))
I>Наоборот, это у тебя только один вариант. Твоя функция Analyze это полностью энергичный код, а у меня она ленивая. Соответсвенно скорость посчитать очень легко, а тебе надо приседать и приседать.
Ээээ что? ))) Скорость это всего лишь vel=val-prev;
I>Очень просто — например тебе надо на лету стрипать определенный контент. Что это может быть и в каких узлах — дело десятое. Например xml читается одним источником, обрабатывается и тут же отдаётся куда нибудь, все это делается одновременно. DOM здесь не поможет, т.е. данные целиком никогда не будут загружены.
Если нам не требуется DOM (даже в итоге), то нам и не нужен подобный подробный разбор. Достаточно банального регулярного выражения.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Если нам надо иметь несколько параллельных парсеров, то просто переделываем глобальную функцию, в функцию-член некого класса и всё. Стандартная техника и кстати код функции при этом править не надо. )))
Но переделывать то надо ? А мне даже отдельной функции заводить не надо
_>Не вижу вообще ничего сложного. Даже конечный автомат не нужен или какие-то другие библиотеки. Просто пишем соответствующий код под каждый алерт и всё. В чём проблема то? ) Там по одной строчке вычисления на каждое текущее значение, плюс по одному if'у на алерт. )))
Не получается по одной строчке на каждое условие
I>>Наоборот, это у тебя только один вариант. Твоя функция Analyze это полностью энергичный код, а у меня она ленивая. Соответсвенно скорость посчитать очень легко, а тебе надо приседать и приседать.
_>Ээээ что? ))) Скорость это всего лишь vel=val-prev;
Это _не_ скорость, а просто дельта текущего и предыдущего значений.
I>>Очень просто — например тебе надо на лету стрипать определенный контент. Что это может быть и в каких узлах — дело десятое. Например xml читается одним источником, обрабатывается и тут же отдаётся куда нибудь, все это делается одновременно. DOM здесь не поможет, т.е. данные целиком никогда не будут загружены.
_>Если нам не требуется DOM (даже в итоге), то нам и не нужен подобный подробный разбор. Достаточно банального регулярного выражения.
Это тянет на нобелевку. Пример — на регулярных выражениях правильно вырезать определенные теги, которые, внезапно, могут быть вложенными.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В кратце это будет реактивный/асинхронный паттерн матчинг. Тебе по идее в курсе, для чего нужен сам паттерн матчинг ?
_>Ага, только непонятно какое это вообще имеет отношение к плюсам возникающим из-за особенности реализации IO/ST в Хаскеле, которые мы тут обсуждали? ))) Rx то не касается этих гипотетических (пока для меня, т.к. Klapaucius пока не показал ни одного примера) плюсов ни в малейшей степени.
Ты просто не хочешь увидеть, ибо аргументы у тебя навроде "я всё это могу на с++ тупо императивно".
Пример что я привел никакой не гипотетический.
I>>Ну и напиши приблизительный конечный скрипт который будет делать ровно то, что я описал выше
_>Ну я промолчу про подобную систему логирования... Предположим, что нам очень не повезло в жизни и реально надо возиться с подобным. Решение выглядит очевидно. Что-то вроде (это не протестированный псевдо код): _>
_>static bool show=false;
_>match what;
_>if(regex_match(str, what, regex)){//regex вырезает данные между "D/Web Console(ххххх) content://jsHybugger.org/jshybugger.js: Line хх:" и "ts:хххххххххххх"
_> if(find(what[1], "endSync")) show=false;
_> if(show) cout<<what[1];
_> if(find(what[1], "startSync")) show=true;
_>}
_>
_>Это без pir, т.к. я не очень понял значения кода там с optional, second и т.п. Но предполагаю, что после разъяснения постановки задачи, добавление нужного кода сведётся к одному дополнительному if'у или чему-то вроде этого. )))
Ты решил не ту задачу У меня разбор некоторого контекстно-свободного языка реактивным парсером.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну я промолчу про подобную систему логирования... Предположим, что нам очень не повезло в жизни и реально надо возиться с подобным.
Я могу логировать ровно столко, сколько мне нужно, главное что бы разгрести эти логи. Поэтому речь не про везение, а про инструмент. Вообще, по уму, хорошо бы логировать каждую строчку, но это конечно сказка
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Но переделывать то надо ? А мне даже отдельной функции заводить не надо
Эээээ, это ты типа сейчас сравниваешь процесс использования некой готовой библиотеки и с процессом написания кода альтернативной библиотеки? ))) Оригинальненько... )))
I>Не получается по одной строчке на каждое условие
НУ это у кого как. )))
I>Это _не_ скорость, а просто дельта текущего и предыдущего значений.
Дааа? ) Т.е. у тебя замеры анализируемого значения производятся не через равные промежутки времени и в нашу функцию анализа передаётся ещё и массив значений этих интервалов? ) Потому как в противном случае дельта — это и будет скорость. )))
I>Это тянет на нобелевку. Пример — на регулярных выражениях правильно вырезать определенные теги, которые, внезапно, могут быть вложенными.
Вообще то подразумевалось, что регулярное выражение используется для нахождения момента с которого мы будем пропускать данные (у нас же потоковая обработка вроде как), а не для самого вырезания из всего объёма данных... Однако если бы мы вдруг захотели именно подобное вырезание, то оно тоже вполне реально, в том числе и для вложенных тэгов.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты просто не хочешь увидеть, ибо аргументы у тебя навроде "я всё это могу на с++ тупо императивно".
Для начала давай разделять "можно на C++" и "можно императивно". Это разные вещи. Чаще всего я как раз показываю, что предложенное решение можно без проблем реализовать и в C++ прямо в оригинальном (не императивном) виде. Однако потом обычно говорю, что это всё нафиг не нужный мусор, разведённый ради мифической красоты (а в реальности для программистских "понтов") и тупой императивный код в лоб решает задачу быстрее. Причём быстрее и по итоговому коду и по времени его написания.
И кстати говоря далеко не все вещи из других языков реально повторить на C++. Например некоторые возможности реализуемые в D на C++ повторить не реально. Хотя с обычно обсуждаемым с тобой языком такого конечно быть не может, там всё наоборот. Кстати, как раз в тему... Как по твоему, реально ли написать на C# функцию liftM2 подходящую для произвольного типа монад? На Хаскеле очевидно легко. На C++ тоже без проблем, как я показал здесь http://www.rsdn.ru/forum/philosophy/5417607
.
I>Пример что я привел никакой не гипотетический.
Только он вообще не имеет никакого отношения к эффектам, на которые намекает Klapaucius...
I>Ты решил не ту задачу У меня разбор некоторого контекстно-свободного языка реактивным парсером.
Тут прямо в точности оно и есть. Мой код вызываем для каждой приходящей строки и получаем тот же результат, что и у тебя. )
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я могу логировать ровно столко, сколько мне нужно, главное что бы разгрести эти логи. Поэтому речь не про везение, а про инструмент.
Дело не в объёме, а в оформление ужаса... ))) Ну да ладно, это уже вопрос совсем далёкий от данной темки...
I>Вообще, по уму, хорошо бы логировать каждую строчку, но это конечно сказка
Подобное "логирование" называется "отладка".
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я могу логировать ровно столко, сколько мне нужно, главное что бы разгрести эти логи. Поэтому речь не про везение, а про инструмент.
_>Дело не в объёме, а в оформление ужаса... ))) Ну да ладно, это уже вопрос совсем далёкий от данной темки...
I>>Вообще, по уму, хорошо бы логировать каждую строчку, но это конечно сказка
_>Подобное "логирование" называется "отладка".
Нет возможности подключить нормальный дебуггер, потому все делается через логированияе.
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Ты просто не хочешь увидеть, ибо аргументы у тебя навроде "я всё это могу на с++ тупо императивно".
_>Для начала давай разделять "можно на C++" и "можно императивно". Это разные вещи. Чаще всего я как раз показываю, что предложенное решение можно без проблем реализовать и в C++ прямо в оригинальном (не императивном) виде.
Ого, в оригинальном не императивном ? Это наверное на другом форуме, все твои решения здесь это обычный императивный код на С++.
>Однако потом обычно говорю, что это всё нафиг не нужный мусор, разведённый ради мифической красоты (а в реальности для программистских "понтов") и тупой императивный код в лоб решает задачу быстрее. Причём быстрее и по итоговому коду и по времени его написания.
Я и вижу — ты уже в который раз дал решение не той задачи или не тот код
_>И кстати говоря далеко не все вещи из других языков реально повторить на C++. Например некоторые возможности реализуемые в D на C++ повторить не реально. Хотя с обычно обсуждаемым с тобой языком такого конечно быть не может, там всё наоборот. Кстати, как раз в тему... Как по твоему, реально ли написать на C# функцию liftM2 подходящую для произвольного типа монад? На Хаскеле очевидно легко. На C++ тоже без проблем, как я показал здесь http://www.rsdn.ru/forum/philosophy/5417607
Я честно говоря не понимаю, что такое liftM2
I>>Пример что я привел никакой не гипотетический. _>Только он вообще не имеет никакого отношения к эффектам, на которые намекает Klapaucius...
Наоборот.
I>>Ты решил не ту задачу У меня разбор некоторого контекстно-свободного языка реактивным парсером.
_>Тут прямо в точности оно и есть. Мой код вызываем для каждой приходящей строки и получаем тот же результат, что и у тебя. )
Нет, не получаем.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Но переделывать то надо ? А мне даже отдельной функции заводить не надо
_>Эээээ, это ты типа сейчас сравниваешь процесс использования некой готовой библиотеки и с процессом написания кода альтернативной библиотеки? ))) Оригинальненько... )))
Я говорю про вычислительную модель а ты пытаешься общий случай заменить частным, показывая примеры императивного кода.
Тебе нужно прекратить стёб и показать саму вычислительную модель, она у тебя императивная, которая покроет все возможные кейсы
I>>Не получается по одной строчке на каждое условие
_>НУ это у кого как. )))
I>>Это _не_ скорость, а просто дельта текущего и предыдущего значений.
_>Дааа? )
Да. Пудозреваю, ты и ускорение можешь вычислить точно так же — дельтой текущего и предыдущего значений.
>Т.е. у тебя замеры анализируемого значения производятся не через равные промежутки времени и в нашу функцию анализа передаётся ещё и массив значений этих интервалов? ) Потому как в противном случае дельта — это и будет скорость. )))
В моем случае вообще не важно, через какие промежутки времени производятся замеры. Нужна скорость — это с помощью 1 функции получаем новый эвент стрим который будет скорость показывать. Еще один стрим — ускорение. Всё. Эта функция естественно, будет накапливать интервалы за некоторую единицу времени Y.
I>>Это тянет на нобелевку. Пример — на регулярных выражениях правильно вырезать определенные теги, которые, внезапно, могут быть вложенными.
_>Вообще то подразумевалось, что регулярное выражение используется для нахождения момента с которого мы будем пропускать данные
Это ты сам себе упростил. Вот простая задача — одинаковые вложеные теги заменяем одним, если некоторый интересующий контент есть только в самом низу. т.е.
<a><a></a><a><a>ф</a></a></a> = <a>ф</a>
<a x="a"><a></a><a><a>ф</a></a></a> = <a>ф</a>
>(у нас же потоковая обработка вроде как), а не для самого вырезания из всего объёма данных... Однако если бы мы вдруг захотели именно подобное вырезание, то оно тоже вполне реально, в том числе и для вложенных тэгов.
ля-ля-ля. покажи регэксп для случая выше. Ты в который раз уже хочешь свести контекстно-свободную грамматику к регулярной и мне это порядком надоело. Толи ты не понимаешь, что пишешь, то ли ты специально дурака валяешь.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Во втором случае (на псевдоплюсах) нигде не написано, что это за M. Использование >>= никак не отражено в сигнатуре. Вот про это я и говорил "нетипизировано" и "несодержательная сигнатура"
_>Писать то можно... Только кто это делает? )
Все делают. В том же Rx множество комбинаторов, для которых никакого спецсинтаксиса нет.
_>Почему я вижу определение грамматики через select, where и т.п.? )
Отлично, мы вернулись на несколько постов назад. Мне скопипастить свой ответ или сами прочитаете?
_>Суть в том, что на практике монады как раз нужны достаточно редко.
Т.е. возвращать из функций вида a -> m b и передавать в другие — это все-таки редко нужно, я правильно понял?
_>А их частое использование в Хаскеле всего лишь следствие некоторых неудобностей языка
Ну так назовите хоть одну. Что это за "неудобности" такие, которые вынуждают в хаскеле монады использовать, и которых в другом языке нет и использовать монады ничто не вынуждает.
Вы раз за разом повторяете, что они есть, но назвать ни одной не можете.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Да, правильно, код внутри монад будет доступен из окружающего его кода в том же самом красивом режиме. Но что если у нас практически весь код приложения находится в монадах? )
Вы так и не объяснили, что вы имеете в виду, говоря "код внутри монад".
_>Тогда в общем то эти плюсы пропадают в никуда.
Какие плюсы? И куда они пропадают?
_>А когда я говорил о заметно меньшем удобстве, то подразумевался процесс написания кода внутри монад. Причём он на мой взгляд хуже и обычного хаскеля и императивных аналогов...
Конечно не хуже, потому что если бы он был хуже императивных аналогов, вы давно бы уже привели код и можно было предметно обсудить недостатки.
Но раз вы не приводите примеры "как в хаскеле" и "как на плюсах" и даже "как должно быть" — значит, очевидно, вы считаете, что ваш тезис примеры не подтвердят. Поэтому остается только повторять одно и то же о "меньшем удобстве" и "худшем коде", ничего конкретно не говоря.
_>В этом примере ещё не всё так страшно, т.к. некая часть программы занята логикой, которая выражается "нормальным" хаскелем. В реальном системном ПО или же тех же примеров из самого wxHaskell соотношение такого кода гораздо хуже.
О да! У игры "астероиды" такая могучая "логика", куда там "реальному системному ПО".
_>Но даже здесь хорошо видна разница между этими областями в приложение.
Это не всем хорошо видно. Не могли бы вы в этом коде обозначить, какие области "кошерные", а какие печальнее C++?
_>Ну а если мы сравним этот пример с его аналогом на C++, то будет всё совсем печально.
Похоже, с сайтом проблемы: хаскель-код у меня отображается, а "аналог на C++" — нет, так что сравнить не получается.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Писать то можно... Только кто это делает? ) Почему я вижу определение грамматики через select, where и т.п.? )
Потому что лично мне понравился вот такой пример. Ты определись, чего хочешь — обсуждать монады или обсуждать лично мои примеры или обсуждать фичи языка который понравился лично мне — C#.
Грамматика на C# через linq сделана потому, что в C# паттерн матчинга нет, но можно сэмулировать частные случаи через query comprehension.
Вопрос — какое отношение имеет паттерн матчинг конкретного языка к монадам ?
Пудозреваю, тебя сейчас порвёт: "Я, Я, Я знаю — это можно сделать на регэкспах !!!111расрас".
K>>Суть как раз в этом. Если у вас exp возвращает double, то принимая числа даже меньше 1000 он уже возвращает ерунду. Просто система обработки ерунды встроена в операции с плавучкой. Понятно, что для большинства типов такой автоматической обработки нет и ее нужно организовывать. Кроме того, я сразу написал, что монады нужны для комбинирования функций вида a -> m b, и там же написал что полезно для комбинирования функций других видов. Мне теперь это повторять в каждом предложении?
_>Суть в том, что на практике монады как раз нужны достаточно редко. А их частое использование в Хаскеле всего лишь следствие некоторых неудобностей языка (которые являются ценой за некоторые особенности, возможно приносящие плюсы, а возможно и нет — это мы так и не выяснили пока).
На практике монады нужны всегда. Ты с коллекциями работаешь ? А это монада, встроеная в язык/фремворк. С исключениями работаешь ? А это монада, встроеная в язык/фремворк.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Естественно, потому как при использование for'a вынесение кода в отдельную функцию не приносит никакой пользы. Но мне почему-то казалось, что на данном форуме ни у кого не может быть проблем с мысленным преобразованием такого кода _>в такой _>
_>Ну если кому-то это сложно, то сорри... )
Вот как раз мне — несложно. А вот вам пока заниматься преобразованиями в уме рано. Кто вам сказал, что одновременно идёт итерация только по одной коллекции? И это я ещё не имею в виду многопоточный случай. Вариант нашего коллеги, в отличие от вашего, хранит состояние локально. _>Этот тоже работающий — я другой не показываю. )))
Простите, но уже вторая попытка не удалась. И это мы рассматриваем примитивнейший случай, где автомату не нужен даже магазин.
В мало-мальски интересном реальном случае у вас рука устанет пот утирать при "мысленном преобразовании кода". Я же вам уже намекал — компиляторы придумали не потому, что человек неспособен раскладывать переменные по регистрам и стеку, а потому, что компьютер это делать не устаёт.
_>1. Ну так вообще то как раз я и показывал вариант, в котором всё разделено. Имеем функцию Analyze. Её можно вызвать хоть из цикла (активно), хоть как реакцию на сообщения (реактивно).
Пока что нельзя.
_> Далее, в самой функции мы можем и написать ручной код (в простых случаях), и вставить мощный конечный автомат на базе какой-то библиотеки, и вставить вообще готовое решения для анализа данных на базе какого-то удобного синтаксиса задания грамматики. Вот это действительно раздельная архитектура, обеспечивающая гибкость и удобство.
Вы пример попробуйте привести. В большинстве известных мне случаев текст функции Analyze без поллитры читать совершенно невозможно. Характерный пример — оконная функция на заре виндов, когда не было бесчисленных Фреймворков, и весь её код состоял из огромного switch, да ещё и с вложениями.
Восстановить логику приложения по этой простыне — совершенно нереально, даже в несложных случаях.
_>А как раз Rx на фоне этого выглядит монолитной хренью заточенной только под один узкий вариант.
Под какой именно вариант?
_>2. Если говорить конкретно о процессе анализа, то идея записывать "грамматику" через sql операторы — это на мой взгляд полная дикость.
Вам же уже написали, что использовать синтаксис query comprehension, как и везде в linq, не обязательно. Можно писать в любимом императином стиле, как в вашей функции Analyze — только без граблей глобальных переменных.
_>Несколько сомнительная идея. Потому как непонятно о чём должны сигнализировать сообщения парсера. Если о приходе узлов, то как бы всё равно получится что придёт только одно сообщение на документ, причём опять же только после прихода всего документа.
Это если весь XML состоит исключительно из одного корневого узла. А если там есть хоть какая-то структура, то сообщения будут приходить сразу после завершения каждого узла.
Да, это означает некоторый риск нарваться на non-welformedness или invalidity документа уже в процессе анализа. Но в интересующих нас случаях это всё ещё лучше, чем ждать всего документа.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ого, в оригинальном не императивном ? Это наверное на другом форуме, все твои решения здесь это обычный императивный код на С++.
В данной темке естественно, т.к. вроде как ни у кого не возникает сомнений (хотя вот у Klapaucius возникли сомнения насчёт liftM2, но я их рассеял), что реализовать монады на C++ легко. Так что тут уже остаётся для дискуссии только вопрос о пользе их применения.
I>Я честно говоря не понимаю, что такое liftM2
Это функция, которая берёт на входе функцию вида C f(A, B), а возвращает функцию вида M<C> f(M<A>, M<B>), где M — это некий монадный тип. Т.е. грубо говоря liftM2 переделывает обычную функцию, в функцию работающую со значениями упакованными в монадный тип. Одна из стандартных вещей в Хаскеле, как и просто liftM, Которая по сути fmap.
Как, такое по силам написать на C#? )
_>>Только он вообще не имеет никакого отношения к эффектам, на которые намекает Klapaucius... I>Наоборот.
Дааа? ) Т.е. ты хочешь сказать, что Rx приносит в C# особенности IO/ST Хаскеля (это которые кстати существует в том числе и совсем без монад)?
I>Нет, не получаем.
Ну давай набор тестовых данных (входные строки и ожидаемый текст на выходе) — посмотрим. )))
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
S>>Суть в том, что если у вас нету монад, то при желании уметь отложенное вычисление sin и exp вам придётся писать отдельную функцию exp(Promise<double>) и sin(Promise<double>). S>>А с монадами у вас есть универсальный способ написать только double-версию sin() и exp(), и бесплатно получить sin(exp(List<double>), sin(exp(Promise<double>)), sin(exp(Promise<List<double>>)) и так далее.
_>Вообще то это у нас описание функторов, а не монад.
Что именно вы называете "функтором"? Функциии типа List<double> exp(List<double> a)? Так речь не о них, а о List<double> с некоторыми доп. плюшками. _>Но даже если бы это были монады... Какой смысл в протягивание этой дополнительной сущности между sin(exp()), когда можно это сделать по "краям"? )
"этой" — это какой? Что такое "протягивание"? И что значит "по краям"? Вы имеете в виду, что можно сразу работать с функцией sinexp == sin(exp())?
Ну это же ещё лучше — вы предлагаете писать рукопашный код не только для каждого сочетания монад, но и для каждой комбинации функций. На всякий случай намекну, что помимо функций одного аргумента есть ещё и функции нескольких аргументов. Имея скалярную функцию Multiply(a, b) я при помоши монад автоматически получаю векторную функцию Multiply(double a, List<double> l) и прочие варианты.
И всё это — всего лишь за счёт того, что монада определяет три "штуки": композиция, декомпозиция, и применение. В традиционных ООП языках система типов недостаточно выразительна, чтобы описать монаду явно. А в ФП-языках для монад есть встроенная поддержка.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я говорю про вычислительную модель а ты пытаешься общий случай заменить частным, показывая примеры императивного кода.
I>Тебе нужно прекратить стёб и показать саму вычислительную модель, она у тебя императивная, которая покроет все возможные кейсы
Что-то ты уже сам себя запутал. Давай ка я кратко повторю свои тезисы, а ты скажешь с чем несогласен.
И так, Rxx позволяет нам производить анализ так называемых push-коллекций с помощью некого монадного парсера, заданного через linq синтаксис.
1. push-коллекции — никогда не имел ничего против этой полезной разновидности паттерна Наблюдатель. Единственно что, авторы библиотеки естественно должны предусмотреть ещё и удобное использование того же кода активным образом. Не знаю как с этим в Rx, но надеюсь, что там всё же не идиоты делали. )))
2. монадный парсер... Ну в принципе рабочий вариант конечно, но в данном случае мне кажется что использование именно монад является всего лишь следствием пункта 3. Т.е. на самом деле тут можно было сделать намного удобнее, например использовав перегрузку операторов и соответственно задавая грамматику полноценными выражениями (создавая такой мини DSL). Однако тогда бы не вышел пункт 3 — поэтому выбрали не самый удобный монадный вариант.
3. linq синтаксис: задание грамматики через sql операторы — это на мой взгляд полный бред и дикость.
I>Да. Пудозреваю, ты и ускорение можешь вычислить точно так же — дельтой текущего и предыдущего значений.
Ну естественно что ускорение — это дельта текущего и предыдущего значения скорости (при равных промежутках времени). А по твоему не так что ли? )))
I>В моем случае вообще не важно, через какие промежутки времени производятся замеры. Нужна скорость — это с помощью 1 функции получаем новый эвент стрим который будет скорость показывать. Еще один стрим — ускорение. Всё. Эта функция естественно, будет накапливать интервалы за некоторую единицу времени Y.
Т.е. тебе для такой тривиальной вещи необходимо плодить новый поток сообщений? Ужас какой...
I>Это ты сам себе упростил. Вот простая задача — одинаковые вложеные теги заменяем одним, если некоторый интересующий контент есть только в самом низу. т.е. I><a><a></a><a><a>ф</a></a></a> = <a>ф</a> I><a x="a"><a></a><a><a>ф</a></a></a> = <a>ф</a>
Ты вот постоянно криво ставишь условия задачи) А потом, когда видишь её решение, начинаешь на ходу менять. Вот наверняка и тут будет тоже самое. Ну да ладно, давай последний раз попробуем. ))) Для конкретно этого условия проблему решит выражение: (<a[^>]*>(<a[^>]*></a>)*)+ф((<a[^>]*></a>)*</a>)+
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
K>Во втором случае (на псевдоплюсах) нигде не написано, что это за M. Использование >>= никак не отражено в сигнатуре. Вот про это я и говорил "нетипизировано" и "несодержательная сигнатура"
Почему это на "псевдоплюсах"? )))
А насчёт нетипизированности... Обычно под этим подразумевают, что компилятор может пропустить ошибку и она всплывёт только где-нибудь во время исполнения. В данном случае, если в качестве M передать тип не имеющий определённого оператора >>=, то компилятор выдаст соответствующую ошибку — какую ещё типизацию то можно требовать?
И кстати говоря это полностью укладывается в классическую идеология шаблонов C++, работающую на базе SFINAE.
K>Т.е. возвращать из функций вида a -> m b и передавать в другие — это все-таки редко нужно, я правильно понял?
Да, цепочки вида m a->m b->m c возникают весьма редко. И в этих редких случаях монады как раз оправданы (в любых языках).
K>Ну так назовите хоть одну. Что это за "неудобности" такие, которые вынуждают в хаскеле монады использовать, и которых в другом языке нет и использовать монады ничто не вынуждает. K>Вы раз за разом повторяете, что они есть, но назвать ни одной не можете.
Мы же вроде как это уже обсудили один раз. Это особенности реализации IO/ST в Хаскеле. Правда вы указали, что эти особенности привносят некие плюсы по сравнению с другими языками. Подразумевая, что эти плюсы (которых в других языках в принципе нет) перевешивают все ужасы подобного кода. Однако, моя просьба привести хотя бы один пример, демонстрирующий суть этих плюсов на практике, была полностью проигнорирована...
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Вообще то я ещё в самом первом сообщение на данную тему (про wxHaskell) точно указал что и где надо сравнивать. Если вы так до сих пор этого не увидели, то мне если честно надоело повторяться.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Потому что лично мне понравился вот такой пример. Ты определись, чего хочешь — обсуждать монады или обсуждать лично мои примеры или обсуждать фичи языка который понравился лично мне — C#.
Вообще то это не просто твой пример, а пример с заглавной страницы библиотечки Rxx, так что он очень даже характерен...
I>Грамматика на C# через linq сделана потому, что в C# паттерн матчинга нет, но можно сэмулировать частные случаи через query comprehension.
I>Вопрос — какое отношение имеет паттерн матчинг конкретного языка к монадам ?
Потому как задавать грамматику можно гораздо более удобными способами. И в таком случае монады становятся не нужны (в данном конкретном случае естественно, а не вообще в жизни).
I>Определение грамматики можно сделать и без query comprehension — http://rsdn.ru/forum/philosophy/5416669.1
I>Пудозреваю, тебя сейчас порвёт: "Я, Я, Я знаю — это можно сделать на регэкспах !!!111расрас".
Не, это как раз случай где максимально рулит Boost.Spirit с его удобным (именно для таких целей) DSL'ем.
I>На практике монады нужны всегда. Ты с коллекциями работаешь ? А это монада, встроеная в язык/фремворк. С исключениями работаешь ? А это монада, встроеная в язык/фремворк.
Так вообще то именно об этом и шла основная ветка данной дискуссии. Насколько нужны монады (в явном виде) в мультипарадигменных языках, в которых вся основная подобная функциональность уже встроенная и нет ограничений типа чистых функций Хаскеля и т.п.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Вот как раз мне — несложно. А вот вам пока заниматься преобразованиями в уме рано. Кто вам сказал, что одновременно идёт итерация только по одной коллекции? И это я ещё не имею в виду многопоточный случай. Вариант нашего коллеги, в отличие от вашего, хранит состояние локально.
Оу, когда начинают цепляться к оформлению тестовых примеров (кстати Ikemefula это уже делал — можно было бы почитать хотя бы мой ответ ему), то это означает что по делу сказать уже вообще нечего...
S>Это если весь XML состоит исключительно из одного корневого узла. А если там есть хоть какая-то структура, то сообщения будут приходить сразу после завершения каждого узла. S>Да, это означает некоторый риск нарваться на non-welformedness или invalidity документа уже в процессе анализа. Но в интересующих нас случаях это всё ещё лучше, чем ждать всего документа.
Да, такое можно сделать, но тогда опять же непонятно зачем нам именно такие данные. Они же будут приходить в очень странной последовательности, по отношению к оригинальной структуре. Например для <a></a><b><c><c/></b> придёт как a, c, b. И зачем нам оно такое?
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Что именно вы называете "функтором"? Функциии типа List<double> exp(List<double> a)? Так речь не о них, а о List<double> с некоторыми доп. плюшками.
Применение функций вида A f(B) к скажем List<B> (и получая List<A>) — это у нас просто функтор, а не монада. Монада у нас появится, если мы имеем дело с функцией вида List<A> f(B) и пытаемся применить её к List<B>.
S>"этой" — это какой? Что такое "протягивание"? И что значит "по краям"? Вы имеете в виду, что можно сразу работать с функцией sinexp == sin(exp())? S>Ну это же ещё лучше — вы предлагаете писать рукопашный код не только для каждого сочетания монад, но и для каждой комбинации функций. На всякий случай намекну, что помимо функций одного аргумента есть ещё и функции нескольких аргументов.
И в чём проблема то? ) Покажите на конкретном примере, а то что-то не видно из общих слов.
S>Имея скалярную функцию Multiply(a, b) я при помоши монад автоматически получаю векторную функцию Multiply(double a, List<double> l) и прочие варианты.
Это всё опять же просто функторы, разновидности на тему fmap.
S>И всё это — всего лишь за счёт того, что монада определяет три "штуки": композиция, декомпозиция, и применение. В традиционных ООП языках система типов недостаточно выразительна, чтобы описать монаду явно. А в ФП-языках для монад есть встроенная поддержка.
Да без проблем всё это записывается и в нормальных ООП языках. Можно прямо в этой темке глянуть примеры. Вопрос только в том нафига оно вообще нужно в большинстве случаев.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то это не просто твой пример, а пример с заглавной страницы библиотечки Rxx, так что он очень даже характерен...
Пример мой потому что я его привел. Он достаточно простой что бы можно было понять основные вещи.
I>>Вопрос — какое отношение имеет паттерн матчинг конкретного языка к монадам ?
_>Потому как задавать грамматику можно гораздо более удобными способами. И в таком случае монады становятся не нужны (в данном конкретном случае естественно, а не вообще в жизни).
Удобство это субъетивно. Вот наверняка в форуме С++ найдется ктото, кому тупой recursive descent на сотни килобайт окажется удобнее чем 1000 строк грамматики.
I>>Определение грамматики можно сделать и без query comprehension — http://rsdn.ru/forum/philosophy/5416669.1
I>>Пудозреваю, тебя сейчас порвёт: "Я, Я, Я знаю — это можно сделать на регэкспах !!!111расрас".
_>Не, это как раз случай где максимально рулит Boost.Spirit с его удобным (именно для таких целей) DSL'ем.
Снова феерическая чушь — я показал пример _реактивного_ парсинга ! буст.спирит такой парсинг не умеет, как все твои yacc и lexx.
Если считаешь иначе — покажи, наконец, пример этого самого _реактивного_ парсинга, грамматику возьми из моего примера про формат чисел с плавающей запятой.
В принципе хрен с ним, со спиритом, сделай хотя бы императивно, но что бы это был честный реактивный код, условимся, для простоты, что в эвентах инфа приходит по одному символу. Скажем я могу запускать такие парсеры хоть асинхронно в одном потоке, хоть в разных, могу менять, добавлять комбинаторы как угодно. А у тебя чуть что, так надо подкладывать костыли, например из за многопоточности, паралеллизма и тд и тд и тд.
Вот и покажи, как получить эту гибкость императивным подходом.
I>>На практике монады нужны всегда. Ты с коллекциями работаешь ? А это монада, встроеная в язык/фремворк. С исключениями работаешь ? А это монада, встроеная в язык/фремворк.
_>Так вообще то именно об этом и шла основная ветка данной дискуссии. Насколько нужны монады (в явном виде) в мультипарадигменных языках, в которых вся основная подобная функциональность уже встроенная и нет ограничений типа чистых функций Хаскеля и т.п.
Речь шла об этом, но ты как раз сказал, что монады не нужны.
Чистые функции хаскеля это не ограничение. Ограничение это шаблоны С++, когда ты >>= и =<< не можешь вынести в тип.
Отсюда в Хаскеле много меньше ограничений, чем в С++, с т.з. высокоуровневых конструкций. Вот в низкоуровневом коде там, наоборот, больше ограничений. Например сортировка на хаскеле никогда не получится быстрее чем на С++. А вот разные хитрые алгоритмы поведения персонажей в игре ты вспотеешь выписывать на С++. Собтсвенно игры давно ушли от с++ в этой части.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Что-то ты уже сам себя запутал. Давай ка я кратко повторю свои тезисы, а ты скажешь с чем несогласен.
_>И так, Rxx позволяет нам производить анализ так называемых push-коллекций с помощью некого монадного парсера, заданного через linq синтаксис.
Нет. Парсер можно задавать комбинаторами безо всякого Linq. Забудь вообще про Linq, linq нужен для паттерн матчинга.
_>1. push-коллекции — никогда не имел ничего против этой полезной разновидности паттерна Наблюдатель. Единственно что, авторы библиотеки естественно должны предусмотреть ещё и удобное использование того же кода активным образом. Не знаю как с этим в Rx, но надеюсь, что там всё же не идиоты делали. )))
Что значит удобно, кому удобно, тебе мне или тому, кто кроме циклов и ветвлений ничего в глаза не видел ?
_>2. монадный парсер... Ну в принципе рабочий вариант конечно, но в данном случае мне кажется что использование именно монад является всего лишь следствием пункта 3. Т.е. на самом деле тут можно было сделать намного удобнее, например использовав перегрузку операторов и соответственно задавая грамматику полноценными выражениями (создавая такой мини DSL). Однако тогда бы не вышел пункт 3 — поэтому выбрали не самый удобный монадный вариант.
С монадами получается гораздо лучший ДСЛ, именно потому, что скобочек, кавычек и разных лишних слов будет меньше, чем в твоем варианте на шаблонах.
_>3. linq синтаксис: задание грамматики через sql операторы — это на мой взгляд полный бред и дикость.
Мне кажется, ты до сих пор не понял, что грамматика задается не через linq, черз linq она обрабатывается, т.е. это эмуляция паттерн матчинга.
Мне что, объяснить, что эмуляция паттерн матчига будет хуже чем полноценный паттерн матчинг ?
I>>Да. Пудозреваю, ты и ускорение можешь вычислить точно так же — дельтой текущего и предыдущего значений.
_>Ну естественно что ускорение — это дельта текущего и предыдущего значения скорости (при равных промежутках времени). А по твоему не так что ли? )))
Нет, не так. В твоей модельке и скорость и ускорение меняются в зависимости от частоты опросов. Вот изменился уровень сигнала за одну минуту с 0 до 60, скорость изменения — 1 ед/c
С твоей "формулой" ты получишь 60 значений и например вполне возможно, последнее будет отрицательным. Опаньки — скорость отрицательная, а сигнал растёт.
I>>В моем случае вообще не важно, через какие промежутки времени производятся замеры. Нужна скорость — это с помощью 1 функции получаем новый эвент стрим который будет скорость показывать. Еще один стрим — ускорение. Всё. Эта функция естественно, будет накапливать интервалы за некоторую единицу времени Y.
_>Т.е. тебе для такой тривиальной вещи необходимо плодить новый поток сообщений? Ужас какой...
Моя модель гарантирует отображение скорости, а твоя при росте уровня сигнала может показывать отрицательную скорость.
I>>Это ты сам себе упростил. Вот простая задача — одинаковые вложеные теги заменяем одним, если некоторый интересующий контент есть только в самом низу. т.е. I>><a><a></a><a><a>ф</a></a></a> = <a>ф</a> I>><a x="a"><a></a><a><a>ф</a></a></a> = <a>ф</a>
_>Ты вот постоянно криво ставишь условия задачи)
Задачу привел Синклер, а я привел простейший пример( для SAX парсера XML).
>А потом, когда видишь её решение, начинаешь на ходу менять.
Ога. Это мы с Синклером сговорились, он придумал XML SAX, а я подобрал вариант который под это подходит.
>Вот наверняка и тут будет тоже самое. Ну да ладно, давай последний раз попробуем. ))) Для конкретно этого условия проблему решит выражение: (<a[^>]*>(<a[^>]*></a>)*)+ф((<a[^>]*></a>)*</a>)+
Ты снова частный случай выдал Что мне делать, если теги будут b ? А если в них будет какой то контент, который тоже надо скипнуть ?
Итого — ты в очередной раз попытался натянуть регулярную грамматику на контекстно свободный язык.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В данной темке естественно, т.к. вроде как ни у кого не возникает сомнений (хотя вот у Klapaucius возникли сомнения насчёт liftM2, но я их рассеял), что реализовать монады на C++ легко. Так что тут уже остаётся для дискуссии только вопрос о пользе их применения.
I>>Я честно говоря не понимаю, что такое liftM2
_>Это функция, которая берёт на входе функцию вида C f(A, B), а возвращает функцию вида M<C> f(M<A>, M<B>), где M — это некий монадный тип. Т.е. грубо говоря liftM2 переделывает обычную функцию, в функцию работающую со значениями упакованными в монадный тип. Одна из стандартных вещей в Хаскеле, как и просто liftM, Которая по сути fmap. _>Как, такое по силам написать на C#? )
Конечно же нет, я ведь погулять вышел.
_>Дааа? ) Т.е. ты хочешь сказать, что Rx приносит в C# особенности IO/ST Хаскеля (это которые кстати существует в том числе и совсем без монад)?
Телепатируй дальше, не буду мешать.
I>>Нет, не получаем.
_>Ну давай набор тестовых данных (входные строки и ожидаемый текст на выходе) — посмотрим. )))
То есть, ты решил забрать свои слова на счет того, что не знаешь что такое optional, second и тд ?
optional(second('pir', jsFunction('takeName()'))
эта хрень парсит джаваскрипт, если перед ним идет pir и вырезает имя функции
Мне чисто любопытно, прежде чем перейдем к тестовым данным, ты и вправду считаешь, что готов хотя бы это покрыть регулярными выражениями ?
у меня будет работать даже вот так (+ мусор который стрипается)
s
t
a
r
t
S
y
n
c
p
i
r
f
u
n
c
t
i
o
n
n
a
m
e
(
)
{
}
e
n
d
S
y
n
c
а вообще, я поторопился, у меня в коде ошибка, блоки start-end не вложеные, а должны быть вложенными.
то есть надо вот так
var expr = empty();
var targetPattern = between(word('startSync'), expr, word('endSync'))
expr.overWrite(or(targetPattern, optional(second('pir', jsFunction('takeName()')))));
...
.takeWhen(targetPattern)
то есть, теперь будут найдены все имена функций во вложеных startSync endSync
Но я не сомневаюсь, что ты и здесь найдешь решение на регулярных выражениях
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Т.е. возвращать из функций вида a -> m b и передавать в другие — это все-таки редко нужно, я правильно понял?
_>Да, цепочки вида m a->m b->m c возникают весьма редко. И в этих редких случаях монады как раз оправданы (в любых языках).
Частота зависит от программиста. Скажем если работа с асинхронщиной, то совершенно не ясно, почему это должно возникать редко Наоборот, очень часто — есть коллекция А, есть коллекция Б, их надо смержить. Но вот фокус, они приходят в промисах.
и получается вот такое
var result = merge(getA(),getB());
парадокс — по этому коду нельзя сказать, какой он, синхронный или асинхронный, если не смотреть использование или не глянуть внутрь. Есть один большой минус — брейкпоинты некуда статить.
P.S. Я уже знаю, что это называется "лифтинг".
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>И всё это — всего лишь за счёт того, что монада определяет три "штуки": композиция, декомпозиция, и применение. В традиционных ООП языках система типов недостаточно выразительна, чтобы описать монаду явно. А в ФП-языках для монад есть встроенная поддержка.
_>Да без проблем всё это записывается и в нормальных ООП языках. Можно прямо в этой темке глянуть примеры. Вопрос только в том нафига оно вообще нужно в большинстве случаев.
Не получается. Я наколбасил две небольшие библиотечки, вроде тех что в примерах кода видны, но шота пока не вижу ни одного примера, где бы это было более-менее удобоваримо.
На самом деле у тебя возражение про Rx совершенно справедливое, только ты проблему не там ищешь. Посмотри внимательно на Rx или Rxx и тебе станет понятно, что не может быть нормальных монад в обычном ООП языке, если они не встроены сразу в язык.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Пример мой потому что я его привел. Он достаточно простой что бы можно было понять основные вещи.
Я к тому, что запись грамматики через linq — это не твоё изобретение, а как раз авторов библиотеки. Т.е. это не твой неудачный пример, а подразумеваемая стандартная практика.
I>Снова феерическая чушь — я показал пример _реактивного_ парсинга ! буст.спирит такой парсинг не умеет, как все твои yacc и lexx.
Так речь шла о задание грамматики, а не об этом. Можно же без проблем написать парсер работающий реактивно и при этом с заданием грамматики в стиле boost.sprit. Вот для этой задачи такое и было бы оптимальным.
I>В принципе хрен с ним, со спиритом, сделай хотя бы императивно, но что бы это был честный реактивный код, условимся, для простоты, что в эвентах инфа приходит по одному символу. Скажем я могу запускать такие парсеры хоть асинхронно в одном потоке, хоть в разных, могу менять, добавлять комбинаторы как угодно. А у тебя чуть что, так надо подкладывать костыли, например из за многопоточности, паралеллизма и тд и тд и тд.
Ой, да хватит уже цепляться к тому тестовому примеру. Очевидно же, что если бы я писал библиотечный парсер, то это по любому был бы класс, который учитывал бы всё это и ещё кучу всяких нюансов типа обработки ошибок и т.п. Только никто в своём уме не будет писать такое ради выкладывание на форум.
I>Речь шла об этом, но ты как раз сказал, что монады не нужны.
Не совсем. Я сказал что они не нужны в большинстве случаев. Т.е. что есть редко встречающийся набор реальных задач, на которые монады идеально ложатся (типа различных конвейеров и т.п.). И естественно, что эти задачи надо решать через что-то типа монад в любых языках. Далее, в Хаскеле у нас монады вообще на каждом углу, но это из-за особенностей реализации там IO/ST и на мой взгляд скорее недостаток языка. А ещё, в некоторых других языках народ пытается протащить монады туда, где они реально не требуются...
I>Чистые функции хаскеля это не ограничение. Ограничение это шаблоны С++, когда ты >>= и =<< не можешь вынести в тип.
Сами чистые функции — это естественно не ограничение, а плюс. Они и в D есть например. Проблема то у Хаскеля совсем другие и всем прекрасно известны...
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Что значит удобно, кому удобно, тебе мне или тому, кто кроме циклов и ветвлений ничего в глаза не видел ?
Я к тому, что должен быть предусмотреть способ в одну строчку превратить обычную коллекцию в push-коллекцию и отправить её в парсер. Если такое есть (я надеюсь Rx не идиоты писали?), то всё отлично и можно спокойно один и тот же код использовать разными способами.
I>С монадами получается гораздо лучший ДСЛ, именно потому, что скобочек, кавычек и разных лишних слов будет меньше, чем в твоем варианте на шаблонах.
О да, по тому примеру для парсинга всего лишь числа с плавающей точкой оно и видно. )))
I>Нет, не так. В твоей модельке и скорость и ускорение меняются в зависимости от частоты опросов. Вот изменился уровень сигнала за одну минуту с 0 до 60, скорость изменения — 1 ед/c I>С твоей "формулой" ты получишь 60 значений и например вполне возможно, последнее будет отрицательным. Опаньки — скорость отрицательная, а сигнал растёт.
Ты похоже путаешь понятие "скорости" (мгновенной, в точке) и "средней скорости по заданному интервалу". ) Это вообще то по физике ещё наверное в классе 7-ом проходят. )))
I>Моя модель гарантирует отображение скорости, а твоя при росте уровня сигнала может показывать отрицательную скорость.
Мдаааа. )))
I>Ты снова частный случай выдал Что мне делать, если теги будут b ? А если в них будет какой то контент, который тоже надо скипнуть ?
Тоже без проблем делается.
I>Итого — ты в очередной раз попытался натянуть регулярную грамматику на контекстно свободный язык.
Ну так она в реальности частенько и натягивается. Естественно не всегда (я сам могу кучу антипримеров привести), но ты вот что-то натыкаешься именно на такие. )))
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Конечно же нет, я ведь погулять вышел.
Ты что-то путаешь. ))) У меня к тебе никогда никаких претензий не было, ну разве что кроме повышенной упёртости. А вот к C#...
Как я понимаю ты согласился, что у C++ гораздо больше возможностей для реализации функциональных фишек в стиле Хаскеля, чем у C#? )
_>>Ну давай набор тестовых данных (входные строки и ожидаемый текст на выходе) — посмотрим. ))) I>То есть, ты решил забрать свои слова на счет того, что не знаешь что такое optional, second и тд ?
Нет, я же говорю, давай входные данные и выходные (вот по ним и пойму ТЗ полностью). Кстати, ты этого так и не дал пока.
I>Мне чисто любопытно, прежде чем перейдем к тестовым данным, ты и вправду считаешь, что готов хотя бы это покрыть регулярными выражениями ?
Так не одним же сразу всё, а императивный код использующий регвыры просто для поиска/замены — с помощью этого вообще любая задачка решается. )))
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Частота зависит от программиста. Скажем если работа с асинхронщиной, то совершенно не ясно, почему это должно возникать редко Наоборот, очень часто — есть коллекция А, есть коллекция Б, их надо смержить. Но вот фокус, они приходят в промисах. I>и получается вот такое I>var result = merge(getA(),getB());
I>парадокс — по этому коду нельзя сказать, какой он, синхронный или асинхронный, если не смотреть использование или не глянуть внутрь. Есть один большой минус — брейкпоинты некуда статить.
I>P.S. Я уже знаю, что это называется "лифтинг".
Кстати говоря лифтинг — это как бы совсем функциональный стиль. Т.е. мы преобразуем функцию в функцию (например складывающую числа в складывающую числа в списках). Но есть и промежуточный вариант — использовать что-то типа fmap (а для коллекций будет просто map). Т.е. можно спокойно использовать обычные функции на списках (или на промисах) и при этом обходиться без монад. Просто код будет выглядеть как apply(A, B, merge).
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не получается. Я наколбасил две небольшие библиотечки, вроде тех что в примерах кода видны, но шота пока не вижу ни одного примера, где бы это было более-менее удобоваримо.
I>На самом деле у тебя возражение про Rx совершенно справедливое, только ты проблему не там ищешь. Посмотри внимательно на Rx или Rxx и тебе станет понятно, что не может быть нормальных монад в обычном ООП языке, если они не встроены сразу в язык.
Так это на каком языке то? ) На C# наверное? ) Ну так а он же далеко не сильнейший среди нормальных ООП языков. Лучше бы C++ или ocaml глянул бы. Кстати у них прямо противоположные подходы для реализации подобного, но оба хотя бы могут.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А насчёт нетипизированности... Обычно под этим подразумевают, что компилятор может пропустить ошибку и она всплывёт только где-нибудь во время исполнения. В данном случае, если в качестве M передать тип не имеющий определённого оператора >>=, то компилятор выдаст соответствующую ошибку — какую ещё типизацию то можно требовать?
Такую, чтоб ошибки возникали не при "передавании типа", а при написании обобщенного кода. Обобщенный код на плюсах практически нетипизированный, хотя нетипизированность в данном случае обычно называют "permissiveness", но сути это не меняет.
Об этом я и писал: "На самом деле понятно, как это предполагается использовать обобщенно, но проблема тут будет в том, что это обобщение не типизировано. Родственная проблема — семантическая неопределенность. Про (=<<) можно много чего сказать не зная ничего о конкретной имплементации, про ваш перегруженный сдвиг ничего сказать нельзя."
_>Да, цепочки вида m a->m b->m c возникают весьма редко.
У меня противоположный опыт на этот счет.
_>Мы же вроде как это уже обсудили один раз.
Даже больше одного. Я несколько раз объяснял, что контроль за эффектами и монады это темы слабосвязанные. Никакой необходимости использовать монады для такого контроля в чистом языке нет. Вы либо не понимаете, либо просто игнорируете мои объяснения и как ни в чем не бывало снова это повторяете. Скорее всего игнорируете, потому, что если бы не понимали — вы бы какие-то вопросы по этой теме задали.
_>Это особенности реализации IO/ST в Хаскеле.
Нет, IO и ST реализуются с помощью инкапсуляции (неэкспорта конструктора) и Rank-2 полиморфизма во втором случае. Монады особенностями реализации не являются. Монады используются для создания разделяемой кодовой базы для обобщенной работы с эффектами, функциями, списками, итераторами, генераторами значений для тестов, парсерами, сериализаторами/десериализаторами и еще зиллионом разных вещей. Будут среди них IO и ST или не буду — ничего принципиально не поменяет.
_>Правда вы указали, что эти особенности привносят некие плюсы по сравнению с другими языками.
Это совершенно отдельный разговор не про полезность монад, а про полезность контроля эффектов.
_>Подразумевая, что эти плюсы (которых в других языках в принципе нет) перевешивают все ужасы подобного кода. Однако, моя просьба привести хотя бы один пример, демонстрирующий суть этих плюсов на практике, была полностью проигнорирована...
У меня перед глазами красноречивый пример — ваш диалог с Ikemefula, который вам приводит примеры без всякого толку. Так что я не буду торопиться с примерами, а сначала провентилирую вопрос с "ужасами подобного кода". Т.е. раньше чем вы покажете тут эти ужасы и мы их предметно обсудим, разговор дальше не пойдет и никаких примеров не будет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то я ещё в самом первом сообщение на данную тему (про wxHaskell) точно указал что и где надо сравнивать. Если вы так до сих пор этого не увидели, то мне если честно надоело повторяться.
Это, разумеется, неправда. "Я видел некие примеры к wxWidgets которые на C++ выглядят лучше, чем на Haskell" точным указанием не являются. Вам, чтоб подкрепить свои слова нужно дать ссылки по которым можно пройти сразу, а сюда скопипастить обозримые примеры, которые можно было предметно обсудить. Никто за вас это не сделает, искать подтверждения и иллюстрации для ваших тезисов я не собираюсь. Конкретный хаскель-код вы предметно обсуждать отказались, а кода на плюсах, который бы мне понравился я никогда не видел, так что ничем вам тут помочь не могу.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Соответственно дальше действия простые — другая сторона получив p1, m, s и имея у себя r путём простейшей проверки может гарантированно убедиться, что p1 честно соответствует m (а это обычно что-то вроде текста "ООО Рога и Копыта").
А есть способы убедиться, что "ООО" это именно то что нам нужно? Например, я скачиваю программу, а она подписана "Microsoft Corporation". Как понять, что это именно M$? Ведь написать можно и "Microsoft Inc", да и просто "Microsoft"...
P.S. Большое спасибо за объяснения, очень доходчиво. Книжку выпустить не планируете?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так это на каком языке то? ) На C# наверное? ) Ну так а он же далеко не сильнейший среди нормальных ООП языков. Лучше бы C++ или ocaml глянул бы. Кстати у них прямо противоположные подходы для реализации подобного, но оба хотя бы могут.
Я бы сказал, что из ООП С++ наихудший. В ём тащут возможности, которые к ООП не имеют никакого отношения — шаблоны, макросы и указатели.
Окамл прежде всего это функциональный язык, а уже потом ОО.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>P.S. Я уже знаю, что это называется "лифтинг".
_>Кстати говоря лифтинг — это как бы совсем функциональный стиль. Т.е. мы преобразуем функцию в функцию (например складывающую числа в складывающую числа в списках). Но есть и промежуточный вариант — использовать что-то типа fmap (а для коллекций будет просто map). Т.е. можно спокойно использовать обычные функции на списках (или на промисах) и при этом обходиться без монад. Просто код будет выглядеть как apply(A, B, merge).
"без монад" значит что эти же обязанности размажешь по коду ровным слоем. Более того, функция собственно мало чем отличается от монады.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ты что-то путаешь. ))) У меня к тебе никогда никаких претензий не было, ну разве что кроме повышенной упёртости. А вот к C#...
Будет тоже самое, только вместо >>= будет функция
_>Как я понимаю ты согласился, что у C++ гораздо больше возможностей для реализации функциональных фишек в стиле Хаскеля, чем у C#? )
На бумажке больше, а на практике без внятного GC для лямбд толку никакого, чемодан без ручки.
_>>>Ну давай набор тестовых данных (входные строки и ожидаемый текст на выходе) — посмотрим. ))) I>>То есть, ты решил забрать свои слова на счет того, что не знаешь что такое optional, second и тд ?
_>Нет, я же говорю, давай входные данные и выходные (вот по ним и пойму ТЗ полностью). Кстати, ты этого так и не дал пока.
Ога, ты читать пробовал то самое сообщение, где пример кода был ?
I>>Мне чисто любопытно, прежде чем перейдем к тестовым данным, ты и вправду считаешь, что готов хотя бы это покрыть регулярными выражениями ?
_>Так не одним же сразу всё, а императивный код использующий регвыры просто для поиска/замены — с помощью этого вообще любая задачка решается. )))
просто поиск мне не нужен, мне нужно обработать язык, который в принципе не может быть описан регулярной грамматикой
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Что значит удобно, кому удобно, тебе мне или тому, кто кроме циклов и ветвлений ничего в глаза не видел ?
_>Я к тому, что должен быть предусмотреть способ в одну строчку превратить обычную коллекцию в push-коллекцию и отправить её в парсер. Если такое есть (я надеюсь Rx не идиоты писали?), то всё отлично и можно спокойно один и тот же код использовать разными способами.
Есть конечно.
_>О да, по тому примеру для парсинга всего лишь числа с плавающей точкой оно и видно. )))
Тот пример он как раз плохой, потому что в джаваскрипте никакой поддержки монад нет.
Но он гораздо лучше, чем в C#, потому что за счет динамики можно уменьшить количество текстового мусора.
В Хаскеле и других ФЯ можно сделать намного лучше и чище, практически БНФ
I>>С твоей "формулой" ты получишь 60 значений и например вполне возможно, последнее будет отрицательным. Опаньки — скорость отрицательная, а сигнал растёт.
_>Ты похоже путаешь понятие "скорости" (мгновенной, в точке) и "средней скорости по заданному интервалу". ) Это вообще то по физике ещё наверное в классе 7-ом проходят. )))
Меня интересует практическая ценность. Попробуй вывести на экран свою скорость и расскажи, как ты сможешь это использовать.
I>>Моя модель гарантирует отображение скорости, а твоя при росте уровня сигнала может показывать отрицательную скорость.
_>Мдаааа. )))
Именно так.
I>>Ты снова частный случай выдал Что мне делать, если теги будут b ? А если в них будет какой то контент, который тоже надо скипнуть ?
_>Тоже без проблем делается.
Ну да, переписывая код, и в какой то момент тебе понадобится автомат с магазином
I>>Итого — ты в очередной раз попытался натянуть регулярную грамматику на контекстно свободный язык.
_>Ну так она в реальности частенько и натягивается. Естественно не всегда (я сам могу кучу антипримеров привести), но ты вот что-то натыкаешься именно на такие. )))
Ты просто хочешь свести всё подряд к регэкспам и простым автоматам.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я к тому, что запись грамматики через linq — это не твоё изобретение, а как раз авторов библиотеки. Т.е. это не твой неудачный пример, а подразумеваемая стандартная практика.
В который раз объясняю — в C# нет паттерн-матчинга. Потому 100% библиотек берут на себя эти обязнности, в сложных случаях громоздко, неэфективно и некачественно.
Ровно то же в С++ — там нет паттерн матчинга, потому 100% библиотек содержан вагоны строчек кода, которые собтсвенно этот ПМ и делают, в сложных случаях громоздко, неэфективно и некачественно.
I>>Снова феерическая чушь — я показал пример _реактивного_ парсинга ! буст.спирит такой парсинг не умеет, как все твои yacc и lexx.
_>Так речь шла о задание грамматики, а не об этом.
Речь шла про реактивный парсинг.
>Можно же без проблем написать парсер работающий реактивно и при этом с заданием грамматики в стиле boost.sprit. Вот для этой задачи такое и было бы оптимальным.
За десять минут уложишься ?
I>>В принципе хрен с ним, со спиритом, сделай хотя бы императивно, но что бы это был честный реактивный код, условимся, для простоты, что в эвентах инфа приходит по одному символу. Скажем я могу запускать такие парсеры хоть асинхронно в одном потоке, хоть в разных, могу менять, добавлять комбинаторы как угодно. А у тебя чуть что, так надо подкладывать костыли, например из за многопоточности, паралеллизма и тд и тд и тд.
_>Ой, да хватит уже цепляться к тому тестовому примеру. Очевидно же, что если бы я писал библиотечный парсер, то это по любому был бы класс, который учитывал бы всё это и ещё кучу всяких нюансов типа обработки ошибок и т.п. Только никто в своём уме не будет писать такое ради выкладывание на форум.
На самом деле парсер-комбинаторы унутре очень простая вещь, тебе надо написать всего три короткие фукнции, дальше они комбинируются. вот скажем between это просто комбинация, фактически обычный sequence но из трех парсеров.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Такую, чтоб ошибки возникали не при "передавании типа", а при написании обобщенного кода. Обобщенный код на плюсах практически нетипизированный, хотя нетипизированность в данном случае обычно называют "permissiveness", но сути это не меняет. K>Об этом я и писал: "На самом деле понятно, как это предполагается использовать обобщенно, но проблема тут будет в том, что это обобщение не типизировано. Родственная проблема — семантическая неопределенность. Про (=<<) можно много чего сказать не зная ничего о конкретной имплементации, про ваш перегруженный сдвиг ничего сказать нельзя."
Ага, идея претензии понятна, но на самом деле она не имеет вообще никакого смысла в C++ по очень простой причине. Смысл был бы, если бы данный шаблон можно было скомпилировать (в библиотеку какую-то или даже просто объектный файл) сам по себе. Но это в C++ невозможно. Неинстанцированные шаблоны просто не существуют для компилятора и имеют смысл в коде не более чем комментарии. Ну а при инстанцированние очевидно уже возникает полная типизация во весь рост. Т.е. тут компилятор чётко выполняет свою работу в области типизации и не позволит существовать некорректному коду.
K>Даже больше одного. Я несколько раз объяснял, что контроль за эффектами и монады это темы слабосвязанные. Никакой необходимости использовать монады для такого контроля в чистом языке нет. Вы либо не понимаете, либо просто игнорируете мои объяснения и как ни в чем не бывало снова это повторяете. Скорее всего игнорируете, потому, что если бы не понимали — вы бы какие-то вопросы по этой теме задали.
Вообще то я это давно понял, согласился и т.п. И продолжаю разговор уже именно про эти самые эффекты.
K>Нет, IO и ST реализуются с помощью инкапсуляции (неэкспорта конструктора) и Rank-2 полиморфизма во втором случае. Монады особенностями реализации не являются. Монады используются для создания разделяемой кодовой базы для обобщенной работы с эффектами, функциями, списками, итераторами, генераторами значений для тестов, парсерами, сериализаторами/десериализаторами и еще зиллионом разных вещей. Будут среди них IO и ST или не буду — ничего принципиально не поменяет.
Я это уже давным давно понял. ))) Да, но только не надо совсем отделять монады от этого дела. Во-первых они всё же используются чтобы частично скрыть некие "ужасы" реализации IO/ST Хаскеля. И во-вторых, с учётом важности этого вопроса для любого нормального приложения, на практике получается что в Хаскеле монады мы видим чаще всего именно в этой области.
K>Это совершенно отдельный разговор не про полезность монад, а про полезность контроля эффектов.
Совершенно верно. И как раз про это я спрашиваю уже очень давно и так ни разу и не получил ответа. Естественно про какие-то случаи из реальной практики, а не обобщённую теорию..
Ну а про монады мне вообще то уже давно всё понятно, как в Хаскеле, так и в других языках...
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Это, разумеется, неправда. "Я видел некие примеры к wxWidgets которые на C++ выглядят лучше, чем на Haskell" точным указанием не являются. Вам, чтоб подкрепить свои слова нужно дать ссылки по которым можно пройти сразу, а сюда скопипастить обозримые примеры, которые можно было предметно обсудить. Никто за вас это не сделает, искать подтверждения и иллюстрации для ваших тезисов я не собираюсь. Конкретный хаскель-код вы предметно обсуждать отказались, а кода на плюсах, который бы мне понравился я никогда не видел, так что ничем вам тут помочь не могу.
Я вообще то говорил не про некие отвлечённые, а про вполне конкретные примеры из поставки wxWidgets. Т.е. идём в папку wxWidgets (она у меня уже много лет на компьютере), видим там папку samples и в ней ещё 86 папок с примерами на все случаи. Аналогично с wxHaskell, только там насколько я помню примеров намного меньше. Находим одинаковые и сравниваем код. Я это сделал когда-то, когда смотрел на Haskell вообще и получил вполне однозначные выводы. Сейчас прямо за секунду (а иначе лень) легко повторить это не могу, т.к. уже давно стёр и wxHaskell и сам Haskell у себя с компьютера, как не нужное. Но если кто-то хочет проверить мои слова, то алгоритм очень простой. Причём я указал на эти самые примеры в первом же своём сообщение на эту тему.
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Basil2, Вы писали:
B>А есть способы убедиться, что "ООО" это именно то что нам нужно? Например, я скачиваю программу, а она подписана "Microsoft Corporation". Как понять, что это именно M$? Ведь написать можно и "Microsoft Inc", да и просто "Microsoft"...
В общем случае нет такого способа. Хотя, думаю, что центры сертификации не пропустят вот прямо такие копии. Там же требуется предоставлять документы при получение сертификата. Ну и в случае сертификатов для сайтов есть ещё дополнительный нюанс (и он обязательно проверяемый браузером) — в самом сертификате указывается домен и если он будет использован для связи с сайтом с другого домена, то браузер будет громко ругаться.
B>P.S. Большое спасибо за объяснения, очень доходчиво. Книжку выпустить не планируете?
Спасибо отзыв. ) про книжку даже никогда не приходило такое в голову. Я как бы 100% практик и в программирование и в бизнесе, а форум просто для развлечения и разминки ума. ) Хотя образование у меня наоборот максимально академическое — может это и накладывает отпечаток. )))
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>"без монад" значит что эти же обязанности размажешь по коду ровным слоем. Более того, функция собственно мало чем отличается от монады.
Да я не об этом. Вот смотри, допустим есть такая функция:
Так вот она всегда вернёт значение y=h(g(f(x))), кем бы у нас не был x. Это могут быть "голые" значения, могут быть какие-то функторы/монады, а могут вообще какие-нибудь stl коллекции. Причём функции f, g, h не перегруженные, а есть только в одном экземпляре, работающем с "голыми" значениями. И естественно имеем тут ноль накладных расходов, в отличие от решения "а сделаем ка всё монадой на будущее, на всякий случай".
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Будет тоже самое, только вместо >>= будет функция
Ну функция вместо оператора это не принципиально... Так покажешь компилируемую реализацию liftM2 на C#? )
I>Ога, ты читать пробовал то самое сообщение, где пример кода был ?
Пример кода (если ты про C#) мне как бы ни к чему, т.к. нет никакого желания лазить по документации Rxx и понимать его смысл. Мне нужен тестовый набор входных и выходных данных и всё. Что бы после реализации никто уже точно не придрался к коду (выдаёт нужное — значит правильный).
I>просто поиск мне не нужен, мне нужно обработать язык, который в принципе не может быть описан регулярной грамматикой
Эммм, так никто и не собирается искать решение в виде "одного мега регулярного выражения". Решение задачи даёт императивный код (который, как ты понимаешь, может в принципе всё, вопрос только какой ценой в смысле размера кода). Просто его размер резко сокращается, если использовать в нём регулярные выражения.
Это если мы говорим вообще. Но парочка твоих примеров в данной темке действительно укладывалась в единое регулярное выражение, о чём я тебе и сообщил. Но естественно никто не подразумевает при этом, что такое возможно всегда.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>"без монад" значит что эти же обязанности размажешь по коду ровным слоем. Более того, функция собственно мало чем отличается от монады.
_>Да я не об этом. Вот смотри, допустим есть такая функция: _>
_>Так вот она всегда вернёт значение y=h(g(f(x))), кем бы у нас не был x. Это могут быть "голые" значения, могут быть какие-то функторы/монады, а могут вообще какие-нибудь stl коллекции. Причём функции f, g, h не перегруженные, а есть только в одном экземпляре, работающем с "голыми" значениями. И естественно имеем тут ноль накладных расходов, в отличие от решения "а сделаем ка всё монадой на будущее, на всякий случай".
В простых случаях это сгодится. Попробуй эту фукнцию примекнить к промисам, тебе сразу понадобятся монады или же аналогичный код напишешь руками.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Тот пример он как раз плохой, потому что в джаваскрипте никакой поддержки монад нет. I>Но он гораздо лучше, чем в C#, потому что за счет динамики можно уменьшить количество текстового мусора. I>В Хаскеле и других ФЯ можно сделать намного лучше и чище, практически БНФ
А можно сделать практически БНФ без всяких монад и в не функциональных языках.
I>Меня интересует практическая ценность. Попробуй вывести на экран свою скорость и расскажи, как ты сможешь это использовать.
Ты что-то совсем плаваешь в теме похоже. Скорость — это первая производная от функции и в принципе определена в точке. И её величина как раз и должна скакать как угодно. Ещё имеем среднюю скорость (думаю можно не уточнять что это такое?) на интервале — её значение существенно зависит от величины интервала и естественно более сглажено.
В компьютерах в связи с их дискретностью реально не существует чистой мгновенной скорости (если говорим о численных вычислениях, а не символьных). Т.е. формально говоря на компьютере вся скорость усреднённая. Но обычно её можно считать мгновенной, если частота выборки существенно превышает интересующие нас интервалы — тогда можно пренебречь погрешностями от дискретности.
Касательно конкретно твоей задачки. Определись просто что тебе надо выводить на экран. Скорость или же усреднённую на каком-то интервале скорость. И кстати во втором случае в нормальном софте обычно позволяют регулировать размер интервала и при этом в зависимости от этого параметра значение средней скорости вполне может и знак поменять даже...
А вообще это всё не имеет никакого отношения к данной темке. Но это ты зачем-то увёл разговор сюда. Хотя я не против — мне тема численных вычислений вполне близка. )))
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В который раз объясняю — в C# нет паттерн-матчинга. Потому 100% библиотек берут на себя эти обязнности, в сложных случаях громоздко, неэфективно и некачественно.
В C# есть по крайне мере перегрузка операторов и простенький вариант обобщённых типов. Этого уже достаточно, чтобы сделать приличное задание подобных шаблонов в коде. Но народ похоже просто увлечён той кривой хренью, которая например лично мне даже и для коллекций не нравится. Иного объяснения не нахожу.
I>За десять минут уложишься ?
Не, переписать Spirit под реактивный стиль — это не слабая задачка... ))) Но если сделать такое (в принципе ни единой проблемы там нет, просто существенный объём работы), то думаю что это будет самое идеально решение подобных задач.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В простых случаях это сгодится. Попробуй эту фукнцию примекнить к промисам, тебе сразу понадобятся монады или же аналогичный код напишешь руками.
И в чём проблема возникнет в случае промисов? )
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Будет тоже самое, только вместо >>= будет функция
_>Ну функция вместо оператора это не принципиально... Так покажешь компилируемую реализацию liftM2 на C#? )
C# в отличие от С++, не умеет rank-2 полиморфизм, в ём хилый вывод типа. Это, в кратце, означает, что лифтинг придется писать для каждого типа монад или эмулировать этот rank.2.
так
(mt1, mt2) => from x in mt1
from y in mt2
select f(x, y);
должен быть определен метод SelectMany для монадического типа
Нужен тупо самый минимум — bind и unit. Т.е. полиморфизм в JS гораздо лучше, чем в C#
I>>Ога, ты читать пробовал то самое сообщение, где пример кода был ?
_>Пример кода (если ты про C#) мне как бы ни к чему, т.к. нет никакого желания лазить по документации Rxx и понимать его смысл. Мне нужен тестовый набор входных и выходных данных и всё. Что бы после реализации никто уже точно не придрался к коду (выдаёт нужное — значит правильный).
Все что надо уже дадено
_>Эммм, так никто и не собирается искать решение в виде "одного мега регулярного выражения". Решение задачи даёт императивный код (который, как ты понимаешь, может в принципе всё, вопрос только какой ценой в смысле размера кода). Просто его размер резко сокращается, если использовать в нём регулярные выражения.
А если использовать реактивную модель в декларативном виде, то размер кода еще сильнее сокращается.
Все очень просто — этот декларативный код есть не что иное, как дсл в который упрятаны все императивные кишки которые у тебя торчат направо и налево
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А можно сделать практически БНФ без всяких монад и в не функциональных языках.
Так покажи уже эту пульку, сделай на ней реактивный парсер, а то одни слова.
I>>Меня интересует практическая ценность. Попробуй вывести на экран свою скорость и расскажи, как ты сможешь это использовать.
_>Ты что-то совсем плаваешь в теме похоже. Скорость — это первая производная от функции и в принципе определена в точке. И её величина как раз и должна скакать как угодно. Ещё имеем среднюю скорость (думаю можно не уточнять что это такое?) на интервале — её значение существенно зависит от величины интервала и естественно более сглажено.
Мгновенная скорость никого не интересует, вообще. Когда говорят просто скорость, имеют ввиду все что угодно но не мгновенную скорость. И эта скорость имеет значение только на некотором временном интервале.
Сам подумай — изменится частота опроса и внезапно твой код придется переписывать, ибо при том же самом сигнале алёрты будут приходить совершенно иначе.
_>Касательно конкретно твоей задачки. Определись просто что тебе надо выводить на экран. Скорость или же усреднённую на каком-то интервале скорость.
Есть просто скорость и есть мгновенная скорость, которая никого не интересует.
>И кстати во втором случае в нормальном софте обычно позволяют регулировать размер интервала и при этом в зависимости от этого параметра значение средней скорости вполне может и знак поменять даже...
Правильно и это легко делается — меняется размер интервала.
_>А вообще это всё не имеет никакого отношения к данной темке. Но это ты зачем-то увёл разговор сюда. Хотя я не против — мне тема численных вычислений вполне близка. )))
Это имеет непосредтсвенное отношение — наглядно демонстрирует свойства твоего решения.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В C# есть по крайне мере перегрузка операторов и простенький вариант обобщённых типов. Этого уже достаточно, чтобы сделать приличное задание подобных шаблонов в коде. Но народ похоже просто увлечён той кривой хренью, которая например лично мне даже и для коллекций не нравится. Иного объяснения не нахожу.
Перегрузка операторов и обобщенные типы очень слабые, это специально сделано. До кучи очень слабый вывод типа, что, в итоге, дает очень слабый полиморфизм — на всё надо писать методы, подсказки и тд и тд.
I>>За десять минут уложишься ?
_>Не, переписать Spirit под реактивный стиль — это не слабая задачка... ))) Но если сделать такое (в принципе ни единой проблемы там нет, просто существенный объём работы), то думаю что это будет самое идеально решение подобных задач.
Да при чем здесь переписывание спирита, я про код конкретной задачи. Представь, что спирит уже переписали под реактивный парсинг или например есть реактивный парсер в императивном виде на С++ и тд.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В простых случаях это сгодится. Попробуй эту фукнцию примекнить к промисам, тебе сразу понадобятся монады или же аналогичный код напишешь руками.
_>И в чём проблема возникнет в случае промисов? )
Вариантов решения ровно 2
1. лифтинг
var result = ComplexFunction(f, g, h, something.getX());
2. водопроводный код, т.е. в самом простом случае, надо писать примерно так
Здравствуйте, Кодт, Вы писали:
К>А моноиды и эндофункторы — это теоретический базис и гарантия того, что 0*X = X*0 = 0, 1*X = X*1 = 1, X*Y*Z = X*Y*Z (скобки расставьте по вкусу)
1. Нуля в общем случае нет.
2. В законе для нейтрального элемента очепятка — должно быть 1*X = X*1 = X
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
DM>>Вот мой вариант "монады за две минуты". К><> DM>>Мысль 2. Каждую строчку можно считать функцией, принимающей результат вычисления предыдущей (может его использовать, может не использовать), и производящей какой-то свой результат. Т.е. код выше можно переписать как К><> К>Это не "монады за 2 минуты", а "продолжения за 2 минуты".
Правильно — сходство ведь большое. Если развернуть do-сахар как раз и будет видна цепочка вложенных продолжений.
Основное отличие от CPS в том, что между действиями вводится дополнительный слой в виде custom'ного бинда, с определённой структурой (ассоциативность даёт интуитивность вложенных do, и т.п.).
Re[17]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>А чего конкретно в C++ не хватает для поддержки подобной функциональщины? K>Да, собственно, всего. Там даже Upward Funarg Problem не решена.
Всё решено.
K>А это самый минимум, необходимый для того, чтоб вообще можно было о какой-то поддержке ФП говорить. Это даже в C# есть.
Сборщик мусора пытается управлять только памятью, да и то возможны утечки. Если же брать управление ресурсами в общем — то и C# и Haskell сливают C++.
Например попробуй сделать аналог:
auto foo()
{
auto x = 5;
ofstream f("log.txt");
auto y = make_shared<Foo>(11);
return [f=move(f), =](auto z)
{
f << z << endl;
return x + y->data;
};
}
int main()
{
cout << foo()("OMG!");
}
Как только замыкание выходит из scope файл закрывается и Foo освобождается.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
K>Во втором случае (на псевдоплюсах) нигде не написано, что это за M. Использование >>= никак не отражено в сигнатуре. Вот про это я и говорил "нетипизировано" и "несодержательная сигнатура"
А что конкретно смущает? То что при плохом "M" произойдёт ошибка в теле шаблона? Так это решается, причём даже в рамках C++1998 — просто добавляется enable_if. Причём даже перегрузка будет работать (то есть можно сделать один liftM2 для монад, второй ещё для чего-нибудь).
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>А насчёт нетипизированности... Обычно под этим подразумевают, что компилятор может пропустить ошибку и она всплывёт только где-нибудь во время исполнения. В данном случае, если в качестве M передать тип не имеющий определённого оператора >>=, то компилятор выдаст соответствующую ошибку — какую ещё типизацию то можно требовать? K>Такую, чтоб ошибки возникали не при "передавании типа", а при написании обобщенного кода. Обобщенный код на плюсах практически нетипизированный, хотя нетипизированность в данном случае обычно называют "permissiveness", но сути это не меняет.
.
K>Об этом я и писал: "На самом деле понятно, как это предполагается использовать обобщенно, но проблема тут будет в том, что это обобщение не типизировано. Родственная проблема — семантическая неопределенность. Про (=<<) можно много чего сказать не зная ничего о конкретной имплементации, про ваш перегруженный сдвиг ничего сказать нельзя."
К параметрам-типам шаблонов можно указывать как синтаксические требования (C++98 SFINAE, C++11 decltype SFINAE, C++14 Concepts), так и семантические — через traits (пользователь подписывается под тем, что его тип удовлетворяет необходимым аксиомам).
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
_>>Как я понимаю ты согласился, что у C++ гораздо больше возможностей для реализации функциональных фишек в стиле Хаскеля, чем у C#? ) I>На бумажке больше, а на практике без внятного GC для лямбд толку никакого, чемодан без ручки.
GC это полумера:
using System;
using System.IO;
public class Test
{
public delegate void fireworks();
public static fireworks make_closure(FileStream fs)
{
return () => fs.Read(new byte[10], 0, 10); // "чемодан без ручки"
}
public static fireworks fire()
{
using (var fs = File.Open("file", FileMode.Open))
{
return make_closure(fs);
}
}
public static void Main()
{
fire()(); // System.ObjectDisposedException
}
}
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
K>Во втором случае (на псевдоплюсах) нигде не написано, что это за M. Использование >>= никак не отражено в сигнатуре. Вот про это я и говорил "нетипизировано" и "несодержательная сигнатура"
Ну понятно, что мета-типизация у плюсов утиная. Но компилятор всё равно проверит наличие функций из словаря Monad, — если они были востребованы, конечно. Так что эти утки крякают не в рантайме.
А при желании можно явно прикрутить контракт — "принадлежность M<*> к модели Monad", самым простым способом — через enable_if и т.п.
Просто для хаскелла это является не желанием, а требованием, которое смягчено автоматическим выводом сигнатуры.
Сравни
liftM2 f ma mb = do { a<-ma; b<-mb; return f a b }
здесь нигде не сказано Monad m =>, но do-нотация или водопровод на это намекают. Так же, как на это будет намекать водопровод в определении плюсовой функции liftM2.
_>>Суть в том, что на практике монады как раз нужны достаточно редко. K>Т.е. возвращать из функций вида a -> m b и передавать в другие — это все-таки редко нужно, я правильно понял?
Мне здесь внезапно увиделась фиксация: раз в хаскелле эндофункторы — это из типа в тип и из функции в функцию, то давайте и во всех остальных языках будем проецировать типы и функции. При том, что механизмы операций над типами и функциями или убоги, или просто другие.
Не могу словами выразить, но чувствую, что где-то кидают.
Перекуём баги на фичи!
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
_>>>Как я понимаю ты согласился, что у C++ гораздо больше возможностей для реализации функциональных фишек в стиле Хаскеля, чем у C#? ) I>>На бумажке больше, а на практике без внятного GC для лямбд толку никакого, чемодан без ручки.
EP>GC это полумера: EP>
EP>
GC к твоему коду не имеет никакого отношения, а твой код не имеет никакого отношения к лифтингу. Так что ни о чем
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>На бумажке больше, а на практике без внятного GC для лямбд толку никакого, чемодан без ручки. EP>>GC это полумера: EP>>
EP>>
I>GC к твоему коду не имеет никакого отношения,
О чём и речь — лямбды есть, GC есть — а чемодан всё равно без ручки
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>GC к твоему коду не имеет никакого отношения,
EP>О чём и речь — лямбды есть, GC есть — а чемодан всё равно без ручки
Для лямбд в C# есть всё что надо, нет rank-2 полиморфизма для монад, решается метапрограммированием довольно легко. Ручки нет, но можно приделать.
В С++ есть rank-2, но лямбы без ручки и приделать её нельзя, только руками-руками-руками.
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Artem Korneev, Вы писали:
AK>vim имеет удобно интегрированную поддержку регулярных выражений, что позволяет легко и быстро производить такую обработку текста.
MSVS, что характерно, тоже умеет по регексам искать. А в Productivity Power Tools есть еще куча мелочей на эту темы.
... << RSDN@Home 1.2.0 alpha 5 rev. 100 on Windows 8 6.2.9200.0>>
I>должны быть определены методы Bind и Unit для монадического типа
Собственно это нормальный вариант и эти функции по любому определяются и в Хаскеле и в том моём примере. Только вот как ты и сам сказал, тебе придётся писать по отдельной реализации liftM2 для каждого типа монады, что уже совсем не дело.
Кстати, Klapaucius говорил как раз о чём-то подобном, когда намекал что у C++ могут быть какие-то сложности с реализацией liftM2. Похоже что его знания императивных языков ограничиваются как раз такими как C# и Java. )))
I>А если использовать реактивную модель в декларативном виде, то размер кода еще сильнее сокращается.
I>Все очень просто — этот декларативный код есть не что иное, как дсл в который упрятаны все императивные кишки которые у тебя торчат направо и налево
Само собой, что использование некого библиотечного кода в большинстве случаев (кроме самых простых) будет более коротким, чем попытка решить проблему в лоб. Только это никак не связано с реактивностью, декларативностью или монадами.
Если же сравнивать именно такие вещи, то надо взять с одной стороны эту твою библиотеку, а с другой скажем реактивный вариант boost.spirit и сравнить какой объём кода получается у них...
Здравствуйте, Ikemefula, Вы писали:
I>Так покажи уже эту пульку, сделай на ней реактивный парсер, а то одни слова.
Я же не сказал, что подобная библиотека существует. Хотя написать её никаких принципиальных проблем нет. Просто определённый объём работы.
I>Мгновенная скорость никого не интересует, вообще. Когда говорят просто скорость, имеют ввиду все что угодно но не мгновенную скорость. И эта скорость имеет значение только на некотором временном интервале.
Ужас какой. ))) Скорость — это первая производная. И точка, без всяких вариантов.
I>Правильно и это легко делается — меняется размер интервала.
Ну так если в твоей задачке надо выводить алерты по значению средней скорости на каком-то интервале, то прямо так и сказал бы. Это конечно же чуть сложнее, чем вариант с просто скоростью — не одна строчка кода, а целых две.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Да при чем здесь переписывание спирита, я про код конкретной задачи. Представь, что спирит уже переписали под реактивный парсинг или например есть реактивный парсер в императивном виде на С++ и тд.
Если ты про ту свою задачку анализатора логов, то я ещё раз говорю, что для неё скорее всего просто императивный код на регулярных выражениях проще будет. Реактивный естественно. Т.е. что-то вроде:
Здравствуйте, Ikemefula, Вы писали:
I>Вариантов решения ровно 2
Ээээ вариантов решения чего? ) Какой проблемы то? Ты так и не сказал почему приведённый мною там код не сработает для промисов. Или ты не понял его идею, что он автоматом работает для всего, в том числе и для них? )
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Вариантов решения ровно 2
_>Ээээ вариантов решения чего? ) Какой проблемы то? Ты так и не сказал почему приведённый мною там код не сработает для промисов. Или ты не понял его идею, что он автоматом работает для всего, в том числе и для них? )
А кто его научит лифтинг делать в промисы ? Функции над самими промисами мне совершенно незачем выполнять.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Если ты про ту свою задачку анализатора логов, то я ещё раз говорю, что для неё скорее всего просто императивный код на регулярных выражениях проще будет. Реактивный естественно. Т.е. что-то вроде: _>
Здравствуйте, alex_public, Вы писали:
I>>Так покажи уже эту пульку, сделай на ней реактивный парсер, а то одни слова.
_>Я же не сказал, что подобная библиотека существует. Хотя написать её никаких принципиальных проблем нет. Просто определённый объём работы.
И такая скорость никому не интересна. Увеличь частоту опроса хотя бы в 10 раз и попробуй глазом различить изменение скорости.
I>>Правильно и это легко делается — меняется размер интервала.
_>Ну так если в твоей задачке надо выводить алерты по значению средней скорости на каком-то интервале, то прямо так и сказал бы. Это конечно же чуть сложнее, чем вариант с просто скоростью — не одна строчка кода, а целых две.
И это, заметь, мы еще не говорили про комбинирование эвентов, например
кидать алёрт если скорость в период А другого сигнала выше определенного значения
Итого — на любое изменение требований тебе надо работать руками-руками-руками, например
1 асинхрронщна
2 многопоточность
3 обработка временных интервалов
4 комбинирование сигналов
Вот после того, как ты покажешь такие вещи, можно будет говорить про реактивное программирование
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Собственно это нормальный вариант и эти функции по любому определяются и в Хаскеле и в том моём примере. Только вот как ты и сам сказал, тебе придётся писать по отдельной реализации liftM2 для каждого типа монады, что уже совсем не дело.
И снова тот же вопрос — какое отношение имеет C# к монадам ?
_>Кстати, Klapaucius говорил как раз о чём-то подобном, когда намекал что у C++ могут быть какие-то сложности с реализацией liftM2. Похоже что его знания императивных языков ограничиваются как раз такими как C# и Java. )))
Он просто погорячился. У тебя вагон кода на ровном месте. Ради одного лифтинга никто потеть не будет. Минимум что необходимо это библиотечка навроде Boost.Phoenix, только для монад.
Отсюда, внезапно, можно сделать вывод — библиотечка будет еще страшнее чем Boost.Phoenix.
Ты открой и посмотри, феникс этот и есть то, как выглядит функциональщина в C++
I>>Все очень просто — этот декларативный код есть не что иное, как дсл в который упрятаны все императивные кишки которые у тебя торчат направо и налево
_>Само собой, что использование некого библиотечного кода в большинстве случаев (кроме самых простых) будет более коротким, чем попытка решить проблему в лоб.
А мне постоянно кажется, что ты хочешь обратное доказать.
>Только это никак не связано с реактивностью, декларативностью или монадами.
Конечно, всё можно написать императивно на ассемблере, следовательно все что свыше — лишнее.
_>Если же сравнивать именно такие вещи, то надо взять с одной стороны эту твою библиотеку, а с другой скажем реактивный вариант boost.spirit и сравнить какой объём кода получается у них...
_>Кстати, тебе наверное должны нравиться вот такие https://github.com/beark/ftl/blob/master/docs/Parsec-I.md штуки... А мне это всё как-то совсем не нравится.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Я свою написал, небольшую, на C# и JS и сейчас хочу выпилить нормальный реактивный парсинг, потому что авторы всяких RX, beacon увлеклись созданием всемогуторов, которые ни в один проект в своём уме всунуть нельзя и практическая ценность около нуля.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А кто его научит лифтинг делать в промисы ? Функции над самими промисами мне совершенно незачем выполнять.
Так это всё в функциях apply. Они перегружены по типу второго аргумента. Для "голых" значений будет просто применение функции, для монад/функторов применение к внутреннему значению (вот промисы сюда попадают), для коллекций stl поэлементное применение и т.п.
Да, и главное в такое схеме, что функций apply всего несколько (по количеству используемых монад или чего там ещё), а функции f,g, h никто не размножает, хотя они теперь как бы могут применяться к чему угодно...
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Давай закончим, а то ты дошел до парсинга джаваскрипта регэекспами
Ещё раз, это не парсинг js (в смысле построения AST и т.п.), а поиск нужного нам в строке (ну и что, что там js код?) по шаблону. Не надо путать эти вещи. Если для решения нашей задачки достаточно второго, то совершенно ни к чему тащить в проект полноценный парсер js.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>А кто его научит лифтинг делать в промисы ? Функции над самими промисами мне совершенно незачем выполнять.
_>Так это всё в функциях apply. Они перегружены по типу второго аргумента. Для "голых" значений будет просто применение функции, для монад/функторов применение к внутреннему значению (вот промисы сюда попадают), для коллекций stl поэлементное применение и т.п.
То есть, вариант 1, ты хочешь лифтинг всунуть унутрь. Чем это отличается от обычного лифтинга — не ясно
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Давай закончим, а то ты дошел до парсинга джаваскрипта регэекспами
_>Ещё раз, это не парсинг js (в смысле построения AST и т.п.), а поиск нужного нам в строке (ну и что, что там js код?) по шаблону. Не надо путать эти вещи. Если для решения нашей задачки достаточно второго, то совершенно ни к чему тащить в проект полноценный парсер js.
объясни, как ты собираешься скипнуть вот такой код, буде он придет в логе
function name(arg /*, ... камент*/){
... // произвольный код, т.е. любой валиднй код на JS
}
Из него нужно взять только name и только тогда, если весь блок является кодом на JS
Покажи уже решение — я обещаю, не буду выдавать его за своё и Нобелевская премия достанется только тебе
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Даже если забыть, что это просто теория, а не реальные библиотеки, то это всё равно на базе монад и прочего. А я говорил как раз о парсере с заданием грамматики в стиле Спирита, только реактивном.
I>И такая скорость никому не интересна. Увеличь частоту опроса хотя бы в 10 раз и попробуй глазом различить изменение скорости.
Вообще то скорость нужна не только для вывода на панель человеку. )))
I>Итого — на любое изменение требований тебе надо работать руками-руками-руками, например I>1 асинхрронщна I>2 многопоточность I>3 обработка временных интервалов I>4 комбинирование сигналов
I>Вот после того, как ты покажешь такие вещи, можно будет говорить про реактивное программирование
А я разве где-то говорил, что я предлагаю для всех случаев использовать код в лоб? Вообще то я писал прямо противоположное. Что мы можем реализовать нашу функцию Analyze любым удобным способом (а не один единственным, как в Rxx). Для простых случаев императивным кодом в лоб, а для сложных можем взять любые подходящие библиотеки (конечные автоматы, БНФ-парсеры и что угодно ещё). Ты внимательнее читай то, что я пишу и не придумывай за меня мои слова.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Он просто погорячился. У тебя вагон кода на ровном месте. Ради одного лифтинга никто потеть не будет. Минимум что необходимо это библиотечка навроде Boost.Phoenix, только для монад.
Ммм, нет, в данном случае объём кода абсолютно равный Хаскелю. Разница только в количестве всяких скобочек и т.п.
I>Отсюда, внезапно, можно сделать вывод — библиотечка будет еще страшнее чем Boost.Phoenix. I>Ты открой и посмотри, феникс этот и есть то, как выглядит функциональщина в C++
Да, внутри будет именно так. Но для пользователя библиотеки всё будет просто супер.
Кстати, а полезность Boost.Phoenix на мой взгляд сильно изменилась с выходом C++11...
I>А мне постоянно кажется, что ты хочешь обратное доказать.
Просто ты постоянно приводишь такие примеры, где сам собой напрашивается простейший код в пару строк в лоб. )))
А так я вообще то сам люблю взять готовую библиотечку какую-нибудь. ))) Только вот использование готовой библиотеки совершенно не означает, что она должна быть на базе монад.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я свою написал, небольшую, на C# и JS и сейчас хочу выпилить нормальный реактивный парсинг, потому что авторы всяких RX, beacon увлеклись созданием всемогуторов, которые ни в один проект в своём уме всунуть нельзя и практическая ценность около нуля.
Ооо, одобряю подход твой. Правда боюсь, что обойтись без монад всё равно не захочешь. )))
Кстати, насчёт той моей ссылки: реализация монадных парсеров — это у них просто типа примера использования библиотечки. А так у них цель немного другая. Что-то типа "притащить Хаскель в C++". ))) На мой взгляд нафиг не нужно, но тебе может будет любопытно взглянуть http://libftl.org.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, вариант 1, ты хочешь лифтинг всунуть унутрь. Чем это отличается от обычного лифтинга — не ясно
Лифтинг работает только на монадах (правда там как плюс можно сделать одну функцию на все виды монад). А тут мы можем работать вообще с чем угодно, причём сразу (один код сложной функции на все случаи). И ещё если в качестве этого "что угодно" будут "голые" значения, то мы не получим никаких накладных расходов.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>объясни, как ты собираешься скипнуть вот такой код, буде он придет в логе
I>
I>function name(arg /*, ... камент*/){
I> ... // произвольный код, т.е. любой валиднй код на JS
I>}
I>
I>Из него нужно взять только name и только тогда, если весь блок является кодом на JS
А там у нас может быть не только js код? ) С чего бы это? По условиям задачки я такого не помню. Насколько я помню у нас внутри "pir:" только js код. Ну и если только js, то думаю не надо говорить как вырезать из этого name? )))
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Даже если забыть, что это просто теория, а не реальные библиотеки, то это всё равно на базе монад и прочего. А я говорил как раз о парсере с заданием грамматики в стиле Спирита, только реактивном.
С++ не умеет те операторы, которые нужны для БНФ или РБНФ.
то есть придется эмулировать все подряд, например следование придется пилить явно, скобки и прочую вешь так же придется эмулировать, т.е. пилить явно.
Вот смотри, твой спирит, я даже не знаю, не то смеяться, не то плакать.
expr = term | term '+' term | term '-' term
term = factor '*' factor | factor '/' factor
factor = number | '(' expr ')' | '-' factor | '+' factor
number = digit {digit}
digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Итого — в спирите раз в 7-8 раз больше кода чем в бнф грамматике, при том что два правила сидят в самой либине — digit и uint, если их добавить, кода будет в 10 раз больше
А вот фокус — та же грамматика на комбинаторах
var term = empty();
var unary = empty();
var number = rep1(range('0..9'))
var expr = or(term, seq(term, or('-+'), term))
var term = term.overWrite(seq( factor, or('*/'), factor))
var factor = or(number, seq('(',expr,')'), unary)
var unary = unary.overWrite(seq(or('-+'), factor))
тут не всё, справа надо добавить .map(AST.ляляля), т.е. трансляцию в АСТ, количество кода не сильно изменится
Итого — спирит сосёт не нагибаясь.
I>>И такая скорость никому не интересна. Увеличь частоту опроса хотя бы в 10 раз и попробуй глазом различить изменение скорости. _>Вообще то скорость нужна не только для вывода на панель человеку. )))
"не для вывода" мгновенная скорость так же бсолютно никому не интересна. Представь — надо управлять заслонкой печи в зависимости от скорости роста температуры. Как это в твоем случае сделать — не ясно, ибо мгновенная скорость может быть отрицительная, а температура в котле будет расти
I>>Итого — на любое изменение требований тебе надо работать руками-руками-руками, например I>>1 асинхрронщна I>>2 многопоточность I>>3 обработка временных интервалов I>>4 комбинирование сигналов
I>>Вот после того, как ты покажешь такие вещи, можно будет говорить про реактивное программирование
_>А я разве где-то говорил, что я предлагаю для всех случаев использовать код в лоб? Вообще то я писал прямо противоположное.
Твои частные случаи неинтересны, это аргумент в духе "всё пишется на ассемблере -> ЯВУ не нужен"
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Из него нужно взять только name и только тогда, если весь блок является кодом на JS
_>А там у нас может быть не только js код? ) С чего бы это? По условиям задачки я такого не помню. Насколько я помню у нас внутри "pir:" только js код. Ну и если только js, то думаю не надо говорить как вырезать из этого name? )))
js он паттерном идёт, как раз для того, что бы отделить от остального мусора
Очевидно, что в логе не только JS, там результаты функций, снимки состояния и тд и тд.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>То есть, вариант 1, ты хочешь лифтинг всунуть унутрь. Чем это отличается от обычного лифтинга — не ясно
_>Лифтинг работает только на монадах (правда там как плюс можно сделать одну функцию на все виды монад). А тут мы можем работать вообще с чем угодно, причём сразу (один код сложной функции на все случаи). И ещё если в качестве этого "что угодно" будут "голые" значения, то мы не получим никаких накладных расходов.
Пудозреваю, тебе самое время смотреть boost.phoenix
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я свою написал, небольшую, на C# и JS и сейчас хочу выпилить нормальный реактивный парсинг, потому что авторы всяких RX, beacon увлеклись созданием всемогуторов, которые ни в один проект в своём уме всунуть нельзя и практическая ценность около нуля.
_>Ооо, одобряю подход твой. Правда боюсь, что обойтись без монад всё равно не захочешь. )))
Можно и без монад — получатся автоматы на коленке с конской вложенностью, простынями из свичей и все это будет размазано по десяткам эвентов.
_>Кстати, насчёт той моей ссылки: реализация монадных парсеров — это у них просто типа примера использования библиотечки. А так у них цель немного другая. Что-то типа "притащить Хаскель в C++". ))) На мой взгляд нафиг не нужно, но тебе может будет любопытно взглянуть http://libftl.org.
Эта хрень такая же страшная, как и boost.phoenix. Все такие возможности очень актуальны, ибо в С++ возможностей для интеграции около нуля. Именно по этой причине для интеграции берут более другой язык — JS, Python, Lua и тд вплоть до С# или Джавы, не гнушаясь даже vbs.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Он просто погорячился. У тебя вагон кода на ровном месте. Ради одного лифтинга никто потеть не будет. Минимум что необходимо это библиотечка навроде Boost.Phoenix, только для монад.
_>Ммм, нет, в данном случае объём кода абсолютно равный Хаскелю. Разница только в количестве всяких скобочек и т.п.
Я чет не заметил, в хаскеле одна прозрачная строчка а у тебя только первяс строчка, что из темплейтов, и уже втрое длиннее.
I>>Отсюда, внезапно, можно сделать вывод — библиотечка будет еще страшнее чем Boost.Phoenix. I>>Ты открой и посмотри, феникс этот и есть то, как выглядит функциональщина в C++
_>Да, внутри будет именно так. Но для пользователя библиотеки всё будет просто супер.
Я в это не верю. За все время ни разу не видел либы, в которую не надо было бы лазить при разработке.
Здравствуйте, Ikemefula, Вы писали: _>>Кстати, Klapaucius говорил как раз о чём-то подобном, когда намекал что у C++ могут быть какие-то сложности с реализацией liftM2. Похоже что его знания императивных языков ограничиваются как раз такими как C# и Java. ))) I>Он просто погорячился. У тебя вагон кода на ровном месте. Ради одного лифтинга никто потеть не будет. Минимум что необходимо это библиотечка навроде Boost.Phoenix, только для монад. I>Отсюда, внезапно, можно сделать вывод — библиотечка будет еще страшнее чем Boost.Phoenix. I>Ты открой и посмотри, феникс этот и есть то, как выглядит функциональщина в C++
Boost.Phoenix даёт:
лямбды — с приходом лямбд в C++11 менее актуально
полиморфные лямбды — с приходом полиморфных лямбд в C++14 менее актуально
короткую нотацию для лямбд, причём даже короче чем в C#: (_1 + _2)(11, 22) == 33
Здравствуйте, alex_public, Вы писали:
K>>Это совершенно отдельный разговор не про полезность монад, а про полезность контроля эффектов.
_>Совершенно верно. И как раз про это я спрашиваю уже очень давно и так ни разу и не получил ответа. Естественно про какие-то случаи из реальной практики, а не обобщённую теорию..
Нужен практический пример полезности контроля эффектов? Есть процесс, имеющий состояние и управляемый потоком событий. Результатом обработки события может быть либо ошибка (и старое состояние), либо новое измененное состояние и ряд эффектов (конкретно — изменение внешнего мира).
Без контроля эффектов псевдокод будет выглядеть так:
State иммутабельно. Способ возврата ошибки (в данном случае — исключение) к примеру отношения не имеет.
Если бы processEventOrFail не имела побочных эффектов (в данном случае кроме возврата исключения), этот код был бы удовлетворителен. Если язык не позволяет тем или иным способом контролировать эффекты, мы будем выкручиваться как-то так (код по прежнему очень псевдо):
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Ты открой и посмотри, феникс этот и есть то, как выглядит функциональщина в C++
EP>Boost.Phoenix даёт: EP> лямбды — с приходом лямбд в C++11 менее актуально EP> полиморфные лямбды — с приходом полиморфных лямбд в C++14 менее актуально EP> короткую нотацию для лямбд, причём даже короче чем в C#: (_1 + _2)(11, 22) == 33
EP>А DO-сахар для монад реализуются ровно в сорок строк без всякого Phoenix'а:
Я не сильно знаю Хаскель что бы сравнить, но помня твои примеры про await, где то ты сильно недоговариваешь
Здравствуйте, alex_public, Вы писали:
_>Ага, идея претензии понятна, но на самом деле она не имеет вообще никакого смысла в C++ по очень простой причине. Смысл был бы, если бы данный шаблон можно было скомпилировать (в библиотеку какую-то или даже просто объектный файл) сам по себе. Но это в C++ невозможно. Неинстанцированные шаблоны просто не существуют для компилятора и имеют смысл в коде не более чем комментарии.
Непонятно, как причина претензии лишает претензию смысла. Именно потому, что так происходит претензия и имеет смысл.
_>Ну а при инстанцированние очевидно уже возникает полная типизация во весь рост. Т.е. тут компилятор чётко выполняет свою работу в области типизации и не позволит существовать некорректному коду.
Чем раньше ошибка выявляется — тем лучше. Поэтому претензия вполне обоснована.
_>Вообще то я это давно понял, согласился и т.п. И продолжаю разговор уже именно про эти самые эффекты.
И тем не менее парой строчек ниже:
_>Во-первых они всё же используются чтобы частично скрыть некие "ужасы" реализации IO/ST Хаскеля.
опять двадцать пять.
_>Совершенно верно. И как раз про это я спрашиваю уже очень давно и так ни разу и не получил ответа. Естественно про какие-то случаи из реальной практики, а не обобщённую теорию..
Я же говорю, как только разберем "ужасы" — так сразу.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Сейчас прямо за секунду (а иначе лень) легко повторить это не могу, т.к. уже давно стёр и wxHaskell и сам Haskell у себя с компьютера, как не нужное. Но если кто-то хочет проверить мои слова, то алгоритм очень простой. Причём я указал на эти самые примеры в первом же своём сообщение на эту тему.
Еще раз: не стоит надеяться на то, что оппонент будет искать за вас доказательства вашей правоты, если сами вы не готовы потратить на это хотя бы столько же времени, сколько на очередное сообщение о том, что вы это делать не станете.
Кроме того, уже известно из опыта, что обсуждать конкретный код и указывать в чем проблемы вы не станете.
Понятно, что такое последовательное нежелание переходить от общих заявлений к конкретике скорее всего свидетельствует о том, что никаких подтверждений своим тезисам в конкретных примерах вы даже и не рассчитываете найти, иначе с примеров и начали бы, а не с бла-бла-бла.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>Ну понятно, что мета-типизация у плюсов утиная. Но компилятор всё равно проверит наличие функций из словаря Monad, — если они были востребованы, конечно.
Ну это не совсем так и даже совсем не так. Функция может быть использована в другой обобщенной функции. А проверка будет только после конкретизации.
К>А при желании можно явно прикрутить контракт — "принадлежность M<*> к модели Monad", самым простым способом — через enable_if и т.п. К>Просто для хаскелла это является не желанием, а требованием, которое смягчено автоматическим выводом сигнатуры.
Ну правильно. Только поэтому это и является чем-то практически полезным. Ведь если что-то можно не написать — это и не напишут. Вот и мой оппонент этого не сделал, хотя я его предупредил с самого начала, что я считаю недостатком.
К>Сравни К>
К>liftM2 f ma mb = do { a<-ma; b<-mb; return f a b }
К>
К>здесь нигде не сказано Monad m =>, но do-нотация или водопровод на это намекают. Так же, как на это будет намекать водопровод в определении плюсовой функции liftM2.
Ну, это не серьезно. Типы все равно будут проверены, даже если они не проаннотированы. Обобщенная сигнатура ведь может быть выведена не для всякого кода, а значит широкий класс ошибок будет выявляться без всякой специализации. Да и есть возможность узнать тип функции.
"Водопровод" же в коде на C++ ни на какую семантику не намекает. Его можно практически как угодно перегрузить. Понятно, что законы для классов в хаскеле — это только традиция, никак это не проверяется, но традиция все-таки есть, да и типы перегружаемого оператора фиксированы. В C++ из-за невозможности объявлять свои операторы (и следующего из этого дефицита имен для операторов) у такой традиции просто не было шанса сформироваться.
И раз уж речь о полезности монад вообще — в языке где законы для монад будут проходить машинную проверку — монады будут еще полезнее.
К>Мне здесь внезапно увиделась фиксация: раз в хаскелле эндофункторы — это из типа в тип и из функции в функцию, то давайте и во всех остальных языках будем проецировать типы и функции. При том, что механизмы операций над типами и функциями или убоги, или просто другие. К>Не могу словами выразить, но чувствую, что где-то кидают.
Да, в языках, которые другие — от монад можно получить не всю перечисленную мной пользу. Вот в C# никакие эндофункторы из-за ограничений системы типов невозможны, так что "повторное использование" из списка можно вычеркивать, но все что сказано про "знаем 80% в каждом из всех возможных встроенных языков, изучив один любой" и "монадические законы подсказывают дизайн-решения для разработчика встроенного языка", и про синтаксическую маскировку "обвязки" — это все остается. И какую-то пользу из монад можно извлекать пока в языке есть хоть что-то отдаленно напоминающее функции вида "из легкого в что-то не очень простое".
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И раз уж речь о полезности монад вообще — в языке где законы для монад будут проходить машинную проверку — монады будут еще полезнее.
В общем случае не получится, как минимум из-за проблемы остановки.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
К>>Ну понятно, что мета-типизация у плюсов утиная. Но компилятор всё равно проверит наличие функций из словаря Monad, — если они были востребованы, конечно. K>Ну это не совсем так и даже совсем не так. Функция может быть использована в другой обобщенной функции. А проверка будет только после конкретизации.
Это я и назвал "если будут востребованы".
Конечно, вольности по специализации и перегрузкам у плюсов таковы, что всегда можно что-то сломать или упустить.
Но это лечится введением дополнительного слоя шаблонов, который мы договоримся не трогать, и в котором всё будет проверено и востребовано.
Очень грубо говоря, вместо M<T> будем оперировать HaskType<M<T>>, то есть, введём единую монаду (монадный трансформер) HaskType, и вообще всё на свете лифтанём в него.
Будет нам
K>И раз уж речь о полезности монад вообще — в языке где законы для монад будут проходить машинную проверку — монады будут еще полезнее.
А насколько это технически возможно, и насколько оправданно?
Опять же, кроме монад, у нас много где фигурируют законы.
Насколько мы здесь рискуем попасть на проблему останова?
К>>Мне здесь внезапно увиделась фиксация: раз в хаскелле эндофункторы — это из типа в тип и из функции в функцию, то давайте и во всех остальных языках будем проецировать типы и функции. При том, что механизмы операций над типами и функциями или убоги, или просто другие. К>>Не могу словами выразить, но чувствую, что где-то кидают.
K>Да, в языках, которые другие — от монад можно получить не всю перечисленную мной пользу. Вот в C# никакие эндофункторы из-за ограничений системы типов невозможны, так что "повторное использование" из списка можно вычеркивать, но все что сказано про "знаем 80% в каждом из всех возможных встроенных языков, изучив один любой" и "монадические законы подсказывают дизайн-решения для разработчика встроенного языка", и про синтаксическую маскировку "обвязки" — это все остается. И какую-то пользу из монад можно извлекать пока в языке есть хоть что-то отдаленно напоминающее функции вида "из легкого в что-то не очень простое".
В таких языках функторы ад-хок и идиоматические, например, "а давайте сделаем на итераторах". И дальше — руками колбасить, подставляя типы какие следует куда следует (т.е. не компилятор, а сам программист выступит функтором). Но — в канве исходной идеи. Польза от компилятора в том, что он гораздо реже ошибается.
Перекуём баги на фичи!
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Кодт, Вы писали:
К>Это я и назвал "если будут востребованы".
Я понял. Так я и говорю, что это звучит неплохо, как будто все в порядке: зачем что-то невостребованное проверять? На деле же, ничего хорошего нет: половина хекеджа — обобщенный код, который в рамках библиотеки не конкретизируется, одни обобщенные функции, использующиеся в других обобщенных функциях. В тех условиях, когда обобщенный код по факту не типизирован — разрабатывать все это было бы затруднительно.
К>А насколько это технически возможно
Технически это вполне возможно.
К>и насколько оправданно?
На этот счет у меня сложившегося мнения нет. Я вообще не любитель доказывания, но то, что какая-то польза от этого может быть — не отрицаю. тут весь вопрос в том, насколько легковесной можно сделать эту систему верификации.
К>Опять же, кроме монад, у нас много где фигурируют законы.
Ну понятно, что речь идет о проверке законов для инстансов тайпклассов (или каких-то их аналогов), а не только для монад.
К>Насколько мы здесь рискуем попасть на проблему останова?
Во-первых, проблема останова касается языков с общей рекурсией. Если ее (и возможностей ее организовать вроде типов, которые строго позитивными не являются) в языке нет, то и беспокоиться не о чем. Если, к примеру, есть только структурная рекурсия и корекурсия, то завершимость можно проверить. (Для структурной рекурсии по индукции доказать, для корекурсии — еще проще, там каждый шаг завершается и "возвращает управление").
Во-вторых, в языках где ограничений на рекурсию нет, проблема останова на практике означает, что проверка завершения консервативная, будет код, для которого завершимость можно проверить, а будет такой, который завершается, но termination checker это проверить не в состоянии и такой код будет ложно считаться "незавершающимся". Эта ситуация ничем не отличается от проверки типов, которая также консервативна и отбраковывает вполне работающий код. На практике же, это не мешает с пользой проверять типы.
Проверка завершимости есть и для обычных языков, не только для пруф ассистантов вроде Агды. Вот, например, такой инструмент для Хаскеля.
В-третих, даже проверка законов без проверки завершения может быть полезна. Понятно, что какой-нибудь undefined в такой системе доказывает все что угодно, но программисты часто (ну ладно, иногда) будут стараться что-то доказать, и не смотря на дырявость системы и ложные сообщения чекера о том, что все проверено, какая-то часть ошибок будет обнаружена.
Даже третий, самый слабый вариант лучше "договорных" законов.
К>В таких языках функторы ад-хок и идиоматические, например, "а давайте сделаем на итераторах". И дальше — руками колбасить, подставляя типы какие следует куда следует (т.е. не компилятор, а сам программист выступит функтором). Но — в канве исходной идеи. Польза от компилятора в том, что он гораздо реже ошибается.
Ну да, все правильно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Ну, понятно. Это же пример, который типизация необоснованно запрещает, а ее отсутствие — разрешает (как и множество других веселых вещей).
Вполне ожидаемо, что "разрешительная" (т.е. фактически отсутствующая) типизация плюсового обобщенного кода ее разрешит.
EP>К параметрам-типам шаблонов можно указывать как синтаксические требования (C++98 SFINAE, C++11 decltype SFINAE, C++14 Concepts), так и семантические — через traits (пользователь подписывается под тем, что его тип удовлетворяет необходимым аксиомам).
А можно и не указывать. Вот мой оппонент и не указал. Да и вы не указали — просто написали, что это возможно. Так подавляющее большинство программистов и поступит: не укажет, но отметит, что можно было и указать. Поэтому разница между типизацией опциональной и отсутствующей на практике довольно эфемерна. Типизация только потому может как легковесная верификация работать, что от нее просто так не отвертишься.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>С++ не умеет те операторы, которые нужны для БНФ или РБНФ. I>то есть придется эмулировать все подряд, например следование придется пилить явно, скобки и прочую вешь так же придется эмулировать, т.е. пилить явно.
Ужас то какой. )))
I>Вот смотри, твой спирит, я даже не знаю, не то смеяться, не то плакать. I>...
Кстати, вот на таких примерах (когда строим полноценную AST) не видны некоторые удобнейшие (на мой вкус) возможности использования Спирита. Например такая int_[([](const int& n){cout<<n<<endl;})] % ',' штука не просто задаёт список интов разделённых запятой, но и сразу же пишется реакция на распознанное значение. Причём таких реакций может быть сколько угодно — хоть на каждый элемент грамматики или их группу. В итоге получается писать крайне краткие и быстрые парсеры для простых вещей.
I>вот BNF: I>...
А это на каком языке программирования написано?
I>А вот фокус — та же грамматика на комбинаторах I>... I>тут не всё, справа надо добавить .map(AST.ляляля), т.е. трансляцию в АСТ, количество кода не сильно изменится
Генерация AST — это ладно, это действительно не надо показывать (т.к. тогда ещё само AST определять надо). А вот где сам парсинг то? ) В случае Спирита понятно, что парсинг всегда осуществляется ровно одним вызовом глобальной функции, которой передаётся строка и грамматика. А тут у нас что делать с этим списком переменных?
Т.е. вот предположим нам надо не AST сгенерировать, а напечатать разобранное выражение в консоль (но с другим форматирование естественно). Как будет тогда выглядеть полный код на базе твоего варианта? Кстати, в случае Спирита это одна строчка будет...
Ну а про разницу в скорости при определение грамматики во время копиляции или во время исполнения я даже особо упоминать не буду — про это по идее и так все помнят.
I>"не для вывода" мгновенная скорость так же бсолютно никому не интересна. Представь — надо управлять заслонкой печи в зависимости от скорости роста температуры. Как это в твоем случае сделать — не ясно, ибо мгновенная скорость может быть отрицительная, а температура в котле будет расти
Хы, в таких задачах (где есть всё работает по определённым законам и можно точно предсказывать "будущее") вообще всё по другому делают. Про фильтр Калмана слышал? ) Кстати, как ты думаешь, там будет фигурировать нормальная скорость или средняя? )))
Хотя, как я уже говорил, на самом деле все эти значения в каком-то смысле всё равно являются средними, но только в следствие несовершенства цифровой техники.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>
I>js он паттерном идёт, как раз для того, что бы отделить от остального мусора
I>Очевидно, что в логе не только JS, там результаты функций, снимки состояния и тд и тд.
Так я не понял, после "pir:" может идти не js код или нет? Если может, то весьма любопытно взглянуть на твоё решение задачки "выловить среди произвольного текста кусок js кода"...
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Пудозреваю, тебе самое время смотреть boost.phoenix
После выхода C++11 не вижу в нём особого смысла. Ну точнее формального говоря он конечно же есть — ленивые выражения на нём можно удобно конструировать. Но я подобным не увлекаюсь.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Можно и без монад — получатся автоматы на коленке с конской вложенностью, простынями из свичей и все это будет размазано по десяткам эвентов.
Конечно, но это если писать руками каждый раз. А если ты это всё скроешь в библиотечке за удобным интерфейсом? )
I>Эта хрень такая же страшная, как и boost.phoenix.
Внутри — возможно. А снаружи вроде как весьма удобно всё.
I>Все такие возможности очень актуальны, ибо в С++ возможностей для интеграции около нуля. Именно по этой причине для интеграции берут более другой язык — JS, Python, Lua и тд вплоть до С# или Джавы, не гнушаясь даже vbs.
Это ты вообще о чём? Что за интеграция? )
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я чет не заметил, в хаскеле одна прозрачная строчка а у тебя только первяс строчка, что из темплейтов, и уже втрое длиннее.
Хы, ну так "красоту" синтаксиса плюсов я защищать не собираюсь. ))) И особенно шаблоны с лямбдами. ))) Но смысловые части в C++ коде и в Хаскель коде тут абсолютно идентичные.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А DO-сахар для монад реализуются ровно в сорок строк без всякого Phoenix'а: EP>...
Красиво. Естественно это ни к чему в языках типа C++, где просто функция является аналогом do-сахара. Но хорошо демонстрирует преимущества наличия в языке средств метапрограммирования — если надо, то можно сделать почти всё что угодно.
P.S. Там в операторе >>= для optional мелкая недоработка есть, но она к сути дела никакого отношения не имеет. )
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
alex_public wrote:
> Кстати, вот на таких примерах (когда строим полноценную AST) не видны > некоторые удобнейшие (на мой вкус) возможности использования Спирита. > Например такая int_[([](const int& n){cout<<n<<endl;})] % ',' штука > не просто задаёт список интов разделённых запятой, но и сразу же > пишется реакция на распознанное значение.
С этим был подводный камень, что если составное rule не сматчилось до
конца, то action у составляющих всёравно срабатывает. Сейчас уже не в
курсе как с этим.
Здравствуйте, alex_public, Вы писали:
_>Красиво. Естественно это ни к чему в языках типа C++, где просто функция является аналогом do-сахара.
Да — самые распространённые монады (или альтернативы) уже есть в языке/библиотеках. Реального практического применения я пока ещё не придумал.
_>P.S. Там в операторе >>= для optional мелкая недоработка есть, но она к сути дела никакого отношения не имеет. )
Вижу, там нужен другой тип для Nothing.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, meadow_meal, Вы писали:
_>Если бы processEventOrFail не имела побочных эффектов (в данном случае кроме возврата исключения), этот код был бы удовлетворителен. Если язык не позволяет тем или иным способом контролировать эффекты, мы будем выкручиваться как-то так (код по прежнему очень псевдо):
_>
_>что уже сложнее, при этом способа гарантировать отсутствие эффектов в processEventOrFail у нас по прежнему нет.
Это всё понятно. Но я вообще то как раз и спрашивал, а какой уже у нас будет тут код на языке позволяющем контроль эффектов? В чём будет его преимущество над кодом выше и т.п...
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Можно и без монад — получатся автоматы на коленке с конской вложенностью, простынями из свичей и все это будет размазано по десяткам эвентов.
_>Конечно, но это если писать руками каждый раз. А если ты это всё скроешь в библиотечке за удобным интерфейсом? )
Всё равно два варианта которые я показал.
I>>Все такие возможности очень актуальны, ибо в С++ возможностей для интеграции около нуля. Именно по этой причине для интеграции берут более другой язык — JS, Python, Lua и тд вплоть до С# или Джавы, не гнушаясь даже vbs.
_>Это ты вообще о чём? Что за интеграция? )
Здравствуйте, alex_public, Вы писали:
I>>js он паттерном идёт, как раз для того, что бы отделить от остального мусора
I>>Очевидно, что в логе не только JS, там результаты функций, снимки состояния и тд и тд.
_>Так я не понял, после "pir:" может идти не js код или нет? Если может, то весьма любопытно взглянуть на твоё решение задачки "выловить среди произвольного текста кусок js кода"...
Не среди произвольного текста, определить, удовлетворяет ли текст внутри блока паттерну или нет. Если да, то взять имя функции
Это не рокет саенс, когда ты проверяешь regex.match("ля ля ля") то делаешь ровно то же. Разница только в том, что
1. у меня язык не является регулярным
2. парсер реактивный
в остальном нет никакой разницы
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>С++ не умеет те операторы, которые нужны для БНФ или РБНФ. I>>то есть придется эмулировать все подряд, например следование придется пилить явно, скобки и прочую вешь так же придется эмулировать, т.е. пилить явно.
_>Ужас то какой. )))
Да не, просто отстой, ничего серьёзного.
I>>Вот смотри, твой спирит, я даже не знаю, не то смеяться, не то плакать. I>>...
_>Кстати, вот на таких примерах (когда строим полноценную AST) не видны некоторые удобнейшие (на мой вкус) возможности использования Спирита. Например такая int_[([](const int& n){cout<<n<<endl;})] % ',' штука не просто задаёт список интов разделённых запятой, но и сразу же пишется реакция на распознанное значение. Причём таких реакций может быть сколько угодно — хоть на каждый элемент грамматики или их группу. В итоге получается писать крайне краткие и быстрые парсеры для простых вещей.
Спасибо, капитан, а я то думал спирит просто парсит ради парсинга, а оказывается, он как все парсеры, даёт еще и результат парсинга обработать. Буду знать !
I>>вот BNF: I>>... _>А это на каком языке программирования написано?
Я ж сказал — на языке описания грамматик, по русски — БФН, переводится как форма Бэкуса-Наура
I>>А вот фокус — та же грамматика на комбинаторах I>>... I>>тут не всё, справа надо добавить .map(AST.ляляля), т.е. трансляцию в АСТ, количество кода не сильно изменится
_>Генерация AST — это ладно, это действительно не надо показывать (т.к. тогда ещё само AST определять надо). А вот где сам парсинг то? )
Там же, где и в спирите — унутре либы.
>В случае Спирита понятно, что парсинг всегда осуществляется ровно одним вызовом глобальной функции, которой передаётся строка и грамматика. А тут у нас что делать с этим списком переменных?
var stream = ... источник, т.е. эвент, стрим, короутина и тд и тд и тд
stream.parse(expr).on('next', function(ast){
...
});
_>Т.е. вот предположим нам надо не AST сгенерировать, а напечатать разобранное выражение в консоль (но с другим форматирование естественно). Как будет тогда выглядеть полный код на базе твоего варианта? Кстати, в случае Спирита это одна строчка будет...
Просто что бы распечатать надо добавить функцию, как ты хочешь печатать каждый узел, см мою линку, там именно этот пример
_>Ну а про разницу в скорости при определение грамматики во время копиляции или во время исполнения я даже особо упоминать не буду — про это по идее и так все помнят.
Когда спирит научится реактивный парсинг делать, тогда и сравним перформанс. А пока что сравнивать не с чем.
_>Хы, в таких задачах (где есть всё работает по определённым законам и можно точно предсказывать "будущее") вообще всё по другому делают. Про фильтр Калмана слышал? ) Кстати, как ты думаешь, там будет фигурировать нормальная скорость или средняя? )))
Ай, не гони. FRP, т.е. Functional Reactive появилось для
1. сложной анимации, которая управляется событиями
2. описания поведения роботов, опять же управление от событий
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Непонятно, как причина претензии лишает претензию смысла. Именно потому, что так происходит претензия и имеет смысл.
Потому как сделать компиляцию шаблона в коды процессора невозможно ни в каком языке. Максимум что мы можем, это сделать чтобы компилятор проверял корректность всех шаблонов, что встретились в исходниках. Но даже если забыть о том, сколько ненужной работы будет при этом делаться каждый раз, то всё равно это на мой взгляд ненормальная возможность, т.к. дело компилятора контролировать правильность скомпилированного кода, а не исходников.
_>>Совершенно верно. И как раз про это я спрашиваю уже очень давно и так ни разу и не получил ответа. Естественно про какие-то случаи из реальной практики, а не обобщённую теорию.. K>Я же говорю, как только разберем "ужасы" — так сразу.
Вопрос о примере загадочной пользы от особенностей реализации IO/ST Хаскеля прозвучал очень давно, но так и не было ответа, а только отмазки. Такое впечатление, что мы тут слушаем в основном рассуждения теоретика...
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Кроме того, уже известно из опыта, что обсуждать конкретный код и указывать в чем проблемы вы не станете. K>Понятно, что такое последовательное нежелание переходить от общих заявлений к конкретике скорее всего свидетельствует о том, что никаких подтверждений своим тезисам в конкретных примерах вы даже и не рассчитываете найти, иначе с примеров и начали бы, а не с бла-бла-бла.
Вообще то в этой темке различных примеров кода от меня пожалуй больше чем от остальных участников. Причём это всё именно мои примеры, а не копипаста из интернета, как у некоторых теоретиков. Так что думаю со стороны прекрасно видно кто у нас тут просто болтает.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
I>На Си написаны сокеты, на JS это интегрируется пятью строчками в http сервер. Можно добавить еще пару строчек и будет простой клиент-серверный чат.
Ааа, понял. Сам люблю такое (на Питончике). Но только до тех пор, пока использую готовые чужие C/C++ модули. А если готового модуля нет, то писать свой обычно очень не охота (там всё же надо небольшой слой "лишнего" реализовать) — тогда проще всё приложение на плюсах сделать. Это естественно касается каких-то небольших внутренних задач. С софтом на продажу ситуация совсем другая по ряду причин, и Питончик (или даже Lua) там если и будет, то только как встроенный скриптовой язык в нативное приложение.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не среди произвольного текста, определить, удовлетворяет ли текст внутри блока паттерну или нет. Если да, то взять имя функции
Хы, раньше этого условия не было. Но случайно получилось, что тот мой код будет работать правильно и при нём. ))) Ну точнее его конечно можно обмануть подсунув что-то типа "function name(){ляляля не валидный js}", т.к. он не проверяет валидность всего js кода. Но думаю для анализатора логов это вполне подходящий уровень. )))
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>На Си написаны сокеты, на JS это интегрируется пятью строчками в http сервер. Можно добавить еще пару строчек и будет простой клиент-серверный чат.
_>Ааа, понял. Сам люблю такое (на Питончике). Но только до тех пор, пока использую готовые чужие C/C++ модули. А если готового модуля нет, то писать свой обычно очень не охота (там всё же надо небольшой слой "лишнего" реализовать) — тогда проще всё приложение на плюсах сделать. Это естественно касается каких-то небольших внутренних задач. С софтом на продажу ситуация совсем другая по ряду причин, и Питончик (или даже Lua) там если и будет, то только как встроенный скриптовой язык в нативное приложение.
С софтом на продажу все гораздо интереснее, там на таких вещах, как интеграция, вообще всё держится. И её быстрее и надёжнее писать на высокоуровневом языке.
Причина простая — на порядки легче сделать медленное быстрым, нежели некорректное корректным.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Не среди произвольного текста, определить, удовлетворяет ли текст внутри блока паттерну или нет. Если да, то взять имя функции
_>Хы, раньше этого условия не было.
Не было указания, что блоки могут быть вложенными, все остальное вполне понятно. Это я поторопился.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Спасибо, капитан, а я то думал спирит просто парсит ради парсинга, а оказывается, он как все парсеры, даёт еще и результат парсинга обработать. Буду знать !
Весь вопрос в том, в какой форме получать эти результаты...
I>Я ж сказал — на языке описания грамматик, по русски — БФН, переводится как форма Бэкуса-Наура
Вообще то принято сокращать как БНФ. Ну так это у нас не язык программирования, правильно? И с чего ты тогда сравниваешь запись грамматики на C++ с этим?
I>Просто что бы распечатать надо добавить функцию, как ты хочешь печатать каждый узел, см мою линку, там именно этот пример
Ага, я про это и спрашиваю... Значит твоя библиотечка выдаёт результат в виде некого дерева, правильно? Соответственно у меня вопросы:
1. Как нам там указывается тип узла (в смысле грамматики)?
2. В переменной какого типа (в смысле C#) хранится распознанное значение в узле?
3. Касательно нашего конкретного примера. У тебя там грамматика задаётся до уровня цифр (а не до уровня int'a как в примере spirit'а) — означает ли это, что конечными узлами дерева будут просто char'ы?
I>Ай, не гони. FRP, т.е. Functional Reactive появилось для I>1. сложной анимации, которая управляется событиями I>2. описания поведения роботов, опять же управление от событий
Хыхы, ну расскажи например про управление ADC с помощью FRP, если ты считаешь что оно актуально в этой области.
P.S. Если что, второй пункт (причём не только поведение, а вообще всё) — это как раз моя область. )))
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>С софтом на продажу все гораздо интереснее, там на таких вещах, как интеграция, вообще всё держится. И её быстрее и надёжнее писать на высокоуровневом языке.
Надёжнее? ) На языке без статической типизации? ) Нуну... )))
I>Причина простая — на порядки легче сделать медленное быстрым, нежели некорректное корректным.
Как раз на Питончике код скорее будет некорректным. И кстати скорость работы кода (если используем C/C++ модули) будет одинаковая. Главный плюс Питона (и ему подобных) — это скорость разработки/модификации.
Это в случае самого приложения на Питоне. А вот если использовать его в качестве встроенного в нормальное нативное приложение скриптового языка, то возникают уже совсем другие эффекты...
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>С софтом на продажу все гораздо интереснее, там на таких вещах, как интеграция, вообще всё держится. И её быстрее и надёжнее писать на высокоуровневом языке.
_>Надёжнее? ) На языке без статической типизации? ) Нуну... )))
Именно так — надёжнее. Кода меньше и этот аргумент не заборет никакая типизация.
I>>Причина простая — на порядки легче сделать медленное быстрым, нежели некорректное корректным.
_>Как раз на Питончике код скорее будет некорректным.
Надо полагать это у Питона фишка такая — баги в программах имплементить.
>И кстати скорость работы кода (если используем C/C++ модули) будет одинаковая. Главный плюс Питона (и ему подобных) — это скорость разработки/модификации.
И скорость и качество.
_>Это в случае самого приложения на Питоне. А вот если использовать его в качестве встроенного в нормальное нативное приложение скриптового языка, то возникают уже совсем другие эффекты...
А я что, предлагаю Питон во все приложения в качестве скриптинга встраивать ?
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я ж сказал — на языке описания грамматик, по русски — БФН, переводится как форма Бэкуса-Наура
_>Вообще то принято сокращать как БНФ. Ну так это у нас не язык программирования, правильно? И с чего ты тогда сравниваешь запись грамматики на C++ с этим?
Для того, что бы посчитать, сколько лишнего мусора в твоем коде. Кроме как сравнения с формализмом самой предметной области это сложно сделать.
_>1. Как нам там указывается тип узла (в смысле грамматики)?
AST нужен не просто так, а для конкретных вещей. Т.е. ты вводишь узел не там, где тебе надо кусочек грамматики описать, а там где тебе нужен этот узел
_>2. В переменной какого типа (в смысле C#) хранится распознанное значение в узле?
В переменной типа Result<TValue, TRest>
_>3. Касательно нашего конкретного примера. У тебя там грамматика задаётся до уровня цифр (а не до уровня int'a как в примере spirit'а) — означает ли это, что конечными узлами дерева будут просто char'ы?
Нет, разумеется. Какой смысл делать для символов?
I>>Ай, не гони. FRP, т.е. Functional Reactive появилось для I>>1. сложной анимации, которая управляется событиями I>>2. описания поведения роботов, опять же управление от событий
_>Хыхы, ну расскажи например про управление ADC с помощью FRP, если ты считаешь что оно актуально в этой области.
Я не знаю, что такое ADC
_>P.S. Если что, второй пункт (причём не только поведение, а вообще всё) — это как раз моя область. )))
Тем хуже для тебя. Если не помогли ни примерЫ, ни ссылки на работы, то напрашивается один вариант — тебе нравится только императивный код и ничего другого ты видеть не хочешь.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Потому как сделать компиляцию шаблона в коды процессора невозможно
Ну так надо делать не "шаблоны", а нормальный параметрический полиморфизм.
_>ни в каком языке.
Ну да, языков с "шаблонами", конечно, видимо-невидимо.
_>Максимум что мы можем, это сделать чтобы компилятор проверял корректность всех шаблонов, что встретились в исходниках.
Никакого реалистичного способа исправить "нетипизированность" шаблонов, разумеется, нет. Любое исправление просто сломает существующий код.
_>т.к. дело компилятора контролировать правильность скомпилированного кода, а не исходников.
Отличная шутка. Вообще-то норма, это когда проверяется именно исходники (бывает, что до рассахаривания), а потом уже генерируется код. Что вы в скомпилированном коде напроверяете? Там и типы-то обычно стерты. А для того, чтоб код генерировать их обычно надо знать. Не говоря уже о том, как вы будете восстанавливать положение ошибки типизации в исходниках по "скомпилированному коду".
_>Вопрос о примере загадочной пользы от особенностей реализации IO/ST Хаскеля прозвучал очень давно, но так и не было ответа, а только отмазки.
Просьба прокомментировать заявление про ужасы IO была тоже очень давно. Сами сопоставить примеры вы отказываетесь, от объяснений уклоняетесь, указать что именно не нравится в моем примере вы не хотите. Понятно, что если мы перейдем к следующему пункту, то к этому уже не вернемся, на что вы, похоже, и рассчитываете. У меня же все основания настаивать на подробном обсуждении этого вопроса есть: преимущества контроля за эффектами будут выглядеть как оправдания каким-то невнятным ужасам, которые я вроде-бы автоматически признаю, переходя к следующему вопросу. Такой вариант меня не устраивает. Кроме того, очевидно, что в обсуждении этой темы вы чувствуете себя неуверенно, а значит это направление для меня, как вашего оппонента, перспективно.
_>Такое впечатление, что мы тут слушаем в основном рассуждения теоретика...
Вы мне льстите. Я всего-навсего практик, до теоретика мне пока далеко.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Потому как сделать компиляцию шаблона в коды процессора невозможно K>Ну так надо делать не "шаблоны", а нормальный параметрический полиморфизм.
А как это поможет с компиляцией в коды процессора?
Через type-erasure, а-ля std::function? Не интересно, потому что медленно.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Так это всё в функциях apply. Они перегружены по типу второго аргумента. Для "голых" значений будет просто применение функции, для монад/функторов применение к внутреннему значению (вот промисы сюда попадают), для коллекций stl поэлементное применение и т.п.
Ну так вот эта функция apply — и есть монада. Точнее, чтобы она была монадой, надо к apply добавить функцию по конверсии "чистого" значения в "монадный" тип, и обеспечить выполнение монадических законов.
Всё. Спор выглядит странным — это всё равно как говорить, что в С++ никакого ООП нет, а есть только данные и методы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Этот код не работает. Как только в него приедет startSync и endSync по частям, ваш логгер облажается.
Представьте на секунду, что Analyze вызывается на каждый приехавший символ.
Это не говоря о том, что вы опять забыли про возможность параллельной работы нескольких потоков фильтрации.
В этом-то и сложность конверсии активного кода в реактивный — там, где активный код пишет "вынь да полож мне следующие 8 символов" (и встаёт в ожидании завершения IO, если у него исчерпался буфер), реактивный код должен уметь вернуть управление сразу же, как только отпроцессил входные данные.
Поэтому, например, корректных реактивных фильтров контента в ASP.NET приложениях в природе не встречается. Весь Analyze сводится к накапливанию аргументов в буфере, а сам анализ происходит по завершению.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то в этой темке различных примеров кода от меня пожалуй больше чем от остальных участников.
Никакого кода от вас по "ужасам IO" тут так и не появилось. По крайней мере я его не вижу.
_>Так что думаю со стороны прекрасно видно кто у нас тут просто болтает.
Ох, если бы вы хотя-бы болтали — это уже было бы неплохо. Даже высказывание каких-то общих соображений, даже без примеров кода или комментарии к уже опубликованному коду — это уже было бы существенным продвижением. Но вы ведь в основном подмигиваете и разным способом декларируете намерения подмигивать и дальше, ничего по существу не говоря.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Klapaucius, Вы писали:
K>>Кроме того, уже известно из опыта, что обсуждать конкретный код и указывать в чем проблемы вы не станете. K>>Понятно, что такое последовательное нежелание переходить от общих заявлений к конкретике скорее всего свидетельствует о том, что никаких подтверждений своим тезисам в конкретных примерах вы даже и не рассчитываете найти, иначе с примеров и начали бы, а не с бла-бла-бла.
_>Вообще то в этой темке различных примеров кода от меня пожалуй больше чем от остальных участников.
Я и вижу — примеры кода за тебя приходится приводить почему то мне
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Я вообще то говорил не про некие отвлечённые, а про вполне конкретные примеры из поставки wxWidgets. Т.е. идём в папку wxWidgets (она у меня уже много лет на компьютере), видим там папку samples и в ней ещё 86 папок с примерами на все случаи. Аналогично с wxHaskell, только там насколько я помню примеров намного меньше. Находим одинаковые и сравниваем код. Я это сделал когда-то, когда смотрел на Haskell вообще и получил вполне однозначные выводы. Сейчас прямо за секунду (а иначе лень) легко повторить это не могу, т.к. уже давно стёр и wxHaskell и сам Haskell у себя с компьютера, как не нужное. Но если кто-то хочет проверить мои слова, то алгоритм очень простой. Причём я указал на эти самые примеры в первом же своём сообщение на эту тему.
Прекрати сочинять, ты потратил уже несколько часов на тему, как тебе лень тратить больше секунды на этот вопрос
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Для того, что бы посчитать, сколько лишнего мусора в твоем коде. Кроме как сравнения с формализмом самой предметной области это сложно сделать.
Вообще то если поправить форматирование (БНФ у тебя в строчку, а в Спирите тоже самое на 4 раскидал) и не вставлять вещи типа namespace'ов (причём тут они к грамматике?), то выглядит практически одинаково.
I>AST нужен не просто так, а для конкретных вещей. Т.е. ты вводишь узел не там, где тебе надо кусочек грамматики описать, а там где тебе нужен этот узел
Можно и так. А можно и сразу.
I>Нет, разумеется. Какой смысл делать для символов?
Тогда я всё же не понял пока, тебе выдаётся дерево или что? Если дерево, то почему не целиком?
I>Я не знаю, что такое ADC
АЦП в смысле.
I>Тем хуже для тебя. Если не помогли ни примерЫ, ни ссылки на работы, то напрашивается один вариант — тебе нравится только императивный код и ничего другого ты видеть не хочешь.
Что-то ты совсем не понял меня. Ну я сейчас накидаю примерчик, так что поймёшь)
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну так надо делать не "шаблоны", а нормальный параметрический полиморфизм.
Чего чего? ) Это в смысле в рантайме?
K>Никакого реалистичного способа исправить "нетипизированность" шаблонов, разумеется, нет. Любое исправление просто сломает существующий код.
Речь шла не про плюсы, а про гипотетический язык с шаблонами, в котором компилятор их полностью проверяет.
K>Отличная шутка. Вообще-то норма, это когда проверяется именно исходники (бывает, что до рассахаривания), а потом уже генерируется код.
Правильно, исходник по которому генерируется код. И только он, а не некие абстрактные исходники. Для последнего существуют всяческие статические анализаторы. Хотя для обсуждаемой темы они естественно тоже не помогут.
K>Просьба прокомментировать заявление про ужасы IO была тоже очень давно. Сами сопоставить примеры вы отказываетесь, от объяснений уклоняетесь, указать что именно не нравится в моем примере вы не хотите.
Я не собираюсь повторяться в третий раз. Даже дважды уже было много. Тем более, что в ответ не услышал даже одного раза.
K>Понятно, что если мы перейдем к следующему пункту, то к этому уже не вернемся, на что вы, похоже, и рассчитываете. У меня же все основания настаивать на подробном обсуждении этого вопроса есть: преимущества контроля за эффектами будут выглядеть как оправдания каким-то невнятным ужасам, которые я вроде-бы автоматически признаю, переходя к следующему вопросу. Такой вариант меня не устраивает.
Здравствуйте, Sinclair, Вы писали:
S>Ну так вот эта функция apply — и есть монада. Точнее, чтобы она была монадой, надо к apply добавить функцию по конверсии "чистого" значения в "монадный" тип, и обеспечить выполнение монадических законов. S>Всё. Спор выглядит странным — это всё равно как говорить, что в С++ никакого ООП нет, а есть только данные и методы.
Ничего подобного. Это гораздо больше чем монада. И будет монадой только для определённого сочетания типа аргумента и функции. Т.е. могут быть варианты:
1. Функцию R(T) применяем к типу Т
2. Функцию M<R>(T) применяем к типу Т
3. Функцию R(M<T>) применяем к типу Т
4. Функцию M<R>(M<T>) применяем к типу Т
5. Функцию R(T) применяем к типу M<Т>
6. Функцию M<R>(T) применяем к типу M<Т>
7. Функцию R(M<T>) применяем к типу M<Т>
8. Функцию M<R>(M<T>) применяем к типу M<Т>
И всё это в одной концепции. Монадой же из всего этого будет только вариант 6. А будет ещё просто применение функций, фукторы и т.д. и т.п.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Когда спирит научится реактивный парсинг делать, тогда и сравним перформанс. А пока что сравнивать не с чем.
Собственно я тут подумал, а почему бы и нет! Ведь в той старой темке я тебе так подробно доказывал преимущества Boost.Coroutine на выдуманных тестовых примерах, а тут же на самом деле прямо идеальный реальный примерчик нарисовался. Причём он ещё и оптимальным по быстродействию может быть с учётом минимальных требований Спирита на входной итератор.
Значит смотри, вот пример обычной работы на Спирите:
string s="-333,-22,-1,0,1,22,333";
int sum=0, count=0;
parse(s.cbegin(), s.cend(), int_[([&](const int& n){cout<<n<<'\t'<<double(sum+=n)/++count<<endl;})]%',');
Теперь попробуем заставить Спирит работать реактивно. Для этого я написал (пара десятков строчек) некий класс rstring. Имея его, мы можем написать так:
Как видно, код самого парсера вообще не изменился. И естественно этот код выдаёт такой же результат как и первый вариант.
Ну что, покажешь аналоги этих примеров на базе тех монадных библиотечек? ) И тогда можем ещё и быстродействие сравнить (я поправлю примеры чтобы брали данные из файла и пришлю готовые бинарники), если рискнёшь конечно. )))
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Как и у любого языка с динамической типизацией) Их нельзя использовать в серьёзном проекте, не обкладывая при этом тоннами тестов.
Это сказки. В динамическом языке прежде всего код пишется проще, его намного меньше.
Теоретически, это достижимо и в С++, но на практике дл интеграции нужно специальное АПИ. Высокоуровневые вещи, внезапно, это вагоны темплейтов, конские иерархии и сложные макры, через которые очень трудно продираться. А вот аналогичное АПИ на динамичеком языке предельно простое. Вот мне непонятно, как работает pipe, открыл да посмотрел — смешное количество строчек кода. А в С++ только перчисление только темплейтов и скобочек будет раз в десять больше.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Этот код не работает. Как только в него приедет startSync и endSync по частям, ваш логгер облажается. S>Представьте на секунду, что Analyze вызывается на каждый приехавший символ.
Всё нормально там будет, строка накапливается в js. Т.е. если startSync и endSync приходят хоть по одному символу (но Analyze всё же вызывается построчно, т.е. в каждой строке по кусочку от startSync/endSync), то никаких проблем. Вот если весь Analyze вызывается для каждого символа (т.е. не по строкам, по которым там фильтрация осуществляется), то тогда действительно надо переделать.
S>В этом-то и сложность конверсии активного кода в реактивный — там, где активный код пишет "вынь да полож мне следующие 8 символов" (и встаёт в ожидании завершения IO, если у него исчерпался буфер), реактивный код должен уметь вернуть управление сразу же, как только отпроцессил входные данные.
S>Поэтому, например, корректных реактивных фильтров контента в ASP.NET приложениях в природе не встречается. Весь Analyze сводится к накапливанию аргументов в буфере, а сам анализ происходит по завершению.
Ну это проблемы исключительно ASP.NET. Как видно, достаточно универсальное решение делается на C++ всего в пару десятков строчек. )))
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Когда спирит научится реактивный парсинг делать, тогда и сравним перформанс. А пока что сравнивать не с чем. _>Собственно я тут подумал, а почему бы и нет! Ведь в той старой темке я тебе так подробно доказывал преимущества Boost.Coroutine на выдуманных тестовых примерах, а тут же на самом деле прямо идеальный реальный примерчик нарисовался.
Я думал вы договорились Boost.Coroutine не использовать, поэтому и не упоминал
А так да — на корутинах можно легко приделать реактивный парсинг к Boost.Spirit.
Вообще, stackful coroutines можно использовать для упрощения использования многих монад, например optional<T>/expected<T>/future<T>/generator<T>(которая в свою очередь эмулирует корутины)/etc. Буквально недавно это обсуждалось в C++ ISO Proposals.
Но такая техника применима не ко всем монадам. Например это неприменимо к монаде list<T>, потому что одно и то же продолжение может вызываться несколько раз, а для stackful coroutine такой фокус не прокатит (стэк изменяется, объекты деструктятся и т.п.). Грубо говоря нужен полноценный call/cc.
Я думаю для stackless coroutines таких ограничений нет — объекты-автоматы можно копировать и вызывать несколько раз для одного checkpoint'а.
_>Для этого я написал (пара десятков строчек) некий класс rstring.
В новой версии Boost.Coroutine есть интерфейс input/output итераторов. По идее должно быть достаточно boost::coroutines::coroutine<char>::pull_type::iterator + boost::spirit::make_default_multi_pass.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Я думал вы договорились Boost.Coroutine не использовать, поэтому и не упоминал EP>А так да — на корутинах можно легко приделать реактивный парсинг к Boost.Spirit.
Хы, не, просто у меня есть привычка не заявлять непроверенный код. А проверять лень было, поэтому я про короутины и не упоминал. Но как видишь, народ меня всё же "добил" своими рассказами о великой сложности задачи реактивного парсинга, так что я ненадолго отбросил лень и набросал код. )))
EP>Вообще, stackful coroutines можно использовать для упрощения использования многих монад, например optional<T>/expected<T>/future<T>/generator<T>(которая в свою очередь эмулирует корутины)/etc. Буквально недавно это обсуждалось в C++ ISO Proposals.
О, это отдельная интересная тема для обсуждения... Вообще C++ в интересном направление стал сейчас развиваеться.
Правда она несколько противоположна тому моему примеру. Я же в нём как бы наоборот использую короутины, чтобы реализовать реактивный парсинг без всяких явных монад.
EP>Но такая техника применима не ко всем монадам. Например это неприменимо к монаде list<T>, потому что одно и то же продолжение может вызываться несколько раз, а для stackful coroutine такой фокус не прокатит (стэк изменяется, объекты деструктятся и т.п.). Грубо говоря нужен полноценный call/cc. EP>Я думаю для stackless coroutines таких ограничений нет — объекты-автоматы можно копировать и вызывать несколько раз для одного checkpoint'а.
Только их ещё конструировать надо самому. )
EP>В новой версии Boost.Coroutine есть интерфейс input/output итераторов. По идее должно быть достаточно boost::coroutines::coroutine<char>::pull_type::iterator + boost::spirit::make_default_multi_pass.
О, значит в новой версии может получится вообще автоматом? ) Позитивно. А у меня 1.53 стоит и я при выходе новых как-то не заметил, что короутины поправили. Надо будет посмотреть и возможно обновиться.
Но в любом случае даже свой код очень простой и короткий вышел (я использовал ещё boost::iterator_facade).
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то если поправить форматирование (БНФ у тебя в строчку, а в Спирите тоже самое на 4 раскидал) и не вставлять вещи типа namespace'ов (причём тут они к грамматике?), то выглядит практически одинаково.
Нет, не одинаково. В спирите как видно, раза в три длинее и мутная нотация, мне например, было крайне сложно понять, что к чему
I>>AST нужен не просто так, а для конкретных вещей. Т.е. ты вводишь узел не там, где тебе надо кусочек грамматики описать, а там где тебе нужен этот узел
_>Можно и так. А можно и сразу.
Это экономия на спичках. Никакого профита это не
I>>Нет, разумеется. Какой смысл делать для символов?
_>Тогда я всё же не понял пока, тебе выдаётся дерево или что? Если дерево, то почему не целиком?
Дизайн в библиотеке я реализовал как мне было удобнее. В конечном итоге парсер может возвратить дерево, если его комбинаторы смапить на AST
I>>Я не знаю, что такое ADC
_>АЦП в смысле.
аналого-цифровой преобразователь ?
I>>Тем хуже для тебя. Если не помогли ни примерЫ, ни ссылки на работы, то напрашивается один вариант — тебе нравится только императивный код и ничего другого ты видеть не хочешь.
_>Что-то ты совсем не понял меня. Ну я сейчас накидаю примерчик, так что поймёшь)
Да-да, работай, а то кроме нерабочего Analyse от тебя было около одного нормального примера.
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Хы, не, просто у меня есть привычка не заявлять непроверенный код. А проверять лень было, поэтому я про короутины и не упоминал. Но как видишь, народ меня всё же "добил" своими рассказами о великой сложности задачи реактивного парсинга, так что я ненадолго отбросил лень и набросал код. )))
Тебе про сложность никто ничего не говорил. Говорили про пользу и я просил пример для сравнения.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Всё нормально там будет, строка накапливается в js. Т.е. если startSync и endSync приходят хоть по одному символу (но Analyze всё же вызывается построчно, т.е. в каждой строке по кусочку от startSync/endSync), то никаких проблем. Вот если весь Analyze вызывается для каждого символа (т.е. не по строкам, по которым там фильтрация осуществляется), то тогда действительно надо переделать.
Надо переделывать, это ж очевидно, и я на это указываю уже хрен знает сколько раз.
S>>В этом-то и сложность конверсии активного кода в реактивный — там, где активный код пишет "вынь да полож мне следующие 8 символов" (и встаёт в ожидании завершения IO, если у него исчерпался буфер), реактивный код должен уметь вернуть управление сразу же, как только отпроцессил входные данные.
_>О да, дико сложно. ))) http://www.rsdn.ru/forum/philosophy/5424925
При чем здесь сложность ? Ты раз за разом выдавал неправильное императивное решение и настаивал что оно работает.
Если ты таки решил прикрутить короутины, то всё в порядке. Правда теперь не ясно, почему ты сопротивлялся столько дней.
Я ожидал что ты сразу переделаешь analyse на короутины, но мне уже надоело. Тебе теперь должно быть понятно, как императивно делается реактивный парсинг.
S>>Поэтому, например, корректных реактивных фильтров контента в ASP.NET приложениях в природе не встречается. Весь Analyze сводится к накапливанию аргументов в буфере, а сам анализ происходит по завершению.
_>Ну это проблемы исключительно ASP.NET. Как видно, достаточно универсальное решение делается на C++ всего в пару десятков строчек. )))
Ну сколько можно — еще одна попытка контекстно-свободный язык парсить регэкспом
Любой реактивный парсинг сожрёт ресурсы и выдаст фильтрованый результат только по окончании. И это не важно, с++ или асп.нет или yesod(хаскель).
Итого — не считая твоих попыток свести контекстно-свободную грамматику к регулярной принципиальной разницы не вижу.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
EP>Вообще, stackful coroutines можно использовать для упрощения использования многих монад, например optional<T>/expected<T>/future<T>/generator<T>(которая в свою очередь эмулирует корутины)/etc. Буквально недавно это обсуждалось в C++ ISO Proposals. EP>Но такая техника применима не ко всем монадам. Например это неприменимо к монаде list<T>, потому что одно и то же продолжение может вызываться несколько раз, а для stackful coroutine такой фокус не прокатит (стэк изменяется, объекты деструктятся и т.п.). Грубо говоря нужен полноценный call/cc. EP>Я думаю для stackless coroutines таких ограничений нет — объекты-автоматы можно копировать и вызывать несколько раз для одного checkpoint'а.
А я помню, как ты рассказывал что stackfull круче чем яйца, а оказыватся это совершенно разные механизмы и области применения у них всего лишь пересекаются
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Теперь попробуем заставить Спирит работать реактивно. Для этого я написал (пара десятков строчек) некий класс rstring. Имея его, мы можем написать так: _>
_>Как видно, код самого парсера вообще не изменился. И естественно этот код выдаёт такой же результат как и первый вариант.
_>Ну что, покажешь аналоги этих примеров на базе тех монадных библиотечек? ) И тогда можем ещё и быстродействие сравнить (я поправлю примеры чтобы брали данные из файла и пришлю готовые бинарники), если рискнёшь конечно. )))
"Те" монандные библиотеки именно так и сделаны — через короутины. в js правда приходится туго, короутины толко в следующем стандарте, а сейчас эмуляция оных.
Что касается сравнения производительности, то снова выходит сравнение нативного компилера с джытом. Это не интересно, для этого незачем городить парсеры.
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А я помню, как ты рассказывал что stackfull круче чем яйца,
Так ведь действительно мощный механизм И кстати — корутины могут мигрировать из потока в поток (был когда-то вопрос на эту тему).
I>а оказыватся это совершенно разные механизмы и области применения у них всего лишь пересекаются
По сравнению с чем? С монадами? Ну да — но мы их и не сравнивали.
Если же ты про C# await — насколько я вижу, он тут ничем не поможет. У генерированных автоматов ведь нет value semantics?
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
EP>>Я думал вы договорились Boost.Coroutine не использовать, поэтому и не упоминал EP>>А так да — на корутинах можно легко приделать реактивный парсинг к Boost.Spirit. _>Хы, не, просто у меня есть привычка не заявлять непроверенный код. А проверять лень было, поэтому я про короутины и не упоминал. Но как видишь, народ меня всё же "добил" своими рассказами о великой сложности задачи реактивного парсинга, так что я ненадолго отбросил лень и набросал код. )))
А, тогда понятно
_>О, это отдельная интересная тема для обсуждения... Вообще C++ в интересном направление стал сейчас развиваеться. _>Правда она несколько противоположна тому моему примеру. Я же в нём как бы наоборот использую короутины, чтобы реализовать реактивный парсинг без всяких явных монад.
Это было неофициальное обсуждение. Я думаю вряд ли в C++ добавят сахар для монад (возможно будет мощный препроцессор, на котором этот сахар легко реализуется (и не только он)).
EP>>Я думаю для stackless coroutines таких ограничений нет — объекты-автоматы можно копировать и вызывать несколько раз для одного checkpoint'а. _>Только их ещё конструировать надо самому. )
Я в общем про stackless. А конструировать их можно разными способами: вручную, макросами, внешним генератором и т.п.
EP>>В новой версии Boost.Coroutine есть интерфейс input/output итераторов. По идее должно быть достаточно boost::coroutines::coroutine<char>::pull_type::iterator + boost::spirit::make_default_multi_pass.
_>О, значит в новой версии может получится вообще автоматом? ) Позитивно.
Здравствуйте, alex_public, Вы писали:
_>Теперь попробуем заставить Спирит работать реактивно. Для этого я написал (пара десятков строчек) некий класс rstring.
А можно показать исходник этого "некоего класса rstring"?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Да, такое можно сделать, но тогда опять же непонятно зачем нам именно такие данные. Они же будут приходить в очень странной последовательности, по отношению к оригинальной структуре. Например для <a></a><b><c><c/></b> придёт как a, c, b. И зачем нам оно такое?
Нам нужны не "именно такие" данные, а возможность заставить XPath Expression работать по неполным данным, а также не держать в памяти весь буфер.
Один пример — выражение типа //c[@value>1] будет мне возвращать нужные мне теги по мере поступления, а не после /b. Что может быть крайне ценным при, скажем, обработке XSLT.
Другой пример — если я считаю некое выражение, скажем sum(//c[@class="red"]/value). Мне для этого подсчёта, вообще говоря, нахрен не упал весь документ одновременно. Отпарсили — прибавили — выкинули. Нужно понимать, что если я тяну документ по сети, и отдаю результат тоже в сеть, то большую часть времени мой "поток" спит. Когда я уже избавился от нативных потоков, и эта сплюшка не отъедает 1мб стека от адресного пространства моего процесса во время своего сна, то боттлнеком становятся вот такие "запоздало-реактивные" реализации. "Накапливаемый" документ отъедает непозволительно большую память на непозволительно большое время. В приведённом примере мне нужно, грубо говоря, хранить три строчки "состояния" парсера, а всё остальное выкидывать сразу после прочтения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И всё это в одной концепции. Монадой же из всего этого будет только вариант 6. А будет ещё просто применение функций, фукторы и т.д. и т.п.
Я, наверное, чего-то не понял. Монада задаёт правила комбинирования функций. Поэтому из "одной концепции" получается весь зоопарк, включая M<R>(M<T>) и всякие F(G()).
Вот, скажем, для Nullable<T> есть встроенные в язык C# правила для лифтинга операторов. А для пользовательских функций "правил лифтинга" нет. И нет никакой возможности описать "правила лифтинга" для своего типа Arbitrary<T> так, чтобы операторы и функции, определённые для T, автоматически конвертировались в операторы и функции, определённые для Arbitrary<T>. Нет средств выразить это в языке. И я никак не вижу способа добиться аналогичного результата в С++. Допустим, Петя определил тип optional<T> очевидным образом, предполагая использовать его для value-типов вроде int, double, и так далее.
Как мне сделать так, чтобы этот тип корректно работал со всеми, в том числе ещё не написанными, типами?
Вот Вася определил тип big_integer.
Как мне писать программу с использованием optional<big_integer>?
Для big_integer Вася определил множество операторов и функций.
Как Пете описать тип optional<T>, чтобы я, прикладной программист, не должен был писать каждый раз
optional<big_integer> e = a.has_value() ? exp(a.value()) : optional<big_integer>::null;
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Теоретически, это достижимо и в С++, но на практике дл интеграции нужно специальное АПИ. Высокоуровневые вещи, внезапно, это вагоны темплейтов, конские иерархии и сложные макры, через которые очень трудно продираться. А вот аналогичное АПИ на динамичеком языке предельно простое. Вот мне непонятно, как работает pipe, открыл да посмотрел — смешное количество строчек кода. А в С++ только перчисление только темплейтов и скобочек будет раз в десять больше.
И да и нет. Смотря о чём говорить. Если говорить о смысловой части (разбиение задачи на функции, классы, алгоритмы вызовов и т.п.), то оно будет одинаковым на любом языке в исполнение одного программиста. А вот количество букв для записи этих классов и т.п. естественно разное. И в C++ оно безусловно больше, чем в обычных языках с динамической типизацией. Но этот объём является ценой за то, что значительная часть ошибок отсеивается ещё на этапе компиляции. Или даже вообще не появляется, благодаря возможностям современных IDE для подобных языков.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нет, не одинаково. В спирите как видно, раза в три длинее и мутная нотация, мне например, было крайне сложно понять, что к чему
Ну давай запишем в одинаковом форматирование и без лишнего обрамление (ты бы ещё инклуды учёл), а только саму грамматику по честному.
auto const expr_def=term>>*((char_('+')>>term)|(char_('-')>>term));
auto const term_def=factor>>*((char_('*')>>factor)|(char_('/')>>factor));
auto const factor_def=uint_|'('>>expr>>')'|(char_('-')>>factor)|(char_('+')>>factor);
Что, прямо такая ужасная разница? )))
I>Это экономия на спичках. Никакого профита это не
Дело как раз не в экономии, а в другом. Хотя и с производительностью есть нюанс, т.к. при варианте Спирита можно вообще не выделять никакой памяти в процессе парсинга. Тут дело в том, что как раз при таком варианте происходит реально реактивный парсинг. Т.е. результаты выдаются сразу после прихода данных. Например, мы можем задать какой-то сложный шаблон и при этом получать результаты при поступление только части данных для него.
I>Дизайн в библиотеке я реализовал как мне было удобнее. В конечном итоге парсер может возвратить дерево, если его комбинаторы смапить на AST
Да не надо мне дерево. Ты мне покажи как мне написать функцию, которая будет хотя бы просто печатать разобранные данные. Вот для того же самого примера калькулятора пускай напечатает операторы другим цветом, а числа выведет в формате с плавающей точкой. А то у тебя пока все примеры были такие, что выдавали результат парсинга в виде некого одного предсказуемого результата (строки или числа там). А вот в каком виде мы получаем результат в случае если там некое выражение, состоящие из разных типов пока не понятно.
I>аналого-цифровой преобразователь ?
Ну да, это основной источник внешней информации вида непрерывной последовательности отсчётов в робототехнике и вообще автоматике. Соответственно, если твои тезисы верны, как раз работу с этим должны были первым делом перевести на всякие там реактивные монады и т.п. Однако я что-то ничего подобного не видел, кругом сплошные тупые императивные фильтры и анализаторы. Ну точнее я слышал краем уха про одну крайне сомнительную попытку (и даже запомнил название, т.к. оно другую библиотечку напоминало), но оно так и осталось теоретической забавой, которую никто и нигде применять не собирается. Вот оно https://www.cs.drexel.edu/~mainland/projects/flask/. А вообще, я прекрасно знаю как делаются подобные вещи сейчас в индустрии, и про функциональное программирование там народ обычно даже не слышал.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>При чем здесь сложность ? Ты раз за разом выдавал неправильное императивное решение и настаивал что оно работает.
Конечно работает. Если посмотрим на первый пример здесь на тему реактивных монадных парсеров (тот самый, что с заглавной страницы библиотечки Rxx), то я написал его ручной императивный аналог, работающий в реактивном режиме, меньше чем за минуту. Причём он оказался намного короче и намного проще для понимания. И вроде как ни у кого нет никаких претензий к его работе (придирки на счёт глобальной функции не принимаются — это тестовый пример и мы всегда можем одним движением заменить на объект, если надо завести много параллельных парсеров).
Но при этом я не раз повторял, что писать подобный код имеет смысл только в простых случаях (правда в этой темке что-то слишком часто попадались именно они). А в сложных следует использовать какие-то готовые библиотеки. Например конечные автоматы для каких-то событий или же Спирит, если говорим о тексте и т.п. Я надеюсь третьего (или уже четвёртого?) повтора этого моего тезиса будет достаточно, чтобы ты не "забыл" его снова? )
I>Если ты таки решил прикрутить короутины, то всё в порядке. Правда теперь не ясно, почему ты сопротивлялся столько дней.
Короутины+Спирит — это на самом деле совсем не оптимальное решение, т.к. там при работе на пустом месте происходит потеря производительности из-за переключений контекста. Оптимальное решение — это переписать Спирит под реактивный стиль. Но пока такого нет (а я точно не собираюсь делать подобное ради форумного спора ), то можно удовлетвориться и таким решением. Так сказать разумный компромисс между эффективностью кода и временем разработки.
I>Я ожидал что ты сразу переделаешь analyse на короутины, но мне уже надоело. Тебе теперь должно быть понятно, как императивно делается реактивный парсинг.
Короутины в Analyze? Зачем они там? Они могут понадобиться только если мы хотим заставить готовый библиотечный код (который мы не можем или не хотим менять) работать в асинхронном режиме. А если в Analyze только мой код, то больше ничего и не требуется.
I>Любой реактивный парсинг сожрёт ресурсы и выдаст фильтрованый результат только по окончании. И это не важно, с++ или асп.нет или yesod(хаскель).
С чего бы это? Ты не видел примеры в этой темке? )
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Что касается сравнения производительности, то снова выходит сравнение нативного компилера с джытом. Это не интересно, для этого незачем городить парсеры.
Насчёт сравнения производительности согласен что не интересно. Хотя дело там совсем не в разных компиляторах, а в принципиально разных подходах к построению парсера.
А вот как насчёт сравнения объёма кода? Те два мои примера (обычный и реактивный) — это считай полностью законченный код. Т.е. туда добавляется обрамляющая функция main, добавляются инсклуды и всё, можно компилировать. Ты можешь показать такие же полноценные примеры реализующие в точности туже самую функциональность с использованием всех этих монадных библиотечек и т.п.? ) Оценим тогда удобство подходов для пользователя библиотечек...
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Это было неофициальное обсуждение. Я думаю вряд ли в C++ добавят сахар для монад (возможно будет мощный препроцессор, на котором этот сахар легко реализуется (и не только он)).
Я к тому, что раньше подобные рассуждения C++'ников выглядели бы очень необычно. Сейчас это уже так, практически норма. )
А что за препроцессор? Что-то не слышал планов про изменения в этой области...
EP>Да, вот так: EP>
О, совсем классно. Явно надо ставить 1.55. Правда тут есть разница с моим вариантом. Точнее с моим вариантом, показанным на форуме. В реальности это был мой второй вариант, а первый работал технически в точности как и код выше. Т.е. ел char'ы и делал переключения контекста на каждый следующий символ. Мне это показалось как-то совсем не оптимально и я написал второй вариант, который ест string'и и делает переключения контекста только при новой порции данных, а не на каждый символ.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>А можно показать исходник этого "некоего класса rstring"?
Да без проблем. Только вот наверное уже нет особого смысла, т.к. это я использовал устаревшую (1.53) версию Boost'a, а в последней (1.55) версии уже прямо это всё готовое есть. Вот здесь http://www.rsdn.ru/forum/philosophy/5425281
Здравствуйте, Sinclair, Вы писали:
S>Нам нужны не "именно такие" данные, а возможность заставить XPath Expression работать по неполным данным, а также не держать в памяти весь буфер. S>Один пример — выражение типа //c[@value>1] будет мне возвращать нужные мне теги по мере поступления, а не после /b. Что может быть крайне ценным при, скажем, обработке XSLT. S>Другой пример — если я считаю некое выражение, скажем sum(//c[@class="red"]/value). Мне для этого подсчёта, вообще говоря, нахрен не упал весь документ одновременно. Отпарсили — прибавили — выкинули. Нужно понимать, что если я тяну документ по сети, и отдаю результат тоже в сеть, то большую часть времени мой "поток" спит. Когда я уже избавился от нативных потоков, и эта сплюшка не отъедает 1мб стека от адресного пространства моего процесса во время своего сна, то боттлнеком становятся вот такие "запоздало-реактивные" реализации. "Накапливаемый" документ отъедает непозволительно большую память на непозволительно большое время. В приведённом примере мне нужно, грубо говоря, хранить три строчки "состояния" парсера, а всё остальное выкидывать сразу после прочтения.
Ааа, понял о чём речь, как раз в стиле Спирита задачки. ))) Согласен, полезная и вполне реализуемая вещь. Причём реализуемая тривиально прямо сейчас, если отказаться от идеи написания полноценного xml парсера, а реализовать решения конкретных задачек (типа двух примеров выше). Т.к. для конкретных задач подойдут простейшие методы работы с текстом, а не полноценный разбор в AST. Ну а если требуется универсальное решение, то действительно надо писать свой реактивный xml парсер. Кстати, для упрощённого xml это делается на Спирите (который, как мы видели, может работать реактивно во всех смыслах) в несколько строк. Ну а для полноценного конечно же лучше писать с нуля.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Я, наверное, чего-то не понял. Монада задаёт правила комбинирования функций. Поэтому из "одной концепции" получается весь зоопарк, включая M<R>(M<T>) и всякие F(G()).
Не любых функций. Монада задаётся (ну в основном, остальное мелочи) с помощью определения оператора >>= (например) вида "M<R> operator >>= (M<T>, M<R>(T));". Т.е. этот оператор позволяет функции вида M<R>(T) подействовать на M<T> и вернуть M<R>. И всё, точка. То, что путём некоторых манипуляций (тот самый лифтинг) мы можем из этого ещё и суметь подействовать на M<T> функцией вида R(T) и получить M<R>, означает всего лишь констатацию того факта, что любая монада является ещё и функтором. Однако подобное далеко не везде и например в обратную сторону это не верно. Т.е. если мы определим например некоторую сущность F через оператор вида "F<R> operator >>= (F<T>, R(T));", т.е. позволяющему действовать функции R(T) на F<T> и получать F<R> (кстати, именно такой сценарий больше всего наблюдался тут в агитации полезности монад), то из этого у нас уже не получится научиться действовать на F<T> функциями вида F<R>(T), так что монадой это не будет. Но применять функции R(T) к F<T> мы будем спокойно, причём без всякого лифтинга.
Абзац выше — это были как раз классические функциональные игры, хотя и записанные на C++. А вот тот мой пример с Apply — это наоборот был тупо императивный подход. Но при этом он работает не только с функторами или монадами, но и с чем угодно. Хоть с голыми значениями или коллекциями stl. А в сочетание с шаблонной магией C++ это ещё и позволяет писать сложный обобщённый алгоримы, работающий без исправления кода для всех этих разных сущностей одновременно. Причём без капли накладных расходов.
S>Вот, скажем, для Nullable<T> есть встроенные в язык C# правила для лифтинга операторов. А для пользовательских функций "правил лифтинга" нет. И нет никакой возможности описать "правила лифтинга" для своего типа Arbitrary<T> так, чтобы операторы и функции, определённые для T, автоматически конвертировались в операторы и функции, определённые для Arbitrary<T>. Нет средств выразить это в языке. И я никак не вижу способа добиться аналогичного результата в С++.
Я лично пока не понял, а в чём собственно проблема то?
S> Допустим, Петя определил тип optional<T> очевидным образом, предполагая использовать его для S>value-типов вроде int, double, и так далее. S>Как мне сделать так, чтобы этот тип корректно работал со всеми, в том числе ещё не написанными, типами? S>Вот Вася определил тип big_integer. S>Как мне писать программу с использованием optional<big_integer>? S>Для big_integer Вася определил множество операторов и функций. S>Как Пете описать тип optional<T>, чтобы я, прикладной программист, не должен был писать каждый раз S>
S>optional<big_integer> e = a.has_value() ? exp(a.value()) : optional<big_integer>::null;
S>
Ну так а чем функция типа Apply не подходит то? Что-то типа
template<typename R, typename T> auto Apply(optional<T> t, R (*f)(T)) {return t?f(*t):optional<R>();}
Пояснение: в boost'е у optional переопределён оператор bool (возвращает has_value()) и * (возвращает value()) — в таком варианте код записывается короче, но разницы в смысле нет.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И да и нет. Смотря о чём говорить. Если говорить о смысловой части (разбиение задачи на функции, классы, алгоритмы вызовов и т.п.), то оно будет одинаковым на любом языке в исполнение одного программиста.
Очевидно — нет. Язык очень сильно определяет это разбиение.
>А вот количество букв для записи этих классов и т.п. естественно разное. И в C++ оно безусловно больше, чем в обычных языках с динамической типизацией. Но этот объём является ценой за то, что значительная часть ошибок отсеивается ещё на этапе компиляции. Или даже вообще не появляется, благодаря возможностям современных IDE для подобных языков.
Это большей частью сказки. Если сравнить С++ с гипотетическим С++, в котором все возможности ровно такие же, но нет типизации, то конечно нынешний зарулит гипотетический в минуса.
Реальность примерно такая — на динамических языках как правило надо кода гнать в разы меньше, а иногда даже на порядки. Собтсвенно смотри сам — спирит сливает даже самопалу на JS.
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Нет, не одинаково. В спирите как видно, раза в три длинее и мутная нотация, мне например, было крайне сложно понять, что к чему
_>Ну давай запишем в одинаковом форматирование и без лишнего обрамление (ты бы ещё инклуды учёл), а только саму грамматику по честному.
Записывать нужно так, что бы было легко прочесть, а не что бы строчек было меньше. Эдак окажется что все программы на всех языках будут в одну строку.
_>БНФ: _>
Ты еще в одну строку все загони. В том виде как ты показал, грамматика нечитаемая.
_>Дело как раз не в экономии, а в другом. Хотя и с производительностью есть нюанс, т.к. при варианте Спирита можно вообще не выделять никакой памяти в процессе парсинга.
Это открытие претендует на нобелевку
>Тут дело в том, что как раз при таком варианте происходит реально реактивный парсинг. Т.е. результаты выдаются сразу после прихода данных. Например, мы можем задать какой-то сложный шаблон и при этом получать результаты при поступление только части данных для него.
Шо, в самом деле ? А я то думал это в любом реактивном парсере можно
I>>Дизайн в библиотеке я реализовал как мне было удобнее. В конечном итоге парсер может возвратить дерево, если его комбинаторы смапить на AST
_>Да не надо мне дерево. Ты мне покажи как мне написать функцию, которая будет хотя бы просто печатать разобранные данные.
Я же давал ссылку — там именно такая функция и приведена. Что еще надо, если та не подходит ?
>Вот для того же самого примера калькулятора пускай напечатает операторы другим цветом, а числа выведет в формате с плавающей точкой. А то у тебя пока все примеры были такие, что выдавали результат парсинга в виде некого одного предсказуемого результата (строки или числа там). А вот в каком виде мы получаем результат в случае если там некое выражение, состоящие из разных типов пока не понятно.
Будешь смеяться, я и это показл. Парсер возвращает пару значение-остаток. Для числа значением будет число, представь себе весь ужас. Для скобки будет скобка и тд и тд.
I>>аналого-цифровой преобразователь ?
_>Ну да, это основной источник внешней информации вида непрерывной последовательности отсчётов в робототехнике и вообще автоматике. ?
Ты наверное путаешь обработку сигналов и описание поведения и реакции на события. Первое оно полностью про ЦОС, включая АЦП и тд. А вот второе к этому никак не относится.
Если тебе надо управлять заслонкой котла в зависимости от показаний скажем десятка датчиков основываясь не только на мгновенных значениях датчиков, но и на предыстории, АЦП к этой задаче никакого отношения не имеет, ибо в задаче самая сложная часть это реакция системы.
>Соответственно, если твои тезисы верны, как раз работу с этим должны были первым делом перевести на всякие там реактивные монады и т.п.
С железом всё крайне консервативно. Типичный железячник пишет такие простыни императивного кода, которые никто, кроме него, прочесть не может. Единственное достоинство — оно как то работает.
FRP нужно для описания поведения и реакции на события некоторой системы. Раз в робототехнике, по твоим словам, это не надо, ну значит робототехника до этого еще не доросла.
вот два нормальных примера, которые еще раз внятно объясняют как это можно использовать
Здравствуйте, alex_public, Вы писали:
I>>Что касается сравнения производительности, то снова выходит сравнение нативного компилера с джытом. Это не интересно, для этого незачем городить парсеры.
_>Насчёт сравнения производительности согласен что не интересно. Хотя дело там совсем не в разных компиляторах, а в принципиально разных подходах к построению парсера.
Подход как раз именно один и тот же, это recursive descent. И я даже пудозреваю, что спирит это тоже реализация через комбинаторы парсеров, только в компайлтайм.
_>А вот как насчёт сравнения объёма кода? Те два мои примера (обычный и реактивный) — это считай полностью законченный код.
Нет там ничего законченого. Если сравнивать, то по всем аспектам, т.е. параллельно несколько ниток в потоке и нескольк потоков, шоб интереснее было.
>Т.е. туда добавляется обрамляющая функция main, добавляются инсклуды и всё, можно компилировать. Ты можешь показать такие же полноценные примеры реализующие в точности туже самую функциональность с использованием всех этих монадных библиотечек и т.п.? ) Оценим тогда удобство подходов для пользователя библиотечек...
У меня и так примеры полноценные, нужно только либу подключить
var lib = require('lib');
Всё По желанию можно неймспейс развернуть, это вот так делается
eval(lib.ns('lib'))
Можешь пробовать. Правда моей либы нет в публичном доступе, сложно будет позапускать.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Конечно работает. Если посмотрим на первый пример здесь на тему реактивных монадных парсеров (тот самый, что с заглавной страницы библиотечки Rxx), то я написал его ручной императивный аналог, работающий в реактивном режиме, меньше чем за минуту. Причём он оказался намного короче и намного проще для понимания.
Не проще В моем случае надо понять только грамматику. В твоем — дополнительно к этому приседания с состоянием.
Да и вообще, сколько смотрю, вот не могу понять, как твой вариант
>И вроде как ни у кого нет никаких претензий к его работе (придирки на счёт глобальной функции не принимаются — это тестовый пример и мы всегда можем одним движением заменить на объект, если надо завести много параллельных парсеров).
Это не придирки, это очень важный аспект, один из ключевых.
_>Но при этом я не раз повторял, что писать подобный код имеет смысл только в простых случаях (правда в этой темке что-то слишком часто попадались именно они). А в сложных следует использовать какие-то готовые библиотеки. Например конечные автоматы для каких-то событий или же Спирит, если говорим о тексте и т.п. Я надеюсь третьего (или уже четвёртого?) повтора этого моего тезиса будет достаточно, чтобы ты не "забыл" его снова? )
Во первых, ты изначально говорил про спирит и yacc, а выдал клочки императивного кода.
Во вторых, функционал имеет свойство развиваться. Отсюда ясно,что твои частные случаи особого смысла не имеют.
I>>Если ты таки решил прикрутить короутины, то всё в порядке. Правда теперь не ясно, почему ты сопротивлялся столько дней.
_>Оптимальное решение — это переписать Спирит под реактивный стиль. Но пока такого нет (а я точно не собираюсь делать подобное ради форумного спора ), то можно удовлетвориться и таким решением. Так сказать разумный компромисс между эффективностью кода и временем разработки.
Это абсолютно неважно — ты сказал что монады не нужны и сам же в конце концов предложил использовать монаду.
Твоя функция Analyze выдохнется через полтора дня, когда окажется, что требования поменялись и все надо будет переписать. А без короутины количество кода будет просто конским.
I>>Я ожидал что ты сразу переделаешь analyse на короутины, но мне уже надоело. Тебе теперь должно быть понятно, как императивно делается реактивный парсинг.
_>Короутины в Analyze? Зачем они там? Они могут понадобиться только если мы хотим заставить готовый библиотечный код (который мы не можем или не хотим менять) работать в асинхронном режиме. А если в Analyze только мой код, то больше ничего и не требуется.
I>>Любой реактивный парсинг сожрёт ресурсы и выдаст фильтрованый результат только по окончании. И это не важно, с++ или асп.нет или yesod(хаскель).
_>С чего бы это? Ты не видел примеры в этой темке? )
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так а чем функция типа Apply не подходит то? Что-то типа _>
_>template<typename R, typename T> auto Apply(optional<T> t, R (*f)(T)) {return t?f(*t):optional<R>();}
_>
_>Пояснение: в boost'е у optional переопределён оператор bool (возвращает has_value()) и * (возвращает value()) — в таком варианте код записывается короче, но разницы в смысле нет.
И? Дальше-то что? Ну вот написал Петя такую функцию Apply для своего optional. А мне-то как этим пользоваться?
Вот у меня был код на обычных big_integer:
Здравствуйте, Sinclair, Вы писали:
S>И? Дальше-то что? Ну вот написал Петя такую функцию Apply для своего optional. А мне-то как этим пользоваться? S>Я решил заменить их на option<big_integer>. Как теперь будет выглядеть мой код?
Пардон, что влезаю в разговор, но разве можно оставить существующий код без изменения при замене T на option<T>? По-моему, это очень опасно. Получается, придется брать какое-то значение по умолчанию и надеяться, что во всех местах оно подойдет.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Дисклаймер: я только-только начинаю постигать смысл монад, поэтому могу ошибиться.
ARK>Пардон, что влезаю в разговор, но разве можно оставить существующий код без изменения при замене T на option<T>? По-моему, это очень опасно. Получается, придется брать какое-то значение по умолчанию и надеяться, что во всех местах оно подойдет.
В том-то и прелесть монад, что можно. В общем это зависит от самой монады, но конкретно с optional поступают так. Если есть операция F(t1,t2,...)над элементами типа T (или нескольких типов T1, T2, T3, ...), то та же самая операция над optional<T> возвращает null если хоть одно из значений null и F(t1,t2,...) все значения не null.
Причем, насколько я понимаю, это преобразование может сделать компилятор. Т.е. да, код выше не измениться.
Немного кода.
"Волшебный" метод bind, который из функции F<T> делает функцию F<optional<T>> (могу наврать с типами и все такое)
Тогда код Синклера никак не поменяется, но использоваться будет новая функция, созданная компилятором.
Супер! Я в восторге. Еще один из монадных принципов "щелкнул". AlexRK, спасибо, что своим вопросом заставил меня задуматься и понять что же хотел сказать Синклер.
СУВ, akava
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Дисклаймер: я только-только начинаю постигать смысл монад, поэтому могу ошибиться.
Я пока этой конструкцией не проникся. Option/Maybe, безусловно, полезен, а нафиг все остальное нужно, пока не понял.
A>В том-то и прелесть монад, что можно. В общем это зависит от самой монады, но конкретно с optional поступают так. Если есть операция F(t1,t2,...)над элементами типа T (или нескольких типов T1, T2, T3, ...), то та же самая операция над optional<T> возвращает null если хоть одно из значений null и F(t1,t2,...) все значения не null.
А если мне это не нужно? Может быть, мне нужно заменить отсутствующие значения на нули. А может в одном месте надо заменить на нули, а в другом — вернуть нулл, если хоть одно нулл.
А монада берет и лихо за меня принимает решения во всех местах. Причем я даже не вижу, в каких, все ведь компилится.
A>Супер! Я в восторге. Еще один из монадных принципов "щелкнул". A>AlexRK, спасибо, что своим вопросом заставил меня задуматься и понять что же хотел сказать Синклер.
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
EP>>Это было неофициальное обсуждение. Я думаю вряд ли в C++ добавят сахар для монад (возможно будет мощный препроцессор, на котором этот сахар легко реализуется (и не только он)). _>Я к тому, что раньше подобные рассуждения C++'ников выглядели бы очень необычно. Сейчас это уже так, практически норма. )
Полиморфные лямбды уже есть, концепции-lite скоро будут. Надо двигаться дальше — модули, compile-time reflection, корутины, макросы, мульти-методы и т.д.
_>А что за препроцессор? Что-то не слышал планов про изменения в этой области...
(Точнее не препроцессор, а макросы). Это не изменения, а только разговоры — например. Главное не надо пытаться использовать макросы там, где достаточно лямбд, compile-time reflection, Boost.Fusion, etc.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>В том-то и прелесть монад, что можно. В общем это зависит от самой монады, но конкретно с optional поступают так. Если есть операция F(t1,t2,...)над элементами типа T (или нескольких типов T1, T2, T3, ...), то та же самая операция над optional<T> возвращает null если хоть одно из значений null и F(t1,t2,...) все значения не null. A>Причем, насколько я понимаю, это преобразование может сделать компилятор. Т.е. да, код выше не измениться.
[...] A>Тогда код Синклера никак не поменяется, но использоваться будет новая функция, созданная компилятором.
Только код поменяется, даже в Haskell. Не все функции можно автоматически лифтануть.
Например, было
a -> [a] -> a
а нужно
a -> [Maybe a] -> a
Придётся переписывать нарезая на continuations вручную, либо через do-сахар.
Точно также и в примере выше, можно переписать
array[i]*array[i]
в
get(array[i])*get(array[i])
тогда будет работать и с optional<int> и с int, и с int*, и с optional<int>*, и даже с future<int>.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>А если мне это не нужно? Может быть, мне нужно заменить отсутствующие значения на нули. А может в одном месте надо заменить на нули, а в другом — вернуть нулл, если хоть одно нулл. ARK>А монада берет и лихо за меня принимает решения во всех местах. Причем я даже не вижу, в каких, все ведь компилится.
Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind.
То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Пардон, что влезаю в разговор, но разве можно оставить существующий код без изменения при замене T на option<T>? По-моему, это очень опасно. Получается, придется брать какое-то значение по умолчанию и надеяться, что во всех местах оно подойдет.
А почему нет? Просто нужно понимать, что как только у нас появилось undefined где-то в выражении, так сразу всё выражение стало undefined. А в тех немногих местах, где нужно оставить "значение по умолчанию", отличное он undefined, пишется ручной код.
Может, я не вижу какой-то опасности?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
I>expr = term | term '+' term | term '-' term
I>term = factor '*' factor | factor '/' factor
I>factor = number | '(' expr ')' | '-' factor | '+' factor
I>number = digit {digit}
I>digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
I>
I>Итого — в спирите раз в 7-8 раз больше кода чем в бнф грамматике, при том что два правила сидят в самой либине — digit и uint, если их добавить, кода будет в 10 раз больше I>А вот фокус — та же грамматика на комбинаторах I>
Это неплохо выглядит. А предыдущий пример это что ?
Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.
Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы"
Похоже, "монады не нужны" оказалось большим преувеличением
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ааа, понял о чём речь, как раз в стиле Спирита задачки. ))) Согласен, полезная и вполне реализуемая вещь. Причём реализуемая тривиально прямо сейчас, если отказаться от идеи написания полноценного xml парсера, а реализовать решения конкретных задачек (типа двух примеров выше).
Я об этом и говорил с самого начала — я могу делать такие решения на коленке для каждого частного случая. Но это всё равно как разбирать регулярные выражения без Regex-библиотеки: работает в простых случаях, а шаг вправо/влево — и объём кода резко возрастает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>А почему нет? Просто нужно понимать, что как только у нас появилось undefined где-то в выражении, так сразу всё выражение стало undefined. А в тех немногих местах, где нужно оставить "значение по умолчанию", отличное он undefined, пишется ручной код.
Я о том, что эти места будут не видны "невооруженным глазом". А особенно хорошо, если язык поддерживает вывод типов. Изменив, например, тип результата функции, мы разом изменяем семантику кода во многих местах. А компилятор нам не подскажет — семантика изменилась, но синтаксис подходит и старый... Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например).
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind. EP>То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся.
Как я понял, Sinclair настаивает как раз на неизменном коде.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это неплохо выглядит. А предыдущий пример это что ?
Я его упростил.
I>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.
Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура).
Чтобы называть монадой, нужно как минимум найти нетривиальный bind.
I>Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы" I>Похоже, "монады не нужны" оказалось большим преувеличением
А в каком смысле было "монады не нужны"? Монада это математическая структура.
1. Не нужно знать такое понятие?
2. Не нужен do-сахар?
3. Не надо требовать в интерфейсе монады, там где достаточно более общих структур?
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
EP>>Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind. EP>>То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся. ARK>Как я понял, Sinclair настаивает как раз на неизменном коде.
Вот, например, упрощённый вариант кода выше:
accumulate a = foldl (+) 0 a
Как сделать так, чтобы он работал на [Maybe Int] без изменений?
(естественно речь не про вытаскивание всех значений снаружи функции и её вызов с обычным списком [Int])
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Реальность примерно такая — на динамических языках как правило надо кода гнать в разы меньше, а иногда даже на порядки. Собтсвенно смотри сам — спирит сливает даже самопалу на JS.
Вот это уже действительно похоже на сказки. )))
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Записывать нужно так, что бы было легко прочесть, а не что бы строчек было меньше. Эдак окажется что все программы на всех языках будут в одну строку.
А что же ты тогда сам изначально БНФ записал в строчку? )))
I>Шо, в самом деле ? А я то думал это в любом реактивном парсере можно
В твоих примерах я этого не видел. )
I>Я же давал ссылку — там именно такая функция и приведена. Что еще надо, если та не подходит ?
Это где она одно число выводит? )))
I>Будешь смеяться, я и это показл. Парсер возвращает пару значение-остаток. Для числа значением будет число, представь себе весь ужас. Для скобки будет скобка и тд и тд.
Ну вот покажи пример аналогичный тем моим. Ну т.е. парсим инты разделённые запятыми и выводим их и среднее за всё время. Простейшая задачка, решаемая в пару строк, как я и показал. Интересно как будет выглядеть решение на базе тех твоих библиотек.
I>С железом всё крайне консервативно. Типичный железячник пишет такие простыни императивного кода, которые никто, кроме него, прочесть не может. Единственное достоинство — оно как то работает.
I>FRP нужно для описания поведения и реакции на события некоторой системы. Раз в робототехнике, по твоим словам, это не надо, ну значит робототехника до этого еще не доросла.
Очень сомнительный пример. Автор в начале развивает крайне кривую архитектуру (тучи разных ajax запросов особенно радуют), а потом успешно с ней борется с помощью сторонней библиотеки. В то время как данная задача решалась уже тысячи раз, причём и без подобных библиотек и без описанных в начале статьи ужасов.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Подход как раз именно один и тот же, это recursive descent. И я даже пудозреваю, что спирит это тоже реализация через комбинаторы парсеров, только в компайлтайм.
Вот именно что в компайлтайм. Это и есть принципиальная разница, а не разница в том что компилятор C++ позволяет создавать код эффективнее чем C#.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не проще В моем случае надо понять только грамматику. В твоем — дополнительно к этому приседания с состоянием. I>Да и вообще, сколько смотрю, вот не могу понять, как твой вариант
Ну по крайне мере он заметно короче. ))) А остальное уже дело вкуса. )
I>Это абсолютно неважно — ты сказал что монады не нужны и сам же в конце концов предложил использовать монаду.
Это ты короутины что ли монадами обозвал? ) При таком раскладе тогда надо считать и все коллекции в stl монадами, да исключения тогда тоже монада и т.п... Весь C++ тогда состоит из сплошных монад. ))) Но мы вроде как в этой темке обсуждали явные монады с вполне конкретными свойствами, а не некую их аналогию из императивных языков. Так вот явные монады в C++ ввести можно без проблем (как показывалось уже в этой темке), но короутины, исключения или скажем std::list — это явно не оно. )))
I>Твоя функция Analyze выдохнется через полтора дня, когда окажется, что требования поменялись и все надо будет переписать. А без короутины количество кода будет просто конским.
Пока что практика показывает обратное. )
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>И? Дальше-то что? Ну вот написал Петя такую функцию Apply для своего optional. А мне-то как этим пользоваться? S>Вот у меня был код на обычных big_integer: S>
S>Я решил заменить их на option<big_integer>. Как теперь будет выглядеть мой код?
Хм, очень странный пример, если смотреть с твоих позиций. Потому как именно при использование монад данный код придётся существенно переделывать. Конечно же и при использование функции вида Apply тоже надо переделывать, т.к. это тоже в общем то функциональный подход (хотя и без монад). Но кроме этого в языке есть и другие способы (см. ниже). Но если уж ты спросил именно про Apply, то всё же отвечу для порядка, хотя естественно я бы не стал подобную фигню использовать:
Apply со многими аргументами естественно без проблем выражается через через Apply для одного. Кстати, в C++ это ещё и можно записать сразу для всех видов монад в принципе, ну а в C# придётся записывать для каждого. Но это так, просто для общей картины.
А вот если воспользоваться "тупым императивным способом" и просто переопределить все нужные операторы для optional, то можно вообще не менять ни одну букву. Причём это естественно будет подходить сразу для всех типов. Что-то вроде:
template<typename T> auto operator+(const optional<T>& t1, const optional<T>& t2){return t1&&t2?*t1+*t2:optional<T>();}
Кстати, а в языке D все эти операторы можно реализовать сразу одной функций, т.к. там вид оператора передаётся просто как параметр (времени компиляции естественно) в функцию.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Тогда код Синклера никак не поменяется, но использоваться будет новая функция, созданная компилятором.
Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Полиморфные лямбды уже есть, концепции-lite скоро будут. Надо двигаться дальше — модули, compile-time reflection, корутины, макросы, мульти-методы и т.д.
Да, да, всё это хочу. )))
Кстати, это у нас уже практически полноценный D получается, только без потери гигантской инфраструктуры C++. Ещё бы только строки в шаблоны по человечески, плюс аналог функции mixin, и можно начинать творить чудеса. )))
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали: ARK>Я о том, что эти места будут не видны "невооруженным глазом".
Эти места будут сразу видны — там, где мы пытаемся выполнить конверсию из option<T> в T.
Наличие lifted операций просто помогает минимизировать последствия катастрофы. Там, где мы писали
int a = b + (c*d);
мы будем писать
int a = b + (c*d) ?? 42;
Но не
int a = (b ?? 42) + (c ?? 0) * (d ?? 0);
ARK>А особенно хорошо, если язык поддерживает вывод типов. Изменив, например, тип результата функции, мы разом изменяем семантику кода во многих местах.
Практически любой современный язык поддерживает вывод типов — по крайней мере, в пределах выражения.
ARK>А компилятор нам не подскажет — семантика изменилась, но синтаксис подходит и старый... Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например).
Совершенно верно. А также при замене int на double, или double на Matrix4x4<double>.
Тут вопрос в том, что считать семантикой
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Это всё понятно. Но я вообще то как раз и спрашивал, а какой уже у нас будет тут код на языке позволяющем контроль эффектов? В чём будет его преимущество над кодом выше и т.п...
Отвечу как практик на эрланге, языке относительно бедном, поэтому ответ будет "от противного".
Во-первых, я хочу гарантировать чистоту processEventOrFail относительно определенных типов эффектов (они должны быть аккумулированы в Effects, в то время как другие — такие как чтение разделяемых глобальных данных или логирование — допустимы) на стадии компиляции или статического анализа. В эрланге это как минимум сложно, приходится решать административно.
Во-вторых, я вынужден вносить Effects внутрь State, так как иначе связывание кода внутри processEvent становится очень громоздким засчет необходимости передавать, возвращать и аккумулировать Effects. Это уродливый костыль с очевидными недостатками (например невозможно явно отличить функции State -> State с эффектами от функций без эффектов), но видимо лучшее практическое решение в отсутствие монад.
А в хаскелле и то и другое не проблема.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Хм, очень странный пример, если смотреть с твоих позиций. Потому как именно при использование монад данный код придётся существенно переделывать.
Зачем?
_>Конечно же и при использование функции вида Apply тоже надо переделывать, т.к. это тоже в общем то функциональный подход (хотя и без монад). Но кроме этого в языке есть и другие способы (см. ниже). Но если уж ты спросил именно про Apply, то всё же отвечу для порядка, хотя естественно я бы не стал подобную фигню использовать: _>
_>Apply со многими аргументами естественно без проблем выражается через через Apply для одного. Кстати, в C++ это ещё и можно записать сразу для всех видов монад в принципе, ну а в C# придётся записывать для каждого. Но это так, просто для общей картины.
В том-то и дело, что в языках без поддержки монад приходится вот так вот извращаться. Как только мы выйдем за пределы начальной школы, где формулы ограничены двумя аргументами, у нас объём кода, привнесённого apply, начнёт превышать объём оригинального кода.
А в языке, где монады — первоклассная сущность, весь heavy lifting должен делать компилятор.
_>А вот если воспользоваться "тупым императивным способом" и просто переопределить все нужные операторы для optional, то можно вообще не менять ни одну букву. Причём это естественно будет подходить сразу для всех типов. Что-то вроде: _>
Да, в С++ конкретно это место будет работать — потому что неинстанциированные шаблоны не компилируются, поэтому отсутствующие для T операторы будут отсутствовать и для optional<T>. К сожалению, это не коснётся пользовательских функций, поэтому прикладному программисту придётся выписывать либо Apply руками в каждое место применения, либо руками лифтить все нужные функции (см. System.Math для маленького примера. Реальная мат.библиотека будет содержать на порядок больше)
_>Кстати, а в языке D все эти операторы можно реализовать сразу одной функций, т.к. там вид оператора передаётся просто как параметр (времени компиляции естественно) в функцию.
Это всё паллиатив. Хардкорность монад — именно в том, что они имеют специальную семантику, и предоставляют определённые гарантии. Благодаря этому компилятор может втыкать Apply там, где нужно, не дожидаясь ручной подсказки от программиста.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
Вот я как раз хочу, чтобы не надо было переколбашивать. И мне кажется, что как раз монады — путь к успеху.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Мммм если целая индустрия работает по одним правилам, и ты один считаешь что им всем надо бы работать по другому, то как ты думаешь, какая вероятность что прав именно ты? )
Безотносительно конкретного вопроса, хотелось бы предостеречь против
1. Использования голосований (в т.ч. в виде статистики использования) для решения технических вопросов. Это очевидно нерелевантная аргументация — иначе мы были бы вынуждены признать PHP наиболее технически совершенным средством для веб-разработки.
2. Отсылки к промышленным применениям. Природа встраиваемых систем такова, что в них всегда предпочитают надёжное новому. Даже если новое решение в 100 раз лучше существующего, ему потребуется значительное время на внедрение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.
EP>Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура). EP>Чтобы называть монадой, нужно как минимум найти нетривиальный bind.
Это ничего не меняет
I>>Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы" I>>Похоже, "монады не нужны" оказалось большим преувеличением
EP>А в каком смысле было "монады не нужны"? Монада это математическая структура. EP>1. Не нужно знать такое понятие? EP>2. Не нужен do-сахар? EP>3. Не надо требовать в интерфейсе монады, там где достаточно более общих структур?
Изначально было так — "монады не нужны" потому что всё можно написать императивно.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Реальность примерно такая — на динамических языках как правило надо кода гнать в разы меньше, а иногда даже на порядки. Собтсвенно смотри сам — спирит сливает даже самопалу на JS.
_>Вот это уже действительно похоже на сказки. )))
Это необходимость. Без этого динамические языки в принципе нежизнеспособны.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
A>>Если есть операция F(t1,t2,...)над элементами типа T (или нескольких типов T1, T2, T3, ...), то та же самая операция над optional<T> возвращает null если хоть одно из значений null и F(t1,t2,...) все значения не null.
ARK>А если мне это не нужно? Может быть, мне нужно заменить отсутствующие значения на нули. А может в одном месте надо заменить на нули, а в другом — вернуть нулл, если хоть одно нулл.
Тогда ты неверно выбрал тип. Если тебе нужны 0 вместо null, то ты так и пишешь: list.map(e=> e.val()??0) Либо пишешь новую монаду которая знает о твоем желании.
ARK>А монада берет и лихо за меня принимает решения во всех местах. Причем я даже не вижу, в каких, все ведь компилится.
Ты решаешь какую монаду выбрать. И делаешь это осознанно.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, akava, Вы писали:
A>>Тогда код Синклера никак не поменяется, но использоваться будет новая функция, созданная компилятором.
_>Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int).
Согласен, что в реальности этот код должен поменяться, но мы в философии, поэтому можем пофантазировать.
Например, предположим, что компилятор сам умеет делать из функции F функцию F* над optional<> аргументами. По принципу: все не null -> вычисляем F, что-то null -> результат null.
Тогда код Синклера:
public T DoStuff<T>(List<T> array, T limit) {where T has '*' and '+' and '>'}
{
var sum = default(T); // вот тут у меня косяк, так как default(optional<T>) вернет null, но, уверен, он решаемfor(int i=0; i<array.length(); i++)
{
if (array[i]*array[i] > limit))
sum+=array[i]*array[i];
}
return sum;
}
останется без изменений, потому как компилятор (см. выше) сделает нам сложение, умножение и сравнение на optional<> (сравнение по принципу если чт-то null, то false, как в sql).
Я, кнечно, могу ошибаться, но я не вижу переколбашивания. Если у T есть сложение, умножение и сравнение, то функция работает. Монада же дает эти операции "на лету" функций над базовым типом.
Здравствуйте, AlexRK, Вы писали:
ARK>А особенно хорошо, если язык поддерживает вывод типов. Изменив, например, тип результата функции, мы разом изменяем семантику кода во многих местах. А компилятор нам не подскажет — семантика изменилась, но синтаксис подходит и старый...
Да, на протяжении всей цепочки, за счет вывода типов, все значения обернутся в монады. Но в конце цепочки, где мы будем использовать результат (вызов вэбсервиса, например) компилятор ругнется и скажет, что такая-то функция не умеет работать с типом optional<T>.
Особенно хорошо это работает с монадой IO или "Async" (еще одна из вещей, которая стала у меня на месте благодаря этому топику):
Есть цепочка:
m = a+b*c
n = m/a-b;
p = m * n;
// ....
ws.Call(p, n, 1);
// или
Console.Write("Result is " + p);
И вместо a мы передали IO{int} (я ее понимаю так: в a сейчас значения нет, но если понадобиться, то я его спрошу у пользователя) или Future{int}. Тогда вся цепочка завернется в монаду. Но ws.Call не умеет работать с IO или Future, поэтому компилятор ругнется и нам придется писать код, который достает значение из монады. Причем, тут может возникнуть эксепшен. Пользователь ввел не int, либо Future закончилось таймаутом. Этот момент нужно обрабатывать.
С Console.Write сложнее. У всех методов есть ToString(). Поэтому компилятор не ругнется.
У монады он, скорее всего реализован в виде кода, получающего значение из нее. А значит, мы можем получить эксепшен в месте, которое выглядит как место где НЕ МОЖЕТ быть исключения. Вот это косяк и как его фиксить я действительно ХЗ.
Еще один косяк с операциями, возвращающими bool. Например сравнение.
if (m > limit)
Alert();
if (!(m <= limit))
Alert();
Что тут делать? Если мы определим '>' над optional<> как false, в случае когда o == null, то первая инструкция будет игнорировать null, а вторая сообщать о них.
Т.е. нужно будет об этом задумываться. А если нужно будет задумываться, то когда-нибудь, какой-нибудь разработчик Леша заменит первый вариант на второй (или наоборот) и изменит семантику кода. Вот это тоже КОСЯК.
Блин, чем больше в лес, тем дальше вылез Товарищи опытные "монадоведы", расскажите плиз, что в таких случаях делать? Сразу хочется работать с монадоми вручную, без компилятора, но тогда монады теряют весь смысл. Единственное, что я смог придумать это принцип: если нужно значение из монады, то получай его явно (т.е. вручную).
Уфф, нифигассе я настрочил.
ARK>Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например).
Я сам ХЗ. Не нужно воспринимать мои коментарии как "эгегей, монады куль, почему никто не использует монады...". Я сам только к ним присматриваюсь (как к новой для меня концепции).
Аргументы выше, это то, что я сам себе ответил, когда задался таким вопросом.
Здравствуйте, akava, Вы писали:
A>Особенно хорошо это работает с монадой IO или "Async" (еще одна из вещей, которая стала у меня на месте благодаря этому топику):
Кстати, монаду IO я, на данный момент, воспринимаю как заморочки в угоду чистоте функций. А вот монаду Async я очень уважаю. Асинхронный код в ее случае становиться выно проще.
СУВ, akava
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не проще В моем случае надо понять только грамматику. В твоем — дополнительно к этому приседания с состоянием. I>>Да и вообще, сколько смотрю, вот не могу понять, как твой вариант
_>Ну по крайне мере он заметно короче. ))) А остальное уже дело вкуса. )
Он короче, чем многословное решение на query comprehension. Решение на Хаскеле по краткости ты сильно вряд ли обгонишь, но я не могу его показать, Хаскелем не владею как то.
I>>Это абсолютно неважно — ты сказал что монады не нужны и сам же в конце концов предложил использовать монаду.
_>Это ты короутины что ли монадами обозвал? )
Это без пяти минут монада.
>При таком раскладе тогда надо считать и все коллекции в stl монадами, да исключения тогда тоже монада и т.п...
Про коллекции и исключения тебе уже рассказали недели три назад.
>Весь C++ тогда состоит из сплошных монад. )))
Да, монады встроены в язык.
>Но мы вроде как в этой темке обсуждали явные монады с вполне конкретными свойствами, а не некую их аналогию из императивных языков. Так вот явные монады в C++ ввести можно без проблем (как показывалось уже в этой темке), но короутины, исключения или скажем std::list — это явно не оно. )))
Чего ты хочешь объяснить, я уже не понимаю. Большей частью у тебя сравнение query comprehension С# vs императивный код на С++.
I>>Твоя функция Analyze выдохнется через полтора дня, когда окажется, что требования поменялись и все надо будет переписать. А без короутины количество кода будет просто конским.
_>Пока что практика показывает обратное. )
Значит ты какие то не те примеры приводишь, ибо твои надо еще допиливать, что бы они обладали хотя бы половиной полезных свойств, как хотя бы то многословное на query comprehension.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Блин, чем больше в лес, тем дальше вылез A>Товарищи опытные "монадоведы", расскажите плиз, что в таких случаях делать? Сразу хочется работать с монадоми вручную, без компилятора, но тогда монады теряют весь смысл. Единственное, что я смог придумать это принцип: если нужно значение из монады, то получай его явно (т.е. вручную).
Так его и получают вручную, даже в Haskell. Например было:
foo a b = a + b
чтобы эта функция работала с монадическими значениями "a" и "b" внутри (а не просто вытащить все значения снаружи и вызвать эту функцию), её нужно расчленить на лямбды-продолжения:
foo a b = a >>=
(
\x ->
b >>=
(
\y ->
return x + y
)
)
можно немного переформатировать:
foo a b = a >>= \x ->
b >>= \y ->
return x + y
Либо использовать синтаксический сахар do:
foo a b = do x <- a
y <- b
return a + b
(для этого конкретного случая достаточно аппликативного функтора вместо монады, но не суть)
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Тогда ты неверно выбрал тип. Если тебе нужны 0 вместо null, то ты так и пишешь: list.map(e=> e.val()??0) Либо пишешь новую монаду которая знает о твоем желании.
Раньше никаких нуллов не было. А потом все изменилось, и надо проанализировать все места. А эти места компилятор не покажет. Ну, какие-то покажет, а какие-то нет.
A>Ты решаешь какую монаду выбрать. И делаешь это осознанно.
Осознанно я выбираю только на самом высоком уровне. А потом все происходит автоматом и компилятор далеко не везде подскажет, что что-то изменилось. Пусть я отдаю себе отчет в том, что семантика изменилась, но перелопатить гору кода мне это знание не поможет.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
По факту, в C# код Синклера никак не поменяется. Потому что ECMA 334:14.2.7 Lifted Operators
В теории, хочется того же самого для пользовательских типов, а не только для Nullable<T>, оборудованного Compiler Magic.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
A>>Ты решаешь какую монаду выбрать. И делаешь это осознанно.
ARK>Осознанно я выбираю только на самом высоком уровне. А потом все происходит автоматом и компилятор далеко не везде подскажет, что что-то изменилось. Пусть я отдаю себе отчет в том, что семантика изменилась, но перелопатить гору кода мне это знание не поможет.
Давай вот тут
продолжим разговор. Как раз там я нашел два места в которых компилятор не поможет.
Я не знаю как это пофиксить. Может вместе что-нить придумаем. А может кто-то подскажет.
СУВ, akava
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, akava, Вы писали:
A>>Блин, чем больше в лес, тем дальше вылез A>>Товарищи опытные "монадоведы", расскажите плиз, что в таких случаях делать? Сразу хочется работать с монадоми вручную, без компилятора, но тогда монады теряют весь смысл. Единственное, что я смог придумать это принцип: если нужно значение из монады, то получай его явно (т.е. вручную).
EP>Так его и получают вручную, даже в Haskell. Например было: EP>
EP>foo a b = a + b
EP>
чтобы эта функция работала с монадическими значениями "a" и "b" внутри (а не просто вытащить все значения снаружи и вызвать эту функцию), её нужно расчленить на лямбды-продолжения:
Ага т.е. сам код, который теоретически будет работать с монадой должен быть напсан специальным образом. Надо обдумать.
Евгений, ты не мог бы мой код из сообщения выше перевести на хаскель, чтобы он поддерживал манады IO и Future? (У Future принцип такой же как в IO только значение дает асинхронная операция).
m = a+b*c
n = m/a-b;
p = m * n;
// ....
ws.Call(p, n, 1);
// или
Console.Write("Result is " + p);
Насколько он станет сложнее. Скажем, a, b и c могут стать монадой. Было бы очень интересно.
СУВ, akava
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Ага т.е. сам код, который теоретически будет работать с монадой должен быть напсан специальным образом. Надо обдумать.
Да, именно так — он должен быть распилен на вложенные продолжения.
A>Евгений, ты не мог бы мой код из сообщения выше перевести на хаскель, чтобы он поддерживал манады IO и Future? (У Future принцип такой же как в IO только значение дает асинхронная операция). A>
A>m = a+b*c
A>n = m/a-b;
A>p = m * n;
A>// ....
A>ws.Call(p, n, 1);
A>// или
A>Console.Write("Result is " + p);
A>
A>Насколько он станет сложнее. Скажем, a, b и c могут стать монадой. Было бы очень интересно.
Примерно так:
foo a b c = do x <- a
y <- b
z <- c
-- again, applicative is enough for this caselet m = a+b*c
let n = m/a-b
let p = m * n
return print "Result is " ++ show p
-- ^^^ do not need return for IO monad, just:
-- print "Result is " ++ show p
Если a, b, c это IO — то "return" можно убрать.
Никакой магии — мы явно нарезаем код на continuations, do-нотация просто помогает убрать несколько буковок.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, meadow_meal, Вы писали:
_>Отвечу как практик на эрланге, языке относительно бедном, поэтому ответ будет "от противного".
Эммм, это как бы снова не то, что я спрашивал. ))) Ну да ладно. )
_>Во-первых, я хочу гарантировать чистоту processEventOrFail относительно определенных типов эффектов (они должны быть аккумулированы в Effects, в то время как другие — такие как чтение разделяемых глобальных данных или логирование — допустимы) на стадии компиляции или статического анализа. В эрланге это как минимум сложно, приходится решать административно.
Я так понимаю, это пожелание иметь "чистые функции" в языке? Да, в C++ они действительно только административно вводятся. А вот например в языке D они есть (причём за этот факт ничем расплачиваться не надо), но я что-то не видел особых чудес от этого.
_>Во-вторых, я вынужден вносить Effects внутрь State, так как иначе связывание кода внутри processEvent становится очень громоздким засчет необходимости передавать, возвращать и аккумулировать Effects. Это уродливый костыль с очевидными недостатками (например невозможно явно отличить функции State -> State с эффектами от функций без эффектов), но видимо лучшее практическое решение в отсутствие монад.
Ну начнём с того, что мы изначально здесь рассматриваем довольно узкий случай, когда "ValidateEvent" нельзя отделить от "ProcessEvent". Т.к. в противном случае мы для этой задачки просто берём какую-нибудь библиотечку конечных автоматов и записываем код в виде таблички вида:
state1+event[guard]/action==state2
Это вот прямо код на C++, где state1, event, state2 — это классы, а guard и action — функции (ну естественно могут быть функторы, лямбды и т.п.). При такой записи мы автоматом получаем нужное нам разделение и даже гораздо больше этого.
_>А в хаскелле и то и другое не проблема.
Пока что не увидел нигде реальных примеров этого.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>В том-то и дело, что в языках без поддержки монад приходится вот так вот извращаться. Как только мы выйдем за пределы начальной школы, где формулы ограничены двумя аргументами, у нас объём кода, привнесённого apply, начнёт превышать объём оригинального кода. S>А в языке, где монады — первоклассная сущность, весь heavy lifting должен делать компилятор.
Эээ, что что? ) Насколько я понимаю, "главный" язык для работы с монадами у нас Хаскель. Так вот в нём компилятор не делает ничего подобного, а надо записывать всё руками.
S>Да, в С++ конкретно это место будет работать — потому что неинстанциированные шаблоны не компилируются, поэтому отсутствующие для T операторы будут отсутствовать и для optional<T>. К сожалению, это не коснётся пользовательских функций, поэтому прикладному программисту придётся выписывать либо Apply руками в каждое место применения, либо руками лифтить все нужные функции (см. System.Math для маленького примера. Реальная мат.библиотека будет содержать на порядок больше)
Ну для начала, если мы говорим о C++, то скажем все наши функции реализованные в виде шаблонов заработают сами автоматом. )))
Ну а нешаблонные действительно надо оборачивать в Apply. Так же как и в Хаскеле (только там в bind). И кстати в Хаскеле это единственный вариант, в отличие от C++.
S>Это всё паллиатив. Хардкорность монад — именно в том, что они имеют специальную семантику, и предоставляют определённые гарантии. Благодаря этому компилятор может втыкать Apply там, где нужно, не дожидаясь ручной подсказки от программиста.
Ээээ что что? ) Это в каком языке компилятор так умеет? )
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Тогда код Синклера: A>
A>public T DoStuff<T>(List<T> array, T limit) {where T has '*' and '+' and '>'}
A>{
A> var sum = default(T); // вот тут у меня косяк, так как default(optional<T>) вернет null, но, уверен, он решаем
A> for(int i=0; i<array.length(); i++)
A> {
A> if (array[i]*array[i] > limit))
A> sum+=array[i]*array[i];
A> }
A> return sum;
A>}
A>
A>останется без изменений, потому как компилятор (см. выше) сделает нам сложение, умножение и сравнение на optional<> (сравнение по принципу если чт-то null, то false, как в sql).
Ну так такое без проблем реализуется в языках, в которых доступна перегрузка операторов. Только вот к монадам это не имеет никакого отношения.
Поясняю разница в подходах:
1. Монады. Определяется ровно одна функция и всё. Дальше, с помощью неё можно разрулить абсолютно все ситуации (в этом и фокус как бы). Но вставлять эту функцию по коду надо руками.
2. Перегрузка операторов. Надо определить кучу операторов для каждого вида монады. И плюс возможно перегрузить несколько функций (те, которые определены не как шаблонные и соответственно не могут сами подхватить новый тип). Но зато после этого, никаких изменений в коде не потребуется вообще. Ни в одной букве.
A>Я, кнечно, могу ошибаться, но я не вижу переколбашивания. Если у T есть сложение, умножение и сравнение, то функция работает. Монада же дает эти операции "на лету" функций над базовым типом.
Монада ничего подобного не даёт. Ну точнее она нам даёт автоматическую реализацию этих функций, но расставить их вызовы в коде надо руками.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Поясняю разница в подходах: _>1. Монады. Определяется ровно одна функция и всё. Дальше, с помощью неё можно разрулить абсолютно все ситуации (в этом и фокус как бы). Но вставлять эту функцию по коду надо руками. _>2. Перегрузка операторов. Надо определить кучу операторов для каждого вида монады. И плюс возможно перегрузить несколько функций (те, которые определены не как шаблонные и соответственно не могут сами подхватить новый тип). Но зато после этого, никаких изменений в коде не потребуется вообще. Ни в одной букве.
Да, и выходит что самый оптимальный вариант получается в языке D, где мы можем переопределить все операторы для данного типа в одной функции. Если при этом ещё и все используемые функции являются шаблонными, то мы получаем полностью автоматическую замену T на optional<T> путём написания ровно одной функции и без модификации кода вообще.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Да, на протяжении всей цепочки, за счет вывода типов, все значения обернутся в монады. Но в конце цепочки, где мы будем использовать результат (вызов вэбсервиса, например) компилятор ругнется и скажет, что такая-то функция не умеет работать с типом optional<T>.
Где-то может и уметь — совершенно случайно.
A>Блин, чем больше в лес, тем дальше вылез
Да, я про это как раз и говорю. Но, судя по дальнейшему обсуждению, монады таки не предполагают волшебного изменения кода...
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я так понимаю, это пожелание иметь "чистые функции" в языке? Да, в C++ они действительно только административно вводятся. А вот например в языке D они есть (причём за этот факт ничем расплачиваться не надо), но я что-то не видел особых чудес от этого.
Я так понял, что речь идет не просто о чистых функциях, а о "выборочно чистых", к примеру чистых от работы с диском, но не от сетевых взаимодействий. В принципе, интересная идея, но в чем реальный бенефит выборочной чистоты и не будет ли это выглядеть адски страшно на любом ЯП — мне пока не ясно.
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Безотносительно конкретного вопроса, хотелось бы предостеречь против S>1. Использования голосований (в т.ч. в виде статистики использования) для решения технических вопросов. Это очевидно нерелевантная аргументация — иначе мы были бы вынуждены признать PHP наиболее технически совершенным средством для веб-разработки. S>2. Отсылки к промышленным применениям. Природа встраиваемых систем такова, что в них всегда предпочитают надёжное новому. Даже если новое решение в 100 раз лучше существующего, ему потребуется значительное время на внедрение.
Ну да, есть такой нюанс. Но разница между пунктом 1 и тем, что мы тут обсуждали, принципиальная. В веб'е грубо говоря все знают, что есть "плохие" технологии и "хорошие". И "плохие" частенько используются только потому, что это выгоднее (или в начале кажется, что это выгоднее). Но все понимают расклад и держат в уме набор "хороших" технологий, даже если не могут ими пользоваться в текущем проекте. А в робототехнике (практической, а не в чем-то типа ИИ), автоматике и т.п. областях просто нет в принципе каких-то известных "хороших" технологий. Чувствуется разница? )
Соответственно возникает вопрос: они там ещё просто не появились или же может быть оно просто не надо? )
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так такое без проблем реализуется в языках, в которых доступна перегрузка операторов. Только вот к монадам это не имеет никакого отношения.
Все реализуется на ассемблере. Вопрос в количестве телодвижений. Какой объем работы нужно проделать, чтобы реализовать все эти операции для optional<>, future<>, ...?
A>>Я, кнечно, могу ошибаться, но я не вижу переколбашивания. Если у T есть сложение, умножение и сравнение, то функция работает. Монада же дает эти операции "на лету" функций над базовым типом. _>Монада ничего подобного не даёт. Ну точнее она нам даёт автоматическую реализацию этих функций, но расставить их вызовы в коде надо руками.
Ты, наверное, имеешь ввиду расставить руками в Хаскеле. Так?
Но дело в том, что Монада -- математическая конструкция. Которая никак не привязана к Хаскелю и другим реализациям.
И ничего нам не помешает реализовать специальный язык Монаскель, в котором вручную ничего расставлять не придется, но мы огребем вохрох проблем
(и это только те, что вижу я).
Но даже сейчас, в Хаскеле, с помощью do-сахара нам, насколько я понял, не придется расставлять вызовы руками.
СУВ, akava
_>Поясняю разница в подходах: _>1. Монады. Определяется ровно одна функция и всё. Дальше, с помощью неё можно разрулить абсолютно все ситуации (в этом и фокус как бы). Но вставлять эту функцию по коду надо руками. _>2. Перегрузка операторов. Надо определить кучу операторов для каждого вида монады. И плюс возможно перегрузить несколько функций (те, которые определены не как шаблонные и соответственно не могут сами подхватить новый тип). Но зато после этого, никаких изменений в коде не потребуется вообще. Ни в одной букве.
Мы в философии. Мы можем фантазировать. Сделай, плиз, один шаг -- объедини 2 подхода.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Он короче, чем многословное решение на query comprehension. Решение на Хаскеле по краткости ты сильно вряд ли обгонишь, но я не могу его показать, Хаскелем не владею как то.
Да, скорее всего так и будет. Но у всего есть своя цена. И у Хаскеля она появляется в месте взаимодействия с реальным внешним миром...
I>Да, монады встроены в язык.
Да, в каком-то смысле можно так сказать. И естественно против таких "монад" вообще никто не может возражать. Т.е. упоминать их тут в контексте нашего обсуждения просто бессмысленно. А говорим мы именно о явных монадах, определённых программистом, и имеющих вполне конкретные общеизвестные свойства.
I>Чего ты хочешь объяснить, я уже не понимаю. Большей частью у тебя сравнение query comprehension С# vs императивный код на С++.
Вообще всё началось с того, что я попросил знатоков (в том смысле, что применяющих их где-то на практике) монад показать какие-нибудь примеры их полезного использования в мультипарадигменных языках, а не в Хаскеле (в котором без монад просто тоскливо).
Насколько я помню, практические единственным реальным примером были как раз твои реактивные монадные парсеры. Из плюсов надо отметить, что это действительно работающий пример. Ну а из минусов (что мы тут и обсуждали) — как мы увидели, тоже самое можно реализовать и без монад, причём частенько и ещё проще. Так что это хотя и был реальный ответ на мой вопрос, но он не стал аргументом в пользу монад.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, akava, Вы писали:
A>>Да, на протяжении всей цепочки, за счет вывода типов, все значения обернутся в монады. Но в конце цепочки, где мы будем использовать результат (вызов вэбсервиса, например) компилятор ругнется и скажет, что такая-то функция не умеет работать с типом optional<T>. ARK>Где-то может и уметь — совершенно случайно.
IQueriable в linq -- типичная монада.
В зависимости от реализации, она может и коллекцию итерировать, и в базу лезть, и вэбсервис вызывать, ... и эксепшены по делу и нет выкидывать. Это ведь никого не пугает.
Все, наоборот радуются, что один и тот же код может и "и коллекцию итерировать, и в базу лезть, и вэбсервис вызывать". А все это благодаря концепции Монада.
В свете вышесказанного, давай вернемся к ARK>Где-то может и уметь — совершенно случайно.
Если умеет -- отлично (если действительно умеет). Если не умеет, то наш тип (т.е. монада) обязана сделать все возможное, чтобы не ломать существующий код.
var q = (new []{1, 2, 3}).AsQueryable().Where(i=>i%2 == 0);
Console.WriteLine(q); // выводит: System.Int32[].Where(i => ((i % 2) == 0))
Вполне годное решение.
Хотя при работе с linq ты знаешь, что работаешь с linq. Т.е. должен понимать, что в зависимости от реализации IQueriable наш код будет вести себя по разному.
A>>Блин, чем больше в лес, тем дальше вылез
ARK>Да, я про это как раз и говорю. Но, судя по дальнейшему обсуждению, монады таки не предполагают волшебного изменения кода...
Конкретная реализация, конкретного языка не предполагает. Возможно есть языки, которые предполагают.
СУВ, aikin
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Да, и выходит что самый оптимальный вариант получается в языке D, где мы можем переопределить все операторы для данного типа в одной функции. Если при этом ещё и все используемые функции являются шаблонными, то мы получаем полностью автоматическую замену T на optional<T> путём написания ровно одной функции и без модификации кода вообще.
Можно ссылку на это плиз?
СУВ, akava
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>По факту, в C# код Синклера никак не поменяется. Потому что ECMA 334:14.2.7 Lifted Operators S>В теории, хочется того же самого для пользовательских типов, а не только для Nullable<T>, оборудованного Compiler Magic.
Хы, ну для начала это очередная "встроенная монада" — такое нет смысла обсуждать в нашем контексте. Но что самое интересное, эта самая реализация "как бы лифтинга" как раз совсем не похожа на классическую, а гораздо больше напоминает обычную перегрузку операторов. ))) Т.е. я конечно не в курсе конкретной реализации, но есть подозрение, что там при реализации этих операторов, компилятор не вызывает каждый раз какую-то специальную функцию типа Nullable, а сам напрямую форвардит вызовы в T. Если это так, то это уже точно становится не явная монада, а просто некая отдалённо похожая концепция. Типа как исключения и т.п. — это вроде как тоже нечто напоминающее монады.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Я так понял, что речь идет не просто о чистых функциях, а о "выборочно чистых", к примеру чистых от работы с диском, но не от сетевых взаимодействий. В принципе, интересная идея, но в чем реальный бенефит выборочной чистоты и не будет ли это выглядеть адски страшно на любом ЯП — мне пока не ясно.
Хы, такими темпами можно дойти до введения "прав доступа" внутри языка. )))
Кстати, ООП со своей инкапсуляцией частично пытается решать эту проблему, причём с другой стороны. Не по принципу "проверим что эта функция не лезет куда не надо", а по принципу "код, который лезет куда не надо, нельзя вызвать ниоткуда, кроме спец. предусмотренных мест".
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Все реализуется на ассемблере. Вопрос в количестве телодвижений. Какой объем работы нужно проделать, чтобы реализовать все эти операции для optional<>, future<>, ...?
На D будет ровно по одной функции на каждый тип монад.
В C++ надо будет переопределить каждый оператор (сколько у нас их там?), но это можно сделать для шаблонного типа монад (т.е. в реализации вызывать некую функцию монады). Т.е. в итоге получаем по одной функции на каждый тип оператора и отдельно по одной функции для каждого типа монад.
В C# фокус из C++ не пройдёт и придётся определять заново все операторы для каждого типа монад.
Ну а в Хаскеле подобное вообще не сделать.
A>Ты, наверное, имеешь ввиду расставить руками в Хаскеле. Так?
Скорее просто про существующие языки. Ну во всяком случае общеизвестные. )))
A>Но дело в том, что Монада -- математическая конструкция. Которая никак не привязана к Хаскелю и другим реализациям. A>И ничего нам не помешает реализовать специальный язык Монаскель, в котором вручную ничего расставлять не придется, но мы огребем вохрох проблем
Не вижу особого смысла в создание подобного. )
A>Но даже сейчас, в Хаскеле, с помощью do-сахара нам, насколько я понял, не придется расставлять вызовы руками.
Эмм, так придётся расставлять собственно этот do-сахар. ))) Т.е. единственное его преимущество перед расстановкой просто bind в том, что он ставится сразу на некий блок кода (работающий с одними значениями), а не каждый вызов каждой функций/оператора в bind засовывать.
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Кстати, я тут подумал... Теоретически на D можно сделать даже и автоматические вызовы нешаблонных функций f(T) с типом optional<T>. Там же есть перегрузка операции opDispatch и плюс функция mixin... Т.е. грубо говоря, мы можем тривиально написать код (одну функцию!), который придаст нашему классу optional бесконечное число функций-членов, каждый из которых просто вызывает глобальную функцию с тем же именем, передавая ей внутреннее значение optional.
Мда, всё же в C++ ещё очень много чего надо добавить, чтобы добиться возможностей D. И как видно, на области метапрограммирования надо концентрироваться в первую очередь, т.к. она позволяет делать потом вообще что угодно.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Кстати, я тут подумал... Теоретически на D можно сделать даже и автоматические вызовы нешаблонных функций f(T) с типом optional<T>. Там же есть перегрузка операции opDispatch и плюс функция mixin... Т.е. грубо говоря, мы можем тривиально написать код (одну функцию!), который придаст нашему классу optional бесконечное число функций-членов, каждый из которых просто вызывает глобальную функцию с тем же именем, передавая ей внутреннее значение optional.
Накидал тут быстренько работающий пример:
double LibFunc(int v) {return 10.0*v;}
struct Optional(T){
this(const T v) {this.v=v; ok=true;}
string toString() {return ok?to!string(v):"nothing";}//для красоты примера, а вообще не требуетсяauto opBinary(string op, T2)(Optional!T2 t) {mixin Prepare!("v"~op~"t.v"); return ok&&t.ok?R(f()):R();}
auto opDispatch(string name)() {mixin Prepare!("v."~name~"()"); return ok?R(f()):R();}
private:
mixin template Prepare(string s) {const auto f=()=>mixin(s); alias Optional!(typeof(f())) R;};
bool ok=false;
T v;
};
auto Test(T)(T t1, T t2){return t1*t2+(t1+t2).LibFunc();}
writeln(Test(10, 20));
writeln(Test(Optional!int(10), Optional!int(20)));
writeln(Test(Optional!int(10), Optional!int()));
Данный код, как и полагается, выводит
500
500
nothing
и естественно все эти игры происходят исключительно во время компиляции и в итоге вырезаются оптимизатором.
Да, всё же D очень хорош, C++ заметно слабее. Ну а C# или Хаскель вообще даже рядом не валялись. )))
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Хы, ну для начала это очередная "встроенная монада" — такое нет смысла обсуждать в нашем контексте.
Не вижу причин не обсуждать. Вы спрашивали "зачем нужны монады" — я вам показываю примеры, зачем нужны монады.
Волшебным образом оказывается, что монады и недомонады встречаются в "обычных языках" и библиотеках на каждом углу.
_>Но что самое интересное, эта самая реализация "как бы лифтинга" как раз совсем не похожа на классическую, а гораздо больше напоминает обычную перегрузку операторов. ))) Т.е. я конечно не в курсе конкретной реализации, но есть подозрение, что там при реализации этих операторов, компилятор не вызывает каждый раз какую-то специальную функцию типа Nullable, а сам напрямую форвардит вызовы в T.
Совершенно верно. Это compiler magic.
_>Если это так, то это уже точно становится не явная монада, а просто некая отдалённо похожая концепция. Типа как исключения и т.п. — это вроде как тоже нечто напоминающее монады.
Совершенно верно. Просто монады предлагают способ прикручивать поддержку исключений, Nullable, async, и прочего без compiler magic.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Эээ, что что? ) Насколько я понимаю, "главный" язык для работы с монадами у нас Хаскель. Так вот в нём компилятор не делает ничего подобного, а надо записывать всё руками.
Жаль. _>Ну для начала, если мы говорим о C++, то скажем все наши функции реализованные в виде шаблонов заработают сами автоматом. )))
Осталось придумать, как реализовать в виде шаблонов функции типа возведения в степень. Желательно так, чтобы они работали и для комплексных чисел тоже.
_>Ну а нешаблонные действительно надо оборачивать в Apply. Так же как и в Хаскеле (только там в bind). И кстати в Хаскеле это единственный вариант, в отличие от C++.
Как я понял, всё же в Хаскеле есть какие-то синтаксические улучшения для монад.
_>Ээээ что что? ) Это в каком языке компилятор так умеет? )
В ограниченном виде query comprehensions в C# делают именно это.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Хы, такими темпами можно дойти до введения "прав доступа" внутри языка. )))
_>Кстати, ООП со своей инкапсуляцией частично пытается решать эту проблему, причём с другой стороны. Не по принципу "проверим что эта функция не лезет куда не надо", а по принципу "код, который лезет куда не надо, нельзя вызвать ниоткуда, кроме спец. предусмотренных мест".
Совершенно верно. Логичным продолжением ограничений является "... ниоткуда, кроме спец. предусмотренных мест, в которые лазить нужно специальным способом".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>Ну для начала, если мы говорим о C++, то скажем все наши функции реализованные в виде шаблонов заработают сами автоматом. ))) S>Осталось придумать, как реализовать в виде шаблонов функции типа возведения в степень. Желательно так, чтобы они работали и для комплексных чисел тоже.
Уже есть в SGI STL: <b>std::power</b>. Работает и для целых, и для вещественных, и для комплексных, и даже для матриц.
Power is generalized exponentiation: it raises the value x to the power n, where n is a non-negative integer.
_>>Ну а нешаблонные действительно надо оборачивать в Apply. Так же как и в Хаскеле (только там в bind). И кстати в Хаскеле это единственный вариант, в отличие от C++. S>Как я понял, всё же в Хаскеле есть какие-то синтаксические улучшения для монад.
Минимальные. Без синтаксических улучшений:
foo a b = a >>= \x ->
b >>= \y ->
return x + y
с do-сахаром:
foo a b = do x <- a
y <- b
return x + y
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Уже есть в SGI STL: <b>std::power</b>. Работает и для целых, и для вещественных, и для комплексных, и даже для матриц.
Не вижу, каким образом оно работает для перечисленного: EP>
EP>Power is generalized exponentiation: it raises the value x to the power n, where n is a non-negative integer.
Важное выделено. Даже в банальную вещественную степень возвести эта штука не сможет.
EP>Минимальные. Без синтаксических улучшений: EP>
EP>foo a b = a >>= \x ->
EP> b >>= \y ->
EP> return x + y
EP>
с do-сахаром: EP>
EP>foo a b = do x <- a
EP> y <- b
EP> return x + y
EP>
Интересно. А при этом с "обычными", немонадными a и b такая запись работает? Ну, то есть можно ли вообще всегда описывать функции в do-нотации, чтобы они работали с произвольными монадами?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Еще один косяк с операциями, возвращающими bool. Например сравнение.
A>
A>if (m > limit)
A> Alert();
A>if (!(m <= limit))
A> Alert();
A>
A>Что тут делать? Если мы определим '>' над optional<> как false, в случае когда o == null, то первая инструкция будет игнорировать null, а вторая сообщать о них.
Да, для bool операций в шарпе лифтинг сделан особенным образом.
A>Т.е. нужно будет об этом задумываться. А если нужно будет задумываться, то когда-нибудь, какой-нибудь разработчик Леша заменит первый вариант на второй (или наоборот) и изменит семантику кода. Вот это тоже КОСЯК.
Я бы заставил лифтед-операции возвращать bool?, который несовместим с "обычным" if-ом. Тогда компилятор мне все такие места сразу сообщит, и заставит руками выписать реакцию на unknown.
Это не так удобно, как в шарпе, зато единообразно — потому, что lifted operator > (IEnumerable<T> left, IEnumerable<T> right) должен вовращать таки IEnumerable<bool>, а не одиночный bool.
A>Товарищи опытные "монадоведы", расскажите плиз, что в таких случаях делать? Сразу хочется работать с монадоми вручную, без компилятора, но тогда монады теряют весь смысл. Единственное, что я смог придумать это принцип: если нужно значение из монады, то получай его явно (т.е. вручную).
Зависит от монады. Если оператор преобразования в базовый тип — implicit, то и хрен бы с ним. А в случаях типа optional или list или ещё чего всё должно быть строго explicit.
ARK>>Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например). A>Я сам ХЗ. Не нужно воспринимать мои коментарии как "эгегей, монады куль, почему никто не использует монады...". Я сам только к ним присматриваюсь (как к новой для меня концепции). A>Аргументы выше, это то, что я сам себе ответил, когда задался таким вопросом.
Здравствуйте, alex_public, Вы писали:
K>>Ну так надо делать не "шаблоны", а нормальный параметрический полиморфизм. _>Чего чего? ) Это в смысле в рантайме?
Не понятно, что вы имеете в виду под "параметрическим полиморфизмом в рантайме" (я дискутировал с носителями самых фантастических представлений на этот счет, так что не провентилировав этот вопрос лучше даже и не начинать обсуждение).
_>Речь шла не про плюсы, а про гипотетический язык с шаблонами, в котором компилятор их полностью проверяет.
В гипотетическом языке можно сделать обязательные концепты и все будет типизировано, при том, что никакой "большой и лишней работы" тайпчекеру делать не придется.
_>Правильно, исходник по которому генерируется код. И только он, а не некие абстрактные исходники.
Под "исходниками по которым генерируется код" вы подразумеваете мономорфный код, сгенерированный по шаблонам? Ну так не нужно страдать ерундой и смешивать недопараметрический недополиморфизм и средства кодогенерации в одно непонятно что. Параметрический полиморфизм должен быть отдельно, а средства кодогенерации — макросы какие-нибудь — отдельно.
_>Я не собираюсь повторяться в третий раз. Даже дважды уже было много. Тем более, что в ответ не услышал даже одного раза.
Два раза много, а ноль раз, как в обсуждаемом случае — недостаточно. Повторяться не нужно — ответте на мои вопросы один раз. Этого будет достаточно.
_>Да да, конечно же совсем не признаёте... http://www.rsdn.ru/forum/philosophy/5407470
Вот об этом я и говорил. Обратите только внимание, что я ругаю околомонадный синтаксис и дурацкие системы именования, но не хвалю какие-то другие языки. Наоборот, рядом я написал следующее:
Я не согласен, что это выглядит намного страшнее, чем в других языках (если не считать упомянутые мной "карательные" наименования, которые легко исправить). Монадический код часто, но не всегда, требует синтаксической обвязки для "стыковки" в отличие от функций вида a -> b в хаскеле, и потому код с мутабельными ссылками/массивами может выглядеть многословнее, чем хаскель-код с иммутабельными. Но в большинстве языков обычно наворочено столько синтаксического мусора без всякого смысла вообще, что на этом фоне и монадический хаскель-код выглядит вполне пристойно. Потому и вопрос — что это за язык такой, по сравнению с которым хаскельный код выглядит намного страшнее.
Т.е. раз у хаскеля нерастраченный на всякую ерунду синтаксический бюджет — какие-то редкие уродства погоды не делают, особенно если сравнивать с языком, сыплющим всюду синтаксический мусор лопатой. Поскольку С++ как раз такой, код на нем даже в тех областях, где он силен смотрится страшнее, чем хаскель-код, демонстрирующий самые неприглядные стороны хаскеля.
Гипотетическую возможность сделать синтаксис лучше, чем в хаскеле я, разумеется, не отрицаю.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Чего ты хочешь объяснить, я уже не понимаю. Большей частью у тебя сравнение query comprehension С# vs императивный код на С++.
_>Вообще всё началось с того, что я попросил знатоков (в том смысле, что применяющих их где-то на практике) монад показать какие-нибудь примеры их полезного использования в мультипарадигменных языках, а не в Хаскеле (в котором без
монад просто тоскливо).
Спирит открой и удивляйся. Я как то не слежу за бустом и С++, а то бы раньше показал этот пример.
_>Насколько я помню, практические единственным реальным примером были как раз твои реактивные монадные парсеры. Из плюсов надо отметить, что это действительно работающий пример. Ну а из минусов (что мы тут и обсуждали) — как мы увидели, тоже самое можно реализовать и без монад, причём частенько и ещё проще. Так что это хотя и был реальный ответ на мой вопрос, но он не стал аргументом в пользу монад.
Promise/Future ты забыл ?
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Интересно. А при этом с "обычными", немонадными a и b такая запись работает? Ну, то есть можно ли вообще всегда описывать функции в do-нотации, чтобы они работали с произвольными монадами?
Чтоб такой код работал с обычными значениями, их придется обернуть в монаду Identity:
-- код был с ошибкой, правильно его записать так:
foo a b = do x <- a
y <- b
return $ x + y
-- или, что то же самое, но идиоматичнее:
foo = liftM2 (+)
-- теперь
runIdentity $ foo (Identity 2) (Identity 40)
-- получаем:
42
Это вполне применяется на практике, к примеру, все операции в пакете vector (это хаскельная библиотека для работы с массивами) монадические, а специализированная, нелифтнутые версии реализуются через монадические, вроде:
map f = mapM (return . f)
Lifted operators в хаскеле вполне реализуются:
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}import Control.Applicative
instance (Applicative f, Num n) => Num (f n) where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
abs = fmap abs
signum = fmap signum
fromInteger = pure . fromIntegral
instance (Applicative f, Fractional n) => Fractional (f n) where
(/) = liftA2 (/)
recip = fmap recip
fromRational = pure . fromRational
Все, теперь у нас арифметика лифтнута в любой аппликативный функтор и мы можем писать на языке j:
>>> 2 + 7 * 8
58
>>> Just 2 + Just 7 * Just 8
Just 58
>>> Just 2 + Nothing * Just 8
Nothing
>>> [1..3] + [7..9] * [11,12]
[78,85,89,97,100,109,79,86,90,98,101,110,80,87,91,99,102,111]
>>> getZipList $ ZipList[1..3] + ZipList[7..9] * ZipList[11..13]
[78,98,120]
-- функции - это тоже функторы и монады:
>>> sum / (fromIntegral . length) $ [1..3] -- вычисляем среднее значение: делим сумму на длину
2.0
Вообще, нормальная работа с функторами/монадами в хаскеле возможна, в основном, не благодаря спецсинтаксису (который как раз страшноватый), а благодаря приличным возможностям для написания полиморфного кода и комбинирования комбинаторов
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет. EP>>Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура). EP>>Чтобы называть монадой, нужно как минимум найти нетривиальный bind. I>Это ничего не меняет
В каком смысле? Ты хочешь называть Spirit монадой, но при этом не можешь показать где там bind (по смыслу)?
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Совершенно верно. Просто монады предлагают способ прикручивать поддержку исключений, Nullable, async, и прочего без compiler magic.
Конечно. Только вот в современных мультипарадигменных языках это всё (и ещё очень много чего) уже есть, причём как раз с полной магией. Т.е. мой вопрос насчёт полезности монад в таких языках по прежнему остаётся в силе...
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Все, теперь у нас арифметика лифтнута в любой аппликативный функтор и мы можем писать на языке j: K>
>>>> 2 + 7 * 8
K>58
>>>> Just 2 + Just 7 * Just 8
K>Just 58
>>>> Just 2 + Nothing * Just 8
K>Nothing
K>
Вот только тут нужны дополнительные оговорки, например:
cделать что-то типа if или PM не получится
foldl (+) 0 a (обсуждаемый выше) для [Maybe a] будет неэффективным
и т.п.
Если же в языке есть полноценный call/cc, то можно делать полноценные монадические вычисления не меняя код.
Подбое возможно например в C++, с помощью Boost.Coroutine — но не для всех типов монад (так как call/cc ограниченный).
Например:
template<template<typename> class M, typename T>
auto operator+(M<T> x, M<T> y)
{
return (await x) + (await y);
}
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Согласен, что в реальности этот код должен поменяться, но мы в философии, поэтому можем пофантазировать. A>Например, предположим, что компилятор сам умеет делать из функции F функцию F* над optional<> аргументами. По принципу: все не null -> вычисляем F, что-то null -> результат null. A>Тогда код Синклера: A>
A>public T DoStuff<T>(List<T> array, T limit) {where T has '*' and '+' and '>'}
A>{
A> var sum = default(T); // вот тут у меня косяк, так как default(optional<T>) вернет null, но, уверен, он решаем
A> for(int i=0; i<array.length(); i++)
A> {
A> if (array[i]*array[i] > limit))
A> sum+=array[i]*array[i];
A> }
A> return sum;
A>}
A>
A>останется без изменений, потому как компилятор (см. выше) сделает нам сложение, умножение и сравнение на optional<> (сравнение по принципу если чт-то null, то false, как в sql).
A>Я, кнечно, могу ошибаться, но я не вижу переколбашивания. Если у T есть сложение, умножение и сравнение, то функция работает. Монада же дает эти операции "на лету" функций над базовым типом.
Это вполне реализуемо в языках с полноценным call-with-current-continuation, то есть код функции будет одинаковым для T, для AnyMonad<T>, etc.
Прямо сейчас это частично реализуемо в C++ на stackful coroutines. "Частично" потому что работает не для всех типов монад.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Осталось придумать, как реализовать в виде шаблонов функции типа возведения в степень. Желательно так, чтобы они работали и для комплексных чисел тоже.
Ну если мы хотим реализовать всё одной функцией, то соответственно у нас должен быть универсальный алгоритм, оптимальный для любых типов. Если же для каких-то типов более оптимален другой алгоритм функции, то для этого в C++ есть явная специализация шаблонов.
S>В ограниченном виде query comprehensions в C# делают именно это.
Ну это вообще другая область. Скорее про лямбды, т.е. типа тех игр, которыми занимается Boost.Phoenix .
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>IQueriable в linq -- типичная монада. A>В зависимости от реализации, она может и коллекцию итерировать, и в базу лезть, и вэбсервис вызывать, ... и эксепшены по делу и нет выкидывать. Это ведь никого не пугает. A>Все, наоборот радуются, что один и тот же код может и "и коллекцию итерировать, и в базу лезть, и вэбсервис вызывать". А все это благодаря концепции Монада.
То что один и тот же код может и по массиву ходить, и данные из базы таскать — это обычная абстракция+полиморфизм, а не монада.
(IQueryable действительно монада, за счёт SelectMany. Но не надо смешивать свойства полиморфизма и монады)
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>>>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет. EP>>>Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура). EP>>>Чтобы называть монадой, нужно как минимум найти нетривиальный bind. I>>Это ничего не меняет
EP>В каком смысле? Ты хочешь называть Spirit монадой, но при этом не можешь показать где там bind (по смыслу)?
В том смысле что функторы спирита мало чем отличается от монад. Для данной беседы эта разница ничтожна.
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
_>и естественно все эти игры происходят исключительно во время компиляции и в итоге вырезаются оптимизатором.
Супер! Но опять-таки, это не полноценные монадические вычисления — if(x > y) не сделать, accumulate по массиву Optional!int будет не оптимальным и т.п. Это больше applicative.
Чтобы это стало полноценной монадой, нужно прикрутить fiber'ы (но этот фокус сработает не для всех типов монад).
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>В каком смысле? Ты хочешь называть Spirit монадой, но при этом не можешь показать где там bind (по смыслу)? I>В том смысле что функторы спирита мало чем отличается от монад. Для данной беседы эта разница ничтожна.
В каком смысле мало отличаются, тем что это тоже математическая структура?
То есть вопрос в том, нужны ли абстрактные структуры/концепции, которые обобщают поведения множества разных объектов?
Конечно же нужны
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>В каком смысле? Ты хочешь называть Spirit монадой, но при этом не можешь показать где там bind (по смыслу)? I>>В том смысле что функторы спирита мало чем отличается от монад. Для данной беседы эта разница ничтожна.
EP>В каком смысле мало отличаются, тем что это тоже математическая структура? EP>То есть вопрос в том, нужны ли абстрактные структуры/концепции, которые обобщают поведения множества разных объектов? EP>Конечно же нужны
Сравнивая с императивным кодом, что монады, что аппликативные функторы это одно и то же.
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
EP>>Уже есть в SGI STL: <b>std::power</b>. Работает и для целых, и для вещественных, и для комплексных, и даже для матриц. S>Не вижу, каким образом оно работает для перечисленного:
Оно работает для любого моноида. Если немного поправить код, и убрать из начала:
if (n == 0)
return identity_element(opr);
то будет работать для любой полугруппы. Нужна всего лишь ассоциативная операция (например умножение матриц или конкатенация строк).
EP>>
EP>>Power is generalized exponentiation: it raises the value x to the power n, where n is a non-negative integer.
S>Важное выделено. Даже в банальную вещественную степень возвести эта штука не сможет.
Для вещественной степени будет больше требований к параметру.
А к чему вообще вопрос про power?
S>Интересно. А при этом с "обычными", немонадными a и b такая запись работает? Ну, то есть можно ли вообще всегда описывать функции в do-нотации, чтобы они работали с произвольными монадами?
Есть несколько вариантов — использовать Identity, как уже сказали выше, либо сделать все не-монады монадами (то есть с тривиальными return и >>=).
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
K>Не понятно, что вы имеете в виду под "параметрическим полиморфизмом в рантайме" (я дискутировал с носителями самых фантастических представлений на этот счет, так что не провентилировав этот вопрос лучше даже и не начинать обсуждение).
Ну так параметрический полиморфизм же может иметь разные реализация, причём даже в рамках одного языка.
Самая эффективная естественно через обобщённое программирование (в случае C++ это шаблоны), т.к. всё отрабатывает на этапе компиляции.
Можно реализовать и в рантайме, через разные указатели на функции/данные (как уже удобно реализованный частный случай этого — ООП полиморфизм). Но это будет намного менее эффективно. Причём естественно не из-за одного лишнего уровня косвенности, а из-за невозможности компилятору заинлайнить это всё. Т.е. например люди не знакомые с этими нюансами и взглянувшие на внутренности скажем Boost'a и код генерируемый по нему были бы в шоке: огромные простыни сложного вложенного кода вырезаются компилятором начисто. А в случае реализации рантайм полиморфизма, это всё придётся оставить в бинарнике и исполнять при каждом вызове...
K>В гипотетическом языке можно сделать обязательные концепты и все будет типизировано, при том, что никакой "большой и лишней работы" тайпчекеру делать не придется.
Кстати про концепты... Они же уже на самом деле давно есть в C++, просто через некоторые "извращения". Но я не вижу какой-то принципиальной пользы от них ни сейчас, ни в удобном варианте.
Вот рассмотрим тот наш конкретный пример (монада в виде шаблонного типа). И предположим, что мы передаём вместо M какой-то неправильный тип, ну например вообще int. ))) В чём будет разница при наличие концептов и без них?
В том моём примере (без концептов), компилятор ругнётся приблизительно так: "шаблон liftM2<int> не может быть применён, т.к. у int не определён оператор >>=".
В случае с концептами компилятор ругнётся как-то типа "шаблон liftM2<int> не может быть применён, т.к. int — это не разновидность Monad".
Ну как бы и в чём существенное преимущество? ) Для меня оба эти сообщения об ошибке звучат приблизительно одинаково. Более того, первый вариант как бы сразу намекает как исправить ошибку.
K>Под "исходниками по которым генерируется код" вы подразумеваете мономорфный код, сгенерированный по шаблонам? Ну так не нужно страдать ерундой и смешивать недопараметрический недополиморфизм и средства кодогенерации в одно непонятно что. Параметрический полиморфизм должен быть отдельно, а средства кодогенерации — макросы какие-нибудь — отдельно.
Кстати говоря, тот факт, что шаблоны C++ можно использовать для довольно эффективного метапрограммирования, является скорее случайным побочным эффектом. А изначально это задумывалось исключительно как средство обобщённого программирования, т.е. как раз для параметрического полиморфизма.
_>>Да да, конечно же совсем не признаёте... http://www.rsdn.ru/forum/philosophy/5407470
)))
K>Вот об этом я и говорил. Обратите только внимание, что я ругаю околомонадный синтаксис и дурацкие системы именования, но не хвалю какие-то другие языки. Наоборот, рядом я написал следующее:
K>Т.е. раз у хаскеля нерастраченный на всякую ерунду синтаксический бюджет — какие-то редкие уродства погоды не делают, особенно если сравнивать с языком, сыплющим всюду синтаксический мусор лопатой. Поскольку С++ как раз такой, код на нем даже в тех областях, где он силен смотрится страшнее, чем хаскель-код, демонстрирующий самые неприглядные стороны хаскеля. K>Гипотетическую возможность сделать синтаксис лучше, чем в хаскеле я, разумеется, не отрицаю.
Так я в общем то и говорил всё время буквально это же самое, только более конкретизировано. Что Хаскель может быть удобнее в одной области и наоборот неудобнее в другой (при работе с внешним миром в частности). Естественно в сравнение с современными императивными языками, которые и заточены на максимальную эффективность во второй области. Ну и соответственно если взглянуть на соотношения размеров этих областей в обычном ПО, то выбор будет совсем не в пользу Хаскеля.
Это если говорить про синтаксис. Кроме этого, были ещё заявлены некоторые особенные возможности Хаскеля, которых нет в других языка, причём как раз в той самой второй области. Если от этих способностей действительно есть какая-то реальная польза на практике (а они не являются просто потребностью самого языка), то возможно вывод предыдущего абзаца следует пересмотреть. Но пока что я не видел ни единого примера на эту тему.
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Совершенно верно. Просто монады предлагают способ прикручивать поддержку исключений, Nullable, async, и прочего без compiler magic.
Да, и кстати... Можно прикручивать подобные вещи и без compiler magic и без монад, используя совсем другие возможности языка. Причём будет получаться гораздо эффективнее явных монад. Вот http://www.rsdn.ru/forum/philosophy/5427522
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP> cделать что-то типа if или PM не получится
Перегрузить все, чтоб немонадический код вообще без переделок делался монадическим конечно не получится. Но какой именно код с if и матчингом нужен?
EP> foldl (+) 0 a (обсуждаемый выше) для [Maybe a] будет неэффективным
Неэффективным по сравнению с чем? Если речь про раннее завершение (short circuit), то в нормальных языках такой проблемы нет как класса:
Здравствуйте, Ikemefula, Вы писали:
I>Спирит открой и удивляйся. Я как то не слежу за бустом и С++, а то бы раньше показал этот пример.
А где ты там монады нашёл? ) С большой натяжкой можно говорить об аппликативный функторах, и то сомнительно, т.к. значение над которым они все работают ни во что такое не упаковано. Это больше напоминает просто некое дерево функций.
I>Promise/Future ты забыл ?
Это в каком языке? )
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так параметрический полиморфизм же может иметь разные реализация, причём даже в рамках одного языка.
Может, конечно. Но я сейчас не о том, что может быть, а о том как это себе представляют.
_>Самая эффективная естественно через обобщённое программирование (в случае C++ это шаблоны), т.к. всё отрабатывает на этапе компиляции.
Что в данном случае понимается под "обобщенное программирование"? Кодогенерация?
_>Можно реализовать и в рантайме, через разные указатели на функции/данные (как уже удобно реализованный частный случай этого — ООП полиморфизм). Но это будет намного менее эффективно.
Вы смешиваете диспетчеризацию, которая может быть времени компиляции (как в случае параметрического полиморфизма с ограниченной квантификацией) и времени выполнения (как в случае экзистенциальных типов и виртуальных методов) и реализацию универсальной квантификации. Это, к сожалению, типичный случай. Давайте это как-нибудь разделим и обсудим поочередно или что-то одно, что вам интереснее.
_>Причём естественно не из-за одного лишнего уровня косвенности, а из-за невозможности компилятору заинлайнить это всё.
Вы всерьез считаете, что реализации параметрического полиморфизма для хаскеля или там sml не делают специализации и инлайна? Но в этом случае такая реализация была бы полностью бесполезна (из-за тормозов). Практичных подход заключается в том, чтоб программист мог сам выбирать трейдофф между скоростью работы скомпилированного кода и степенью раздельности компиляции. Т.е. сколько и каких разверток функций попадает в интерфейсный файл, чтоб потом специализировать/заинлайнить обобщенный код. Это проблема вполне решаемая и даже решенная.
_>Кстати про концепты... Они же уже на самом деле давно есть в C++, просто через некоторые "извращения". Но я не вижу какой-то принципиальной пользы от них ни сейчас, ни в удобном варианте.
_>Вот рассмотрим тот наш конкретный пример (монада в виде шаблонного типа). И предположим, что мы передаём вместо M какой-то неправильный тип, ну например вообще int. ))) В чём будет разница при наличие концептов и без них?
Смысл в том, чтоб обнаруживать ошибки до того, как какой-то конкретный int вообще откуда-то появится.
_>Кстати говоря, тот факт, что шаблоны C++ можно использовать для довольно эффективного метапрограммирования, является скорее случайным побочным эффектом. А изначально это задумывалось исключительно как средство обобщённого программирования, т.е. как раз для параметрического полиморфизма.
Это говорит только о сильно нетрадиционном понимании параметрического полиморфизма изобретателем шаблонов для плюсов и тем, что для прототипирования такой системы использовался кодогенератор-"шаблонизатор".
K>>у хаскеля нерастраченный на всякую ерунду синтаксический бюджет — какие-то редкие уродства погоды не делают, особенно если сравнивать с языком, сыплющим всюду синтаксический мусор лопатой. Поскольку С++ как раз такой, код на нем даже в тех областях, где он силен смотрится страшнее, чем хаскель-код, демонстрирующий самые неприглядные стороны хаскеля.
_>Так я в общем то и говорил всё время буквально это же самое, только более конкретизировано. Что Хаскель может быть удобнее в одной области и наоборот неудобнее в другой (при работе с внешним миром в частности). Естественно в сравнение с современными императивными языками, которые и заточены на максимальную эффективность во второй области. Ну и соответственно если взглянуть на соотношения размеров этих областей в обычном ПО, то выбор будет совсем не в пользу Хаскеля. _>Это если говорить про синтаксис.
Нет, это не то же самое, а противоположное. Перечитайте мое сообщение. Я пишу не о том, что код синтаксически лучше выглядит в какой-то другой области, а о том, что даже тот самый код, про который вы говорите "весь в большой монаде", если я, конечно, правильно понял, что вы имели в виду, синтаксически лучше, чем код на типичном императивном языке, синтаксис которого как будто придуман, чтоб покарать любого, кто захочет на этом языке что-то написать, не говоря уж о том, чтоб прочесть.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>> cделать что-то типа if или PM не получится K>Перегрузить все, чтоб немонадический код вообще без переделок делался монадическим конечно не получится.
Получается что языки с сall-with-current-continuation в этом месте мощнее — можно обычный код сделать монадическим не меняя его.
K>Но какой именно код с if и матчингом нужен?
Да хотя бы:
f a = if a == 5 then"foo"else"bar"
допустим придёт IO Int.
EP>> foldl (+) 0 a (обсуждаемый выше) для [Maybe a] будет неэффективным K>Неэффективным по сравнению с чем? Если речь про раннее завершение (short circuit), то в нормальных языках такой проблемы нет как класса:
Я думаю можно сделать пример монады, где это не сработает (например добавить счётчик во внутрь монады, но нужно проверить законы моноида).
K>
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Супер! Но опять-таки, это не полноценные монадические вычисления — if(x > y) не сделать, accumulate по массиву Optional!int будет не оптимальным и т.п. Это больше applicative.
Ага. Я как раз это и демонстрирую, что задача решается эффективно и без монад.
Насчёт x>y мне кажется, что и не должно автоматом работать с монадой, потому как совершенно непонятно что тут должно происходит в реальном коде. Вот например для optional что там делать? Скорее такой код всё же надо править и как самый простейший вариант — обернуть в лямбду соответствующий кусок кода.
А что касается accumulate, то это как раз без проблем. Для этого в D надо просто перегрузить ещё один оператор для Optional: opAssign(string op)(r).
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Спирит открой и удивляйся. Я как то не слежу за бустом и С++, а то бы раньше показал этот пример.
_>А где ты там монады нашёл? ) С большой натяжкой можно говорить об аппликативный функторах, и то сомнительно, т.к. значение над которым они все работают ни во что такое не упаковано. Это больше напоминает просто некое дерево функций.
Вот это "просто дерево функций" это без пяти минут монада. Что бы это стало полноценной монадо, всё что надо, это дописать две функции и по другому связывать. Все функции будут устроены ровно так же, один к одному.
При желании, описании грамматики ты сможешь сделать через эти функции, только смысла в этом мало, потому что нет поддержки со стороны компилятора.
I>>Promise/Future ты забыл ?
_>Это в каком языке? )
Во всех сразу. Пример тебе приводили.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>Супер! Но опять-таки, это не полноценные монадические вычисления — if(x > y) не сделать, accumulate по массиву Optional!int будет не оптимальным и т.п. Это больше applicative.
_>Ага. Я как раз это и демонстрирую, что задача решается эффективно и без монад.
"без монад" в данном случае означает структуру, которую до монады можно допилить ровно двумя функциями. Изначально у тебя "без монад" это просто императивный код.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
K>>Перегрузить все, чтоб немонадический код вообще без переделок делался монадическим конечно не получится. EP>Получается что языки с сall-with-current-continuation в этом месте мощнее — можно обычный код сделать монадическим не меняя его.
Реальный язык или гипотетический?
EP>Да хотя бы: EP>
EP>f a = if a == 5 then"foo"else"bar"
EP>
допустим придёт IO Int.
Вообще-то if then else синаксис перегружаемый. На практике, правда, перегружать его никто не будет, да и вообще уместность его (if-a) применения в хаскеле достаточно спорная. Там скорее какой-нибудь комбинатор по случаю используют, который лифтится. Более серьезна проблема с ПМ, но и паттерн-матчинг — инструмент очень низкоуровневый, который лучше запереть в каком-нибудь комбинаторе.
EP>Я думаю можно сделать пример монады, где это не сработает (например добавить счётчик во внутрь монады, но нужно проверить законы моноида).
Если монада в принципе раннее завершение не поддерживает — конечно это работать не будет. Но весь смысл Maybe, в общем-то, в раннем завершении. Зачем она иначе нужна-то?
другой пример:
прибавляем двойку ко всем натуральным числам, смотрим первые пять получившихся:
Prelude Control.Applicative> take 5 $ 2 + [1..]
[3,4,5,6,7]
Монада List без раннего завершения тоже, в основном, бесполезная.
Они предназначены для того, чтоб комбинировать комбинаторы и получать в результате полезные функции. Без таких возможностей комбинации функций будут принципиально ущербными (на что вы сами и указали), ведь ручное их слияние всегда будет работать лучше. Естественно, получать бесполезные функции особого смысла нет, так что в энергичных языках комбинирование комбинаторов обычно сразу незадается.
EP>А как именно это реализовано (мемоизация, etc?) и есть ли гарантия этой оптимизации?
Это называется нормальный порядок редукции. Вовсе никакая не оптимизация. Я скопировал результаты из интерпретатора, а там оптимизаций нет. Оптимизация это как раз аппликативный порядок вычислений, когда для упрощения реализации идут на то, чтоб некий класс программ не работал вообще или работал плохо. Приведенный пример как раз из вторых. Если бы список был бесконечным — был бы вообще нерабочий (зацикливающийся).
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
В C++ это шаблоны, в Java generics и т.п..
K>Вы смешиваете диспетчеризацию, которая может быть времени компиляции (как в случае параметрического полиморфизма с ограниченной квантификацией) и времени выполнения (как в случае экзистенциальных типов и виртуальных методов) и реализацию универсальной квантификации. Это, к сожалению, типичный случай. Давайте это как-нибудь разделим и обсудим поочередно или что-то одно, что вам интереснее.
Естественно речь про диспетчеризацию, т.к. именно она определяет эффективность (в смысле быстродействия).
K>Вы всерьез считаете, что реализации параметрического полиморфизма для хаскеля или там sml не делают специализации и инлайна? Но в этом случае такая реализация была бы полностью бесполезна (из-за тормозов). Практичных подход заключается в том, чтоб программист мог сам выбирать трейдофф между скоростью работы скомпилированного кода и степенью раздельности компиляции. Т.е. сколько и каких разверток функций попадает в интерфейсный файл, чтоб потом специализировать/заинлайнить обобщенный код. Это проблема вполне решаемая и даже решенная.
Я правильно понимаю, что нормальная оптимизация происходит только при условии, что обобщённый код и использующего его код находятся в одной единице компиляции?
Если да, то получается что никаких отличий от C++ нет — те же самые два варианта: нормальная оптимизация/совместная компиляция и плохая оптимизация/раздельная компиляция.
K>Смысл в том, чтоб обнаруживать ошибки до того, как какой-то конкретный int вообще откуда-то появится.
Ну так это тогда уже не к концептам и т.п., а к вообще другому языку, даже не знаю какому. Т.к. в языках с шаблонной техникой, шаблоны не трогаются пока они не используются.
K>Это говорит только о сильно нетрадиционном понимании параметрического полиморфизма изобретателем шаблонов для плюсов и тем, что для прототипирования такой системы использовался кодогенератор-"шаблонизатор".
Лично я считаю, что из всех существующих концепций в программирование, метапрограммирование — это наиболее сильный инструмент с любых точек зрения. И развивать в языке надо прежде всего его. Например C++ хорошо бы подтянуть хотя бы до уровня языка D.
K>Нет, это не то же самое, а противоположное. Перечитайте мое сообщение. Я пишу не о том, что код синтаксически лучше выглядит в какой-то другой области, а о том, что даже тот самый код, про который вы говорите "весь в большой монаде", если я, конечно, правильно понял, что вы имели в виду, синтаксически лучше, чем код на типичном императивном языке, синтаксис которого как будто придуман, чтоб покарать любого, кто захочет на этом языке что-то написать, не говоря уж о том, чтоб прочесть.
Ага, но саму разницу внутри Хаскеля тоже прекрасно ощущаете... Т.е. у нас одинаковое понимание пока мы смотрим только на Хаскель и разное, когда начинаем сравнивать его с другими языками.
Касательно сравнения монадного кода Хаскеля и кода на современных императивных языках. На мой взгляд тут довольно просто провести сравнение. Ведь если не вводить кучу уровней абстракции (а всё равно нижний уровень придётся писать), то подобный код сводится к последовательности вызовов некого системного API. Так вот на императивных языках это прямо буквально так и записывается. Ну а на монадах Хаскеля это записывается аналогично, плюс ещё некий набор ритуальных плясок... Разве не очевидно, какой вариант лучше? )
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Вот это "просто дерево функций" это без пяти минут монада. Что бы это стало полноценной монадо, всё что надо, это дописать две функции и по другому связывать. Все функции будут устроены ровно так же, один к одному.
Да, можно сделать подобную монаду. Но, как видишь, в Спирите это не сделано, т.к. задача эффективно решается и без этого. )
I>Во всех сразу. Пример тебе приводили.
Ну если например взглянуть на C++11, то там future не является монадой. Это всего лишь контейнер с методом get. Так что опять же живём без всяких монад. Вот в будущем, где вроде бы планируют добавить в future функцию then, возможно и получится классическая монада... Но пока ничего такого нет.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>"без монад" в данном случае означает структуру, которую до монады можно допилить ровно двумя функциями. Изначально у тебя "без монад" это просто императивный код.
Хыхы) Ну да, можно допилить этот код до монады. Но!
1. Как видишь он эффективно решает задачу и без этого.
2. Он делает вещи, которые собственно монадам не по силам.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Эммм, это как бы снова не то, что я спрашивал. ))) Ну да ладно. )
Более четкая формулировка вопроса поможет лучше понять его.
_>Я так понимаю, это пожелание иметь "чистые функции" в языке?
Чистые функции. First class effects. Whatever. К проблеме можно подойти по разному и решать по разному в разных языках.
_>Да, в C++ они действительно только административно вводятся. А вот например в языке D они есть (причём за этот факт ничем расплачиваться не надо), но я что-то не видел особых чудес от этого.
Чудес и не надо. А в моем примере они меня спасут от целого класса ошибок.
_>Ну начнём с того, что мы изначально здесь рассматриваем довольно узкий случай, когда "ValidateEvent" нельзя отделить от "ProcessEvent". Т.к. в противном случае мы для этой задачки просто берём какую-нибудь библиотечку конечных автоматов
1. Отделить можно, но очень сложно.
2. Это вовсе не узкий случай, все зависит от бизнес-логики. В конечном итоге мы стремимся записать решение задачи в терминах предметной области наиболее прямолинейным образом. Если это не подразумевает простой возможности отделения валидации от обработки, значит мы должны обойтись без нее.
3. О конечности числа состояний речи не было.
Однако желание свести все к конечному автомату при реализации на С++ понять можно — при простом решении в лоб, приведенном выше, уже накладные расходы на обеспечение иммутабельности State при очень сложном State непрактичны. Как бы я это делал на С++ — ума не приложу, но я и не знаток С++. Кончено, нужны совсем другие техники, но мне сложно представить, что решение может быть проще (короче и очевидней), чем то, что я использую.
_>>А в хаскелле и то и другое не проблема.
_>Пока что не увидел нигде реальных примеров этого.
А чем плох мой пример? хаскелл решает обе мои проблемы совершенно тривиальным образом. (Собственно монада IO — пример такого решения, с единственной разницей что в моем случае я должен аккумулировать эффекты, а не применять их сразу же — но это уже детали реализации моей условной монады Effects, а использование аналогично).
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
EP>>Супер! Но опять-таки, это не полноценные монадические вычисления — if(x > y) не сделать, accumulate по массиву Optional!int будет не оптимальным и т.п. Это больше applicative. _>Ага. Я как раз это и демонстрирую, что задача решается эффективно и без монад. _>Насчёт x>y мне кажется, что и не должно автоматом работать с монадой, потому как совершенно непонятно что тут должно происходит в реальном коде. Вот например для optional что там делать? Скорее такой код всё же надо править и как самый простейший вариант — обернуть в лямбду соответствующий кусок кода.
Вот именно — нужно завернуть остаток кода в continuation, тогда всё заработает без изменений.
Представь что у optional есть .then (блокирующий). Тогда задача решается простым await'ом (на stackful coroutine):
operator bool()
{
return await *this;
}
Только для optional есть один момент — если будет Nothing, то продолжение не вызовется, но стэк-то надо раскрутить. Придётся бросить исключение, что убивает всю идею Maybe.
Другой недостаток — продолжение нельзя вызвать несколько раз. Это например используется в List Monad.
В D кстати есть фиберы в std.
_>А что касается accumulate, то это как раз без проблем. Для этого в D надо просто перегрузить ещё один оператор для Optional: opAssign(string op)(r).
Это никак не поможет. Проблема в том, что мы должны остановится как только встретим первое Nothing. Если просто лифтить операторы — то никакого останова не будет (если конечно оптимизатор не додумается), и Nothing'и будут продолжать складываться.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>>>Перегрузить все, чтоб немонадический код вообще без переделок делался монадическим конечно не получится. EP>>Получается что языки с сall-with-current-continuation в этом месте мощнее — можно обычный код сделать монадическим не меняя его. K>Реальный язык или гипотетический?
Реальный — Scheme. "Гипотетический" — Unlambda.
EP>>Да хотя бы: EP>>
EP>>f a = if a == 5 then"foo"else"bar"
EP>>
допустим придёт IO Int. K>Вообще-то if then else синаксис перегружаемый. На практике, правда, перегружать его никто не будет,
Ок, не знал.
K>да и вообще уместность его (if-a) применения в хаскеле достаточно спорная. Там скорее какой-нибудь комбинатор по случаю используют, который лифтится. K>Более серьезна проблема с ПМ, но и паттерн-матчинг — инструмент очень низкоуровневый, который лучше запереть в каком-нибудь комбинаторе.
Это всё понятно — но это другой вопрос.
EP>>Я думаю можно сделать пример монады, где это не сработает (например добавить счётчик во внутрь монады, но нужно проверить законы моноида). K>Если монада в принципе раннее завершение не поддерживает — конечно это работать не будет. Но весь смысл Maybe, в общем-то, в раннем завершении. Зачем она иначе нужна-то?
Я имел ввиду делать раннее завершение и считать сколько раз пытались вытащить Nothing. Монадический fold остановится, а обычный должен будет пройтись по всем значениям.
EP>>А как именно это реализовано (мемоизация, etc?) и есть ли гарантия этой оптимизации? K>Это называется нормальный порядок редукции. Вовсе никакая не оптимизация. Я скопировал результаты из интерпретатора, а там оптимизаций нет.
Как порядок вычислений здесь поможет?
Вот есть:
((a+b)+c)
^^^ результат Nothing
второй лифтанутый (+) не должен быть вызван.
Как именно это реализуется внутри, и есть ли гарантия?
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Во всех сразу. Пример тебе приводили. _>Ну если например взглянуть на C++11, то там future не является монадой. Это всего лишь контейнер с методом get. Так что опять же живём без всяких монад. Вот в будущем, где вроде бы планируют добавить в future функцию then, возможно и получится классическая монада... Но пока ничего такого нет.
Кстати, в Boost.Thread у future есть .then — я его использовал для реализации await (хотя там не обязательно привязываться к конкретному типу future, можно сделать customiztion point).
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Конечно. Только вот в современных мультипарадигменных языках это всё (и ещё очень много чего) уже есть, причём как раз с полной магией. Т.е. мой вопрос насчёт полезности монад в таких языках по прежнему остаётся в силе...
А, я понял, простите за тупизну.
Фактически вы противопоставляете встроенное расширяемому. То есть, что лучше — встраивать популярные монады прямо в язык, или научить язык работать с любыми монадами, а потом реализовывать плюшки библиотеками.
Ответ зависит от нетехнических факторов. Нужно понимать, что во времена юности С++ вопрос "чем в современных языках расчётов (читай 'Фортран') могут быть полезны ваши Объекты. Тип complex у нас уже есть, и как раз с полной магией" был вполне себе в силе. То есть, Бъярни выбрал расширяемость вместо встроенности.
А вот Хейльсберг в С# всегда занимал консервативную позицию: "мы улучшаем не фичи, а сценарии". То есть, если у пользователей языка есть конкретная проблема, то команда выбирает такой дизайн, который хорошо решает именно эту задачу, а не универсальный ответ на множество несвязанных задач. Характерный пример — оператор infoof, который должен был возвращать метаданные по мемберу (аналог typeof(typename)), только для методов, свойств, событий, и полей). Типичные сценарии, который хотелось решить с его помощью — реализация INotifyPropertyChanged так, чтобы гарантировать корректное имя свойства в аргументах, и логгирование вызовов, чтобы гарантировать корректное имя текущего метода или свойства. В итоге вместо всемогущего инфуфа (реализация которого создаёт больше проблем, чем решает), прикрутили атрибут CallerMemberName, применяемый к параметрам.
Моё мнение такое, что должны быть и те и другие языки. В том смысле, что для обкатки полезных идей нужен язык, в котором можно добавить более-менее всё, что угодно; а уже потом зарекомендовавшие себя идеи можно переносить в мейнстрим, где важнее обеспечить плавную кривую обучения и обложить всё внятными сообщениями компилятора.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну если мы хотим реализовать всё одной функцией, то соответственно у нас должен быть универсальный алгоритм, оптимальный для любых типов. Если же для каких-то типов более оптимален другой алгоритм функции, то для этого в C++ есть явная специализация шаблонов.
Не, мы хотим одним махом обработать все функции вида power, определённые для типа T, залифтив их к типу anything<T>. _>Ну это вообще другая область. Скорее про лямбды, т.е. типа тех игр, которыми занимается Boost.Phoenix .
Ну там от монад только SelectMany. Тем не менее, он есть, а его конкретная семантика определяется стандартным алгоритмом выбора перегрузки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
то будет работать для любой полугруппы.
Не будет, т.к. убрав код, вы внесёте ошибку.
EP>Нужна всего лишь ассоциативная операция (например умножение матриц или конкатенация строк).
EP>>>
EP>>>Power is generalized exponentiation: it raises the value x to the power n, where n is a non-negative integer.
S>>Важное выделено. Даже в банальную вещественную степень возвести эта штука не сможет. EP>Для вещественной степени будет больше требований к параметру.
Вы, по-моему, не понимаете вопроса. Вы как собираетесь возводить, скажем, число 1.5 в степень -i*Pi, при помощи этой функции?
Или хотя бы в степень 0.5?
EP>А к чему вообще вопрос про power?
К тому, что рассчитывать на то, что power волшебным образом заработает с optional<double>, не стоит. То есть работа должна быть сделана на стороне optional, а не на стороне power.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Да, и кстати... Можно прикручивать подобные вещи и без compiler magic и без монад, используя совсем другие возможности языка. Причём будет получаться гораздо эффективнее явных монад. Вот http://www.rsdn.ru/forum/philosophy/5427522
пример подобного.
Если я правильно понял, то "без монад" ничего не получится, т.к. не всякую функцию можно использовать в качестве bind.
То есть вы предлагаете использовать монады, не используя термин "монады".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Вот это "просто дерево функций" это без пяти минут монада. Что бы это стало полноценной монадо, всё что надо, это дописать две функции и по другому связывать. Все функции будут устроены ровно так же, один к одному.
_>Да, можно сделать подобную монаду. Но, как видишь, в Спирите это не сделано, т.к. задача эффективно решается и без этого. )
Это не важно, главное что монада и такой вот функтор в языке без поддержки монад есть практически одно и то же. Более того, такой метод есть уже в спирите, даже целых несколько, например binary_operator::eval или unary_operator::eval
Собственно как то иначе сделать спирит будет затруднительно, парсер-комбинаторы сами по себе монадические до безобразия. Парсеры комбинаторы без монад всё равно что промисы без метода then
I>>Во всех сразу. Пример тебе приводили.
_>Ну если например взглянуть на C++11, то там future не является монадой. Это всего лишь контейнер с методом get. Так что опять же живём без всяких монад. Вот в будущем, где вроде бы планируют добавить в future функцию then, возможно и получится классическая монада... Но пока ничего такого нет.
Промисы у которых всегда есть метод then не в счёт ?
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>1. Как видишь он эффективно решает задачу и без этого. _>2. Он делает вещи, которые собственно монадам не по силам.
Это чтото очень интересное и я шота не пойму, какие вещи не под силу монадам ? В твоём любимом С++ все до одной фичи которые тебе нравятся, это монады встроеные в язык. И этим монадам, оказывается, чтото не под силу
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
_>>Ну если например взглянуть на C++11, то там future не является монадой. Это всего лишь контейнер с методом get. Так что опять же живём без всяких монад. Вот в будущем, где вроде бы планируют добавить в future функцию then, возможно и получится классическая монада... Но пока ничего такого нет.
EP>Кстати, в Boost.Thread у future есть .then — я его использовал для реализации await (хотя там не обязательно привязываться к конкретному типу future, можно сделать customiztion point).
Шота сиплюсники путаются в показаниях Если then есть у future, то это уже гарантировано монанднее некуда.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Получается что языки с сall-with-current-continuation в этом месте мощнее — можно обычный код сделать монадическим не меняя его. EP>Реальный — Scheme. "Гипотетический" — Unlambda.
И вы можете такую "монадизацию" существующего кода без его изменения проиллюстрировать примером?
EP>Я имел ввиду делать раннее завершение и считать сколько раз пытались вытащить Nothing. Монадический fold остановится, а обычный должен будет пройтись по всем значениям.
Ничего не понял. Что за обычный и монадический фолды? Почему один остановится, а другой нет?
EP>Как порядок вычислений здесь поможет? EP>Вот есть: EP>
EP>((a+b)+c)
EP> ^^^ результат Nothing
EP>
второй лифтанутый (+) не должен быть вызван. EP>Как именно это реализуется внутри, и есть ли гарантия?
Скобки у вас не там. Свертка-то правая.
foldr (+) 0 [a..z]
= {foldr (+) 0 (a:as) = a + foldr (+) 0 as}
a + (b + (c ... + 0))
= {(+) = liftM2 (+)}
liftM2 (+) a (b + (c ... + 0))
= {liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b}
a >>= \a -> (b + (c ... + 0)) >>= \b -> a + b
= {a = Nothing} -- и вот у нас попадается NothingNothing >>= \a -> (b + (c ... + 0)) >>= \b -> a + b
= {Nothing >>= _ = Nothing} -- вот здесь, например, нормальный порядок
-- позволяет не считать все остальное. При аппликативном порядке все, что
-- передается в функцию, вычисляется перед ее вызовом, так что вычислять
-- придется до посинения.Nothing
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Что в данном случае понимается под "обобщенное программирование"? Кодогенерация? _>В C++ это шаблоны, в Java generics и т.п..
Тогда непонятно, что означают слова "параметрический полиморфизм же может иметь разные реализация, причём даже в рамках одного языка. Самая эффективная естественно через обобщённое программирование". Параметрический полиморфизм, получается, один из инструментов обобщенного программирования (наряду с мл-ными функторами и т.д.), что означает его реализация через обобщенное программирование тогда.
_>Естественно речь про диспетчеризацию, т.к. именно она определяет эффективность (в смысле быстродействия).
На быстродействие влияет и то и другое. Диспетчеризация в рантайме не позволяет заинлайнить функцию из словаря, например, (ну, если только у нас не какой-нибудь трассирующий JIT), а параметрический код в одной версии для указателей заставляет все боксить.
_>Я правильно понимаю, что нормальная оптимизация происходит только при условии, что обобщённый код и использующего его код находятся в одной единице компиляции?
Нет. Одна единица компиляции (модуль, например) компилируется в объектный файл и интерфейсный файл, содержащий развертки (код из модуля в той или иной степени прекомпиляции, сериализованное аст, например — ну, не важно). Никаких разверток в файле может вообще не быть — никаких межмодульных оптимизаций тогда не будет, компиляция полностью раздельная. Допустим, что компилировали мы с -O0, для ускорения компиляции во время разработки. Теперь мы хотим получить итоговую версию, и компилируем с -O2 в интерфейсных файлах теперь гораздо больше разверток, а компилятор не стесняется их использовать, когда компилирует зависимые модули. Разумеется, компиляция теперь не полностью раздельная, требует больше времени, но зато есть инлайн и специализация. Противоположная крайность такого подхода, когда весь код всех компилируемых модулей программы оказывается в развертках в интерфейсных файлах — теперь никакой раздельной компиляции нет, есть полнопрограммный анализ, естественно, чудовищно медленный, зато дающий на выходе самый быстрый код.
_>Если да, то получается что никаких отличий от C++ нет — те же самые два варианта: нормальная оптимизация/совместная компиляция и плохая оптимизация/раздельная компиляция.
Из описанного выше, думаю, понятно, что вариантов не два а сколько угодно.
K>>Смысл в том, чтоб обнаруживать ошибки до того, как какой-то конкретный int вообще откуда-то появится. _>Ну так это тогда уже не к концептам и т.п., а к вообще другому языку, даже не знаю какому. Т.к. в языках с шаблонной техникой, шаблоны не трогаются пока они не используются.
Ну да, "шаблоны не трогаются" а дженерики, параметризуемые модули и т.д. наоборот, проверяются и типизируются. В известно каких языках — всех, кроме C++ и его клонов.
_>Лично я считаю, что из всех существующих концепций в программирование, метапрограммирование — это наиболее сильный инструмент с любых точек зрения. И развивать в языке надо прежде всего его. Например C++ хорошо бы подтянуть хотя бы до уровня языка D.
Я согласен, что метапрограммирование надо развивать, речь не про развитие, а про путаницу, развитию не способствующую.
_>Ага, но саму разницу внутри Хаскеля тоже прекрасно ощущаете...
Ну, это было бы довольно странно, если бы код, который что-то делал, выглядел так же просто, как код, который этого не делает — это означает только, что есть очевидные пути для улучшения этого не делающего того же кода.
_>Касательно сравнения монадного кода Хаскеля и кода на современных императивных языках. На мой взгляд тут довольно просто провести сравнение. Ведь если не вводить кучу уровней абстракции (а всё равно нижний уровень придётся писать), то подобный код сводится к последовательности вызовов некого системного API. Так вот на императивных языках это прямо буквально так и записывается. Ну а на монадах Хаскеля это записывается аналогично, плюс ещё некий набор ритуальных плясок... Разве не очевидно, какой вариант лучше? )
Непонятно, почему это нужно рассматривать случай, в котором куча абстракций не вводится? Тогда в языках вроде хаскеля вообще смысла нет, потому что в них все оптимизировано именно для облегчения построения таких абстракций. Именно для этого существуют, в числе прочего, и то, что вы называете "ритуальными плясками". Если же слои абстракций возводить не нужно, то и языки программирования, кроме самых примитивных не нужны, а различия между ними не существенны. Нужны и существенны только прилежание и усидчивость.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
то будет работать для любой полугруппы. S>Не будет, т.к. убрав код, вы внесёте ошибку.
Это будет не ошибка, а precondtition: n > 0
EP>>Нужна всего лишь ассоциативная операция (например умножение матриц или конкатенация строк). EP>>>>
EP>>>>Power is generalized exponentiation: it raises the value x to the power n, where n is a non-negative integer.
S>>>Важное выделено. Даже в банальную вещественную степень возвести эта штука не сможет. EP>>Для вещественной степени будет больше требований к параметру. S>Вы, по-моему, не понимаете вопроса. Вы как собираетесь возводить, скажем, число 1.5 в степень -i*Pi, при помощи этой функции? S>Или хотя бы в степень 0.5?
С помощью этой — естественно никак, она слишком общая. У неё мало требований к аргументу, поэтому и степень натуральная.
Если будет обобщённая функция для возведения в вещественную степень, или в комплексную — то и требований будет больше.
EP>>А к чему вообще вопрос про power? S>К тому, что рассчитывать на то, что power волшебным образом заработает с optional<double>, не стоит. То есть работа должна быть сделана на стороне optional, а не на стороне power.
А, то есть вопрос про liftA2? Выше уже был пример лифтинга в C++.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Кстати, в Boost.Thread у future есть .then — я его использовал для реализации await (хотя там не обязательно привязываться к конкретному типу future, можно сделать customiztion point). I>Шота сиплюсники путаются в показаниях Если then есть у future, то это уже гарантировано монанднее некуда.
В C++11 std::future нету .then, там есть только блокирующий get. Есть boost::future, к которому добавили .then (afaik, после выхода C++11).
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Кстати, в Boost.Thread у future есть .then — я его использовал для реализации await (хотя там не обязательно привязываться к конкретному типу future, можно сделать customiztion point). I>>Шота сиплюсники путаются в показаниях Если then есть у future, то это уже гарантировано монанднее некуда.
EP>В C++11 std::future нету .then, там есть только блокирующий get. Есть boost::future, к которому добавили .then (afaik, после выхода C++11).
И что это меняет ?
Re[18]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали: K>>Да, собственно, всего. Там даже Upward Funarg Problem не решена. EP>Всё решено.
Смелое заявление. А подтверждение этому какое-нибудь есть?
Скрытый текст
Это шутка, на самом деле, никакого практичного решения этой проблемы кроме точного, уплотняющего кучу ГЦ с поколениями пока не придумали, а такого в C++ никогда не будет по понятным причинам. Так что просил подтверждение я, разумеется, не всерьез.
EP>Сборщик мусора пытается управлять только памятью, да и то возможны утечки. Если же брать управление ресурсами в общем — то и C# и Haskell сливают C++. EP>Например попробуй сделать аналог: EP>
EP>auto foo()
EP>{
EP> auto x = 5;
EP> ofstream f("log.txt");
EP> auto y = make_shared<Foo>(11);
EP> return [f=move(f), =](auto z)
EP> {
EP> f << z << endl;
EP> return x + y->data;
EP> };
EP>}
EP>int main()
EP>{
EP> cout << foo()("OMG!");
EP>}
EP>
В языках с ГЦ для детерминированного освобождения используются всякие брекеты вроде using
let foo () =
let x = 5
use file = new Movable<_>(System.IO.File.CreateText(@"d:\log.txt"))
(*failwith "BANG!" //тут ресурс будет освобожден детерминированно *)let y = 11
let file = file.Move()
(* failwith "BANG!" //а тут сборщиком мусора *)fun s -> use f = file
(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f.Write(s + "!")
x + y
printfn "%d" <| foo () "OMG"
EP> Как только замыкание выходит из scope файл закрывается и Foo освобождается.
Звучит довольно бессмысленно. Во первых, тут владение открытым файлом передается в функцию, которую вы называете "замыканием", хотя замыкание это сомнительное. В общем-то смысл замыкания как раз в продлении жизни скоупа из которого оно уходит. Так что замыкание и решение UFP — это работающий [&], а не копирование. При сколько нибудь существенном использовании ФП вы устанете ждать, пока там что-то копируется, да и смысл замыкания часто именно в том, чтоб разные функции ушедшие из одного скоупа впоследствии работали друг с другом через замыкание на него. Т.е. в большинстве практически полезных случаев придется использовать тормозные и замусоривающие код умные указатели со счетчиками. Не говоря уж о том, что в ФП циклические ссылки в порядке вещей. Ну так вот, в эту функцию владение передается и файл закрывается после того, как эта функция отработала. Все верно?
Вообще говоря, тут утечка ресурса. Никакого практического смысла возвращать функцию и тут же ее использовать нет. На практике функция будет болтаться в памяти как часть какого-то замыкания или структуры данных, хранящих функции и возможно вовсе никогда не будет вызвана. Т.е. момент ее выполнения будет определен динамически, ни о каком детерминированном высвобождении ресурса тут речи не идет. Поэтому, за захват ресурса в замыкание и отправление этого замыкания в свободное плавание неплохо бы бить канделябром. Более-менее осмысленное решение, это делать функцию вида ЭтоНамНадоЧтобПолучитьРесурс -> (ОткрытыйРесурс -> Результат) -> Результат, которая сначала собирает через второй аргумент функции, которые что-то будут с ресурсом делать, а потом выполняется сама, открывая ресурс, скармливая всем этим функциям и закрывая его. Т.е. те самые брекеты и их развитие вроде pipes-safe и resourcet.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[19]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>>>Да, собственно, всего. Там даже Upward Funarg Problem не решена. EP>>Всё решено. K>Смелое заявление. А подтверждение этому какое-нибудь есть? (cut) Это шутка, на самом деле, никакого практичного решения этой проблемы кроме точного, уплотняющего кучу ГЦ с поколениями пока не придумали, а такого в C++ никогда не будет по понятным причинам. Так что просил подтверждение я, разумеется, не всерьез.(/cut)
C++ предоставляет выбор — можно сделать move, можно copy, можно ref-counted, а можно вообще зарегистрировать deleter в scope повыше. Причём это работает для любых ресурсов, а не только для памяти как в языках с GC.
EP>>Сборщик мусора пытается управлять только памятью, да и то возможны утечки. Если же брать управление ресурсами в общем — то и C# и Haskell сливают C++. EP>>Например попробуй сделать аналог: K>В языках с ГЦ для детерминированного освобождения используются всякие брекеты вроде using
Ну вот в C# есть GC, и using'и:
using System;
using System.IO;
public class Test
{
public delegate void fireworks();
public static fireworks make_closure(FileStream fs)
{
return () => fs.Read(new byte[10], 0, 10); // "чемодан без ручки"
}
public static fireworks fire()
{
using (var fs = File.Open("file", FileMode.Open))
{
return make_closure(fs);
}
}
public static void Main()
{
fire()(); // System.ObjectDisposedException
}
}
Тут-то куда писать using?
K>
K>let foo () =
K> let x = 5
K> use file = new Movable<_>(System.IO.File.CreateText(@"d:\log.txt"))
K> (*failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
K> let y = 11
K> let file = file.Move()
K> (* failwith "BANG!" //а тут сборщиком мусора *)
K> fun s -> use f = file
K> (* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
K> f.Write(s + "!")
K> x + y
K>printfn "%d" <| foo () "OMG"
K>
Можно ли вызвать замыкание несколько раз? Когда конкретно происходит удаление?
EP>> Как только замыкание выходит из scope файл закрывается и Foo освобождается. K>Звучит довольно бессмысленно. Во первых, тут владение открытым файлом передается в функцию, которую вы называете "замыканием", хотя замыкание это сомнительное.
[f=move(f), =](auto z) mutable
{
f << z << endl;
return x + y->data;
};
Ну а что это тогда если не замыкание?
K>В общем-то смысл замыкания как раз в продлении жизни скоупа из которого оно уходит. Так что замыкание и решение UFP — это работающий [&], а не копирование.
Работающего [&] при передачи вверх естественно не будет. Но говорить что работающий [&] это необходимое условие для решения UFP — неправильно. Вот например цитата из wiki:
Another solution is to simply copy the value of the variables into the closure at the time the closure is created.
В разных языках разные подходы
K>При сколько нибудь существенном использовании ФП вы устанете ждать, пока там что-то копируется,
Копировать необязательно, часто достаточно move.
K>да и смысл замыкания часто именно в том, чтоб разные функции ушедшие из одного скоупа впоследствии работали друг с другом через замыкание на него. Т.е. в большинстве практически полезных случаев придется использовать тормозные и замусоривающие код умные указатели со счетчиками.
Во-первых в большинстве полезных случаев ref-counted не нужен, а во-вторых код не замусоривается:
K>Не говоря уж о том, что в ФП циклические ссылки в порядке вещей.
Они действительно возможны, но разве это прям в порядке вещей? Особенно учитывая иммутабельность.
K>Ну так вот, в эту функцию владение передается и файл закрывается после того, как эта функция отработала. Все верно?
Нет. В эту лямбду захватывается файл, а он закрывается в деструкторе лямбды. Саму лямбду можно вызывать много раз.
K>Вообще говоря, тут утечка ресурса.
Где?
K>Никакого практического смысла возвращать функцию и тут же ее использовать нет.
Это только иллюстрация проблемы UFP, естественно в большинстве use-case'ов это замыкание будет вызываться несколько раз, и возможно будет передаваться ещё выше. Например:
{
auto log = make_log("...");
log(1);
log("1");
log(foo);
} // log destructor cleans up its resources
Как сделать подобное в C# или Haskell?
K>На практике функция будет болтаться в памяти как часть какого-то замыкания или структуры данных, хранящих функции и возможно вовсе никогда не будет вызвана. Т.е. момент ее выполнения будет определен динамически, ни о каком детерминированном высвобождении ресурса тут речи не идет.
Выше use-case.
K>Поэтому, за захват ресурса в замыкание и отправление этого замыкания в свободное плавание неплохо бы бить канделябром.
В языках где есть готовые решения только для памяти, но нет ничего для остальных ресурсов — действительно, такой номер не пройдёт. Потому что GC для памяти это полумера, и не решает UFP в общем случае
K>Более-менее осмысленное решение, это делать функцию вида ЭтоНамНадоЧтобПолучитьРесурс -> (ОткрытыйРесурс -> Результат) -> Результат, которая сначала собирает через второй аргумент функции, которые что-то будут с ресурсом делать, а потом выполняется сама, открывая ресурс, скармливая всем этим функциям и закрывая его. Т.е. те самые брекеты и их развитие вроде pipes-safe и resourcet.
Часто открытие/закрытие ресурсов может быть накладным, не говоря о том что может быть вообще недопустимо (например квота на сессии).
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>Кстати, в Boost.Thread у future есть .then — я его использовал для реализации await (хотя там не обязательно привязываться к конкретному типу future, можно сделать customiztion point). I>>>Шота сиплюсники путаются в показаниях Если then есть у future, то это уже гарантировано монанднее некуда. EP>>В C++11 std::future нету .then, там есть только блокирующий get. Есть boost::future, к которому добавили .then (afaik, после выхода C++11). I>И что это меняет ?
Вы обсуждали std::future — сейчас там нет .then, так что никакой "путаницы в показаниях" нет.
std не единственная библиотека где есть future/promise, и в некоторых из них есть .then — например PPL, Boost.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, meadow_meal, Вы писали:
_>Более четкая формулировка вопроса поможет лучше понять его.
Вопрос был о преимущества техники контроля эффектов Хаскеля. Соответственно ответом на него должен был бы быть код на Хаскеле с пояснением почему аналогичное трудно реализовать на других языка программирования.
_>Чудес и не надо. А в моем примере они меня спасут от целого класса ошибок.
Я просто заметил, что хотя в D оно есть, но им не особо пользуются. ) Т.е. конечно же у всех соответствующих функций в стандартной библиотеке проставлен модификатор pure и т.п. Но я вот что-то не помню каких-то мест, где бы принимались pure функции и не принимались обычные. Понятно о чём я? )
А так да, для определённого автоматического самоконтроля это конечно полезная вещь.
_>Однако желание свести все к конечному автомату при реализации на С++ понять можно — при простом решении в лоб, приведенном выше, уже накладные расходы на обеспечение иммутабельности State при очень сложном State непрактичны. Как бы я это делал на С++ — ума не приложу, но я и не знаток С++. Кончено, нужны совсем другие техники, но мне сложно представить, что решение может быть проще (короче и очевидней), чем то, что я использую.
На самом деле, если приглядеться к вашему примеру, то можно увидеть, что требование неразделимости validateEvent и processEvent не выполняется и у вас. Т.е. оно более сильное, чем на самом деле в вашем коде. А реально у вас там работает требование "неразделённость validateEvent и analyzeEvent", в то время как реальный action (требующий результаты analyzeEvent) вполне отделён. Т.е. на самом деле опять же получился классический конечный автомат. Просто его action и guard теперь будут использовать некую общую переменную effect, а код самого автомата (вида "state1+event[guard]/action==state2") нисколько при этом не меняется. Конечно это не совсем приятно с точки зрения красоты архитектуры, но раз у нас такой дико сложный guard, что его неэффективно повторять внутри action, то подобная оптимизация быстродействия является вполне разумным решением.
_>А чем плох мой пример? хаскелл решает обе мои проблемы совершенно тривиальным образом. (Собственно монада IO — пример такого решения, с единственной разницей что в моем случае я должен аккумулировать эффекты, а не применять их сразу же — но это уже детали реализации моей условной монады Effects, а использование аналогично).
Так а где само решение на Хаскеле то? ) Я пока увидел только саму проблему и вроде как её "плохое" решение на псевдокоде, которое реализуется в любом языке. А где хорошее решение на Хаскеле?
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Вот именно — нужно завернуть остаток кода в continuation, тогда всё заработает без изменений. EP>Представь что у optional есть .then (блокирующий). Тогда задача решается простым await'ом (на stackful coroutine): EP>
Только для optional есть один момент — если будет Nothing, то продолжение не вызовется, но стэк-то надо раскрутить. Придётся бросить исключение, что убивает всю идею Maybe. EP>Другой недостаток — продолжение нельзя вызвать несколько раз. Это например используется в List Monad. EP>В D кстати есть фиберы в std.
В итоге получается, что вместо того, что бы устраивать монадопобные игры, проще всего использовать boost.optional в его оригинальном виде. А именно, заменяем Т на optional<T> и расставляем везде по коду звёздочки. В итоге всё будет работать как и раньше, а в случае nothing прилетит исключение. Конечно это не получится полное отсутствие модификации кода, но очень близкое к этому.
EP>Это никак не поможет. Проблема в том, что мы должны остановится как только встретим первое Nothing. Если просто лифтить операторы — то никакого останова не будет (если конечно оптимизатор не додумается), и Nothing'и будут продолжать складываться.
Ааа, в этом смысле, действительно. Я даже не подумал о таком варианте в начале. У меня nothing почему-то ассоциировалось с чем-то вроде исключительной ситуации, которую оптимизировать не надо. )
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали: EP>>>>Получается что языки с сall-with-current-continuation в этом месте мощнее — можно обычный код сделать монадическим не меняя его. EP>>Реальный — Scheme. "Гипотетический" — Unlambda. K>И вы можете такую "монадизацию" существующего кода без его изменения проиллюстрировать примером?
Да, практически.
Единственное изменение — это вызов get вместо простого использования значения напрямую, но это мелочи (в C++/D/Haskell этот get был бы не нужен. может быть и в Scheme это тоже как-то возможно).
Пользовательская функция:
(define (user_func get Mx My)
(define x '())
(define y '())
(set! x (get Mx))
(if (less x 1000)
(begin
(set! y (get My))
(* x y))
'()))
как видно — она достаточно императивная, никакого нарезания control flow на продолжения как в Haskell нет.
Запускаем разными способами:
EP>>Я имел ввиду делать раннее завершение и считать сколько раз пытались вытащить Nothing. Монадический fold остановится, а обычный должен будет пройтись по всем значениям. K>Ничего не понял. Что за обычный и монадический фолды? Почему один остановится, а другой нет?
foldl остановится? Возможно ли написать foldlm, с тем же порядком вычислений, но так чтобы он остановился? K>Скобки у вас не там. Свертка-то правая. K>
K>foldr (+) 0 [a..z]
K>= {foldr (+) 0 (a:as) = a + foldr (+) 0 as}
K>a + (b + (c ... + 0))
K>= {(+) = liftM2 (+)}
K>liftM2 (+) a (b + (c ... + 0))
K>= {liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b}
K>a >>= \a -> (b + (c ... + 0)) >>= \b -> a + b
K>= {a = Nothing} -- и вот у нас попадается Nothing
K>Nothing >>= \a -> (b + (c ... + 0)) >>= \b -> a + b
K>= {Nothing >>= _ = Nothing} -- вот здесь, например, нормальный порядок
K>-- позволяет не считать все остальное. При аппликативном порядке все, что
K>-- передается в функцию, вычисляется перед ее вызовом, так что вычислять
K>-- придется до посинения.
K>Nothing
K>
Теперь дошло, спасибо. Остановка происходит за счёт гарантированной ленивости, верно?
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В итоге получается, что вместо того, что бы устраивать монадопобные игры, проще всего использовать boost.optional в его оригинальном виде. А именно, заменяем Т на optional<T> и расставляем везде по коду звёздочки. В итоге всё будет работать как и раньше, а в случае nothing прилетит исключение.
Maybe — это фактически и есть исключение, но без значения. Точнее только с одним значением:
struct Nothing {};
...
throw Nothing{};
(в Haskell даже есть монада Exception, которая очень похожа на Maybe)
Поэтому, естественно, в случае C++/D лучше воспользоваться встроенными исключениями в язык (причём оптимизированными).
_>Конечно это не получится полное отсутствие модификации кода, но очень близкое к этому.
Звёздочки, кстати, расставлять в пользовательском коде не обязательно, достаточно расставить внутри лифтанутых операторов.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>А, я понял, простите за тупизну. S>Фактически вы противопоставляете встроенное расширяемому. То есть, что лучше — встраивать популярные монады прямо в язык, или научить язык работать с любыми монадами, а потом реализовывать плюшки библиотеками.
Не совсем такая логика. Сейчас попробую по пунктам изложить:
1. Я пока что-то сами языки программирования не проектирую, поэтому пока подхожу к ним исключительно с точки зрения потребителя. Т.е. основной является проблема выбора оптимального, на продумывание идеальной архитектуры нового.
2. Выбор языка естественно завязан на задачи и про "монадность" при этом думается в последнюю очередь. Т.е. для начала надо чтобы язык хотя бы позволял создавать необходимый код, не важно как будет выглядит его исходник. А уже после этого, из оставшегося множества выбираем вариант с наиболее эффективным синтаксисом.
3. ОК, выбрали язык. В нашем случае это оказался C++. И вот теперь посмотрим на него с точки зрения монад. C++, благодаря своим шаблонам, позволяет создавать и использовать явные монады ничуть не слабее Хаскеля (а вот C# например не может так). Казалось бы вот сейчас наделаем этих самых монад как и в Хаскеле. Но мы смотрим на язык и видим, что практически для всех целей, которые решаются в Хаскеле известными монадами, в C++ есть свои, уже вложенные в язык средства. Причём они точно не являются явными монадами (никаких явных функций bind и т.п.), а являются просто чем-то отдалённо похожим, но при этом работают ещё более эффективно, чем явные монады, т.к. реализуются компилятором.
В результат всего это возникает логичный вопрос: есть ли какие-то задачи, которые отлично решаются с помощью монад и при этом не имеют более эффективного решения на базе встроенных в C++ средств? Потому как если есть, то мы тут же быстренько накидаем соответствующую явную монаду и будем её постоянно использовать в этих задачах.
Собственно этот вопрос я и пытался выяснить в дискуссии в данной темке. Однако пока не увидел ни одного подходящего примера.
Кстати, возможно кому-то показалось что я настроен "против монад". Это естественно не так, ведь я могу спокойно использовать их в своём языке, так что никаких ммм предубеждений такого типа у меня быть не может. Просто для того, чтобы решить их использовать, надо убедиться, что они могут давать результат лучше встроенных средства, а пока что ни один пример тут не выдержал подобной проверки. Т.е. действительно в каком-то смысле у меня получается вывод "монады не нужны". ))) Но не из-за каких-то базовых принципов, а только потому, что пока так и не видел ни единого подходящего примера обратному.
S>Моё мнение такое, что должны быть и те и другие языки. В том смысле, что для обкатки полезных идей нужен язык, в котором можно добавить более-менее всё, что угодно; а уже потом зарекомендовавшие себя идеи можно переносить в мейнстрим, где важнее обеспечить плавную кривую обучения и обложить всё внятными сообщениями компилятора.
Согласен. ) Только я бы оставил как раз расширяемый язык для мейнстрима (возможно если и не по головам считать, то по лидирующим продуктам), а простой и безопасный предназначил для толп малоквалифицированных программистов, разрабатывающих корпоративный софт в не IT компаниях.
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В результат всего это возникает логичный вопрос: есть ли какие-то задачи, которые отлично решаются с помощью монад и при этом не имеют более эффективного решения на базе встроенных в C++ средств? Потому как если есть, то мы тут же быстренько накидаем соответствующую явную монаду и будем её постоянно использовать в этих задачах. _>Собственно этот вопрос я и пытался выяснить в дискуссии в данной темке. Однако пока не увидел ни одного подходящего примера.
Вот тут есть список "интересных" монад. Каких-то недостающих в C++ монад я не увидел.
Я думаю большим преимуществом монад является явный контроль над эффектами. Если какой-то код выпустит наружу исключение — это будет видно по его типу. Если кто-то полезет в I/O — то без явного разрешения (либо чего-то типа unsafePerformIO, или ForeignFunctionInterface) ничего не получится. То есть получается чуть больше гарантий по умолчанию.
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Не, мы хотим одним махом обработать все функции вида power, определённые для типа T, залифтив их к типу anything<T>.
Ааа, это... Ну так это же тут обсуждалось уже.
1. В D мы делаем это одной функцией на каждый тип монад (optional, list и т.п.). В том смысле, что на все функции в природе вообще, а не только на power.
2. В C++ такого нет, и мы вынуждены будем написать по одному дополнительному шаблону на каждый набор функций с одним именем (например для всех power). Зато этот шаблон для power можно написать для произвольного типа монады, а не только optional.
3. В C# не получится даже вариант C++ и придётся выписывать вариант для каждого имени функции и для каждого типа монады.
4. В Хаскеле. Я в нём не особый специалист (стёр его уже давно у себя, как не понравившийся), но насколько помню, там ситуация полностью аналогичная C++.
Это именно расклад для ситуации, когда мы не хотим вообще менять существующий код, который использует нашу функцию power.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, alex_public, Вы писали: _>>Да, и кстати... Можно прикручивать подобные вещи и без compiler magic и без монад, используя совсем другие возможности языка. Причём будет получаться гораздо эффективнее явных монад. Вот http://www.rsdn.ru/forum/philosophy/5427522
пример подобного. S>Если я правильно понял, то "без монад" ничего не получится, т.к. не всякую функцию можно использовать в качестве bind. S>То есть вы предлагаете использовать монады, не используя термин "монады".
Какой bind? Где он там? ) Там даже намёков нет на подобное и вообще другого уровня код. Мы там просто указали, что у optional есть функция-член вида "auto ??? () {???(this.value);}", где ??? подставит компилятор. Т.е. какую бы функцию член мы не затребовали от optional, он нам её предоставит, реализовав её через вызов одноимённой функции на внутреннем значение.
Так что монад тут и близко нет. Отдалённо можно обозвать это функтором, но и то только по аналогии, т.к. напрямую никто тут функции в optional не передаёт.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это не важно, главное что монада и такой вот функтор в языке без поддержки монад есть практически одно и то же.
А что за таинственная поддержка монад языком? ) Уже который раз от тебя слышу, но так что-то и не понял.
И между функтором и монадой есть большая разница в любом языке. Мы можем сделать из монады функтор (не меняя код!), но не можем сделать из функтора монаду. Во всяком случае без введения ещё одной особой операции (т.е. опять же правки кода).
I>Более того, такой метод есть уже в спирите, даже целых несколько, например binary_operator::eval или unary_operator::eval
В случае монады или даже функтора, у нас имеется некий контейнерный тип, в который запаковываются некие внутренние типы. Вот поясни, что ты считаешь в Спирите контейнером и что в него запаковывают. Тогда и аналог функции bind (ну или fmap для функтора) будет уже проще найти.
I>Собственно как то иначе сделать спирит будет затруднительно, парсер-комбинаторы сами по себе монадические до безобразия. Парсеры комбинаторы без монад всё равно что промисы без метода then
У меня такое ощущение, что ты обзываешь монадами любой кортеж функций, применяемый последовательно к одному параметру. )))
I>Промисы у которых всегда есть метод then не в счёт ?
Здравствуйте, Ikemefula, Вы писали:
I>Это чтото очень интересное и я шота не пойму, какие вещи не под силу монадам ? В твоём любимом С++ все до одной фичи которые тебе нравятся, это монады встроеные в язык. И этим монадам, оказывается, чтото не под силу
То, что встроено в язык, это на самом деле даже близко не монады. Просто отдалённо напоминающие сущности.
А не под силу им обычно вещи, реализуемые через серьёзное метапрограммирование.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Тогда непонятно, что означают слова "параметрический полиморфизм же может иметь разные реализация, причём даже в рамках одного языка. Самая эффективная естественно через обобщённое программирование". Параметрический полиморфизм, получается, один из инструментов обобщенного программирования (наряду с мл-ными функторами и т.д.), что означает его реализация через обобщенное программирование тогда.
Обобщённым программированием принято называть конкретную реализацию параметрического полиморфизма, используемую в языках типа C++, Java, C#, D и т.п. Это речь естественно не о внутреннее реализации, т.к. в этом смысле даже перечисленные сильно различаются.
K>Нет. Одна единица компиляции (модуль, например) компилируется в объектный файл и интерфейсный файл, содержащий развертки (код из модуля в той или иной степени прекомпиляции, сериализованное аст, например — ну, не важно). Никаких разверток в файле может вообще не быть — никаких межмодульных оптимизаций тогда не будет, компиляция полностью раздельная. Допустим, что компилировали мы с -O0, для ускорения компиляции во время разработки. Теперь мы хотим получить итоговую версию, и компилируем с -O2 в интерфейсных файлах теперь гораздо больше разверток, а компилятор не стесняется их использовать, когда компилирует зависимые модули. Разумеется, компиляция теперь не полностью раздельная, требует больше времени, но зато есть инлайн и специализация. Противоположная крайность такого подхода, когда весь код всех компилируемых модулей программы оказывается в развертках в интерфейсных файлах — теперь никакой раздельной компиляции нет, есть полнопрограммный анализ, естественно, чудовищно медленный, зато дающий на выходе самый быстрый код.
Хааа, ну так если мы поставляем вместе с объектным файлом ещё и по сути исходник (интерфейсный файл с AST), который потом используется для сборки других модулей, то это вообще то даже близко не компиляция. Это скорее просто некая оптимизация процесса сборки для настроек без оптимизации.
Т.е. получается, что обобщённый код на Хаскеле действительно может компилироваться в самостоятельный двоичный код, но, как тут и указывали, этот код получается тормозной, так что его используют разве что для процесса разработки. Но можно получить и нормальный код, резко забыв про раздельную компиляцию... )))
K>Ну да, "шаблоны не трогаются" а дженерики, параметризуемые модули и т.д. наоборот, проверяются и типизируются. В известно каких языках — всех, кроме C++ и его клонов.
Ну так на то они и дженерики, а не шаблоны и как следствие имеют намного более слабые возможности. И я здесь совсем не про метапрограммирование, а именно про возможности обобщённого программирования.
K>Непонятно, почему это нужно рассматривать случай, в котором куча абстракций не вводится? Тогда в языках вроде хаскеля вообще смысла нет, потому что в них все оптимизировано именно для облегчения построения таких абстракций. Именно для этого существуют, в числе прочего, и то, что вы называете "ритуальными плясками". Если же слои абстракций возводить не нужно, то и языки программирования, кроме самых примитивных не нужны, а различия между ними не существенны. Нужны и существенны только прилежание и усидчивость.
Ага, но опять же в дело вступает вопрос соотношения объёмов. Не думаю, что можно считать хорошей программой такую, в которой большую часть занимают абстракции, а не занятия собственно делом. А делом у нас занимаются как раз вызовы системного апи, последовательности которых нам и надо будет выписывать (и побольше, чем введений всяких абстракций). А именно этот процесс и сопровождается в Хаскеле лишними (по отношению к обычным императивным языкам) плясками.
Re[19]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В общем-то смысл замыкания как раз в продлении жизни скоупа из которого оно уходит. Так что замыкание и решение UFP — это работающий [&], а не копирование. При сколько нибудь существенном использовании ФП вы устанете ждать, пока там что-то копируется
Ммм не собираюсь влезать в вашу с Евгением непосредственную дискуссию, но после прочтение этого сразу же возник вопрос. Вы конечно же знаете, что в C++ кроме операций "передача ссылки" и операции "копирование" возможна ещё и операция "перемещение"? И что она определена например для всех stl коллекции и для них не особо отличима по потреблению ресурсов от передачи ссылки на коллекцию, хотя при этом происходит полная передача владения?
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Какой bind? Где он там? ) Там даже намёков нет на подобное и вообще другого уровня код.
_>Мы там просто указали, что у optional есть функция-член вида "auto ??? () {???(this.value);}", где ??? подставит компилятор. Т.е. какую бы функцию член мы не затребовали от optional, он нам её предоставит, реализовав её через вызов одноимённой функции на внутреннем значение.
Хм. Давайте проверим.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Поэтому, естественно, в случае C++/D лучше воспользоваться встроенными исключениями в язык (причём оптимизированными).
Ну думаю и для optional можно найти узкое место применения в C++, но естественно не в виде монады или чего-то подобного, а вот прямо как в Boost'e. Например для случая, когда nothing является вполне себе регулярным результатом, а не признаком исключительной ситуации. Только тогда планировать его в код изначально и использовать через if.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
S>Какого типа будет у нас выражение LibFunc(Optional!int(20))?
Будет естественно Optional!(Optional!double), но для подобных функций (знающих что такое optional) этот код и не предназначен. Он создан для решения проблемы использования "старого" кода (не знающего optional) без его переписывания.
S>Когда вы почините ваш код, ваш opDispatch будет с точностью до синтаксиса воспроизводить пример Липперта:
С чего бы мне там что-то чинить? Всё работает как и задумывалось.
S>А нужный мне для лифтинга функтор будет строиться из opDispatch (==bind) и this().
То, что из любой монады можно получить функтор — это как бы очевидно. Но монады у нас тут нет.
S>В итоге вы, собственно, опишете монаду, т.к. ваш код будет удовлетворять всем монадным законам.
Максимум это похоже на функтор, но и то странный. Эдакий функтор времени компиляции. )
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
S>>Какого типа будет у нас выражение LibFunc(Optional!int(20))?
_>Будет естественно Optional!(Optional!double), но для подобных функций (знающих что такое optional) этот код и не предназначен. Он создан для решения проблемы использования "старого" кода (не знающего optional) без его переписывания.
Проблема в том, что вы заранее не знаете, где какой код. У вас может смешиваться код, "знающий", что такое optional, и код, который ничего о нём не знает. Чтобы это решить, вам придётся либо явно описывать упаковку/распаковку в перегрузках LibFunc, либо всё-таки сделать из Optional монаду.
_>С чего бы мне там что-то чинить? Всё работает как и задумывалось.
Это потому, что вы задумали неправильно. Ваш код работает ровно на одном тестовом примере, а шаг вправо/влево приводит к неожиданностям.
_>То, что из любой монады можно получить функтор — это как бы очевидно. Но монады у нас тут нет. Пока нет. Но и код неуниверсальный. Когда вы его почините, у вас будет полная монада. S>>В итоге вы, собственно, опишете монаду, т.к. ваш код будет удовлетворять всем монадным законам. _>Максимум это похоже на функтор, но и то странный. Эдакий функтор времени компиляции. )
Это и есть функтор (в математическом смысле, а не в смысле С++). Какая разница, в какой момент он работает? Важна семантика.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ikemefula, Вы писали:
EP>>>>>Кстати, в Boost.Thread у future есть .then — я его использовал для реализации await (хотя там не обязательно привязываться к конкретному типу future, можно сделать customiztion point). I>>>>Шота сиплюсники путаются в показаниях Если then есть у future, то это уже гарантировано монанднее некуда. EP>>>В C++11 std::future нету .then, там есть только блокирующий get. Есть boost::future, к которому добавили .then (afaik, после выхода C++11). I>>И что это меняет ?
EP>Вы обсуждали std::future — сейчас там нет .then, так что никакой "путаницы в показаниях" нет. EP>std не единственная библиотека где есть future/promise, и в некоторых из них есть .then — например PPL, Boost.
Это ничего не меняет.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Это не важно, главное что монада и такой вот функтор в языке без поддержки монад есть практически одно и то же.
_>А что за таинственная поддержка монад языком? ) Уже который раз от тебя слышу, но так что-то и не понял.
do
x <- return 1
y <- return 2
z <- return 3
return x + y + z
Всё очевидно, по моему. Первый вариант в своём уме никто не будет писать. Есть, правда, исключения, которые подтверждают правило.
Поддержка языком делается
1. на уровне синтаксиса
2. на уровне библиотеки
Тоы ты продолжай делать вид, что слышишь такое впервые, очень интересно
_>И между функтором и монадой есть большая разница в любом языке. Мы можем сделать из монады функтор (не меняя код!), но не можем сделать из функтора монаду. Во всяком случае без введения ещё одной особой операции (т.е. опять же правки кода).
А сравнивая одно с другим на фоне императивного кода получаем ничтожную разницу. Скажем к императивному коду ты хоть сотню операций добавь, монаднее он не станет, это все равно будет императивный код.
I>>Более того, такой метод есть уже в спирите, даже целых несколько, например binary_operator::eval или unary_operator::eval
_>В случае монады или даже функтора, у нас имеется некий контейнерный тип, в который запаковываются некие внутренние типы. Вот поясни, что ты считаешь в Спирите контейнером и что в него запаковывают. Тогда и аналог функции bind (ну или fmap для функтора) будет уже проще найти.
тоже самое, что в любых других реализациях парсер-комбинаторов, т.к. парсер требует хранения состояния и я уже показывал.
I>>Собственно как то иначе сделать спирит будет затруднительно, парсер-комбинаторы сами по себе монадические до безобразия. Парсеры комбинаторы без монад всё равно что промисы без метода then
_>У меня такое ощущение, что ты обзываешь монадами любой кортеж функций, применяемый последовательно к одному параметру. )))
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>C++ предоставляет выбор — можно сделать move, можно copy, можно ref-counted, а можно вообще зарегистрировать deleter в scope повыше. Причём это работает для любых ресурсов, а не только для памяти как в языках с GC.
Выбор-то он предоставляет, вот только того варианта, который лучше всего подходит для ФП кода — нормального ГЦ — среди предложенных нет.
EP>Можно ли вызвать замыкание несколько раз? Когда конкретно происходит удаление?
А! До меня только сейчас дошло (простите, медленно соображаю), что нужно было сделать:
let foo () =
let x = 5
use file = new Movable<_>(System.IO.File.CreateText(@"d:\log7.txt"))
(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)let y = 11
let f = file.Move()
(* failwith "BANG!" //а тут сборщиком мусора *)
DispFun.Create(f, fun s ->
(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f.Write(s + "!")
x + y)
let bar () =
let f = foo ()
use d = DispFun.ToDisposable(f)
f "OMG"(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f "OMG!"
f "OMG!!"
bar()
В принципе, F# функция могла бы имплементировать IDisposable, если захватывает в замыкание что-то имплементирующее IDisposable. Технических проблем тут, на первый взгляд, нет, но это не сделано. Пришлось мне это сделать самому, отнаследовавшись от FSharpFunc:
using System;
using Microsoft.FSharp.Core;
namespace DisposableFunction
{
public static class DispFun
{
public static FSharpFunc<T, R> Create<T, R>(IDisposable disp, FSharpFunc<T, R> f)
{
return new DispFun<T, R>(disp, f);
}
public static IDisposable ToDisposable<T, R>(FSharpFunc<T, R> f)
{
return f as IDisposable;
}
}
public class DispFun<T,R> : FSharpFunc<T,R>, IDisposable
{
private readonly IDisposable _disp;
private readonly FSharpFunc<T, R> _f;
public DispFun(IDisposable disp, FSharpFunc<T, R> f)
{
_disp = disp;
_f = f;
}
public override R Invoke(T x)
{
return _f.Invoke(x);
}
public void Dispose()
{
_disp.Dispose();
// Console.WriteLine("func.Dispose");
}
}
}
EP>Работающего [&] при передачи вверх естественно не будет. Но говорить что работающий [&] это необходимое условие для решения UFP — неправильно. Вот например цитата из wiki: EP>
EP>Another solution is to simply copy the value of the variables into the closure at the time the closure is created.
В разных языках разные подходы
С практической точки зрения, наиболее полезный способ — это именно нормальный [&].
K>>При сколько нибудь существенном использовании ФП вы устанете ждать, пока там что-то копируется, EP>Копировать необязательно, часто достаточно move. EP>Во-первых в большинстве полезных случаев ref-counted не нужен
С моей точки зрения, копирование и передача владения удовлетворяют всяким предельным и маргинальным случаям. Какой смысл вообще связываться с ФП, если оно останется на игрушечном уровне и придется ходить держась за стенку? Никакого нормального перехода к высокоуровневому коду не будет, если программист не получит абстракции, которые просто работают.
K>>да и смысл замыкания часто именно в том, чтоб разные функции ушедшие из одного скоупа впоследствии работали друг с другом через замыкание на него. Т.е. в большинстве практически полезных случаев придется использовать тормозные и замусоривающие код умные указатели со счетчиками.
EP>код не замусоривается: EP>
EP>Foo x(1,2);
EP>x.bar();
EP>x.baz();
EP>// vs
EP>auto x = make_shared<Foo>(1, 2);
x->>bar();
x->>baz();
EP>
Конечно он замусоривается, если для чего-то использующегося как правило нужно писать и читать дополнительную писанину, а для исключений — не нужно. Должно быть наоборот.
K>>Не говоря уж о том, что в ФП циклические ссылки в порядке вещей.
EP>Они действительно возможны, но разве это прям в порядке вещей? Особенно учитывая иммутабельность.
Да, в порядке вещей. Особенно учитывая, что ленивость — это такая замаскированная мутабельность, которая позволяет сконструировать иммутабельную структуру с элементами "из будущего".
K>>Вообще говоря, тут утечка ресурса. EP>Где?
Вы возвращаете функцию, владеющую открытым ресурсом. В реальном ФП коде ее время жизни будет определятся динамически, а не статически по лексическому скоупу и т.д. В результате никакого преимущества перед финализацией ГЦ тут нет. Вообще, я считаю, что захват и передача вверх портит все автоматическое управление ресурсами с помощью стека. Это для нее плохой сценарий, на который такая система не расчитана, а в ФП он типичный.
EP>Это только иллюстрация проблемы UFP, естественно в большинстве use-case'ов это замыкание будет вызываться несколько раз, и возможно будет передаваться ещё выше. Например: EP>
EP>{
EP> auto log = make_log("...");
EP> log(1);
EP> log("1");
EP> log(foo);
EP>} // log destructor cleans up its resources
EP>
Как сделать подобное в C# или Haskell?
См. мой код на F# выше.
K>>На практике функция будет болтаться в памяти как часть какого-то замыкания или структуры данных, хранящих функции и возможно вовсе никогда не будет вызвана. Т.е. момент ее выполнения будет определен динамически, ни о каком детерминированном высвобождении ресурса тут речи не идет.
EP>Выше use-case.
Ну я же не отрицаю случаев, когда она не будет. Но из возможности поддерживать какие-то маргинальные ФП-сценарии не следует поддержка ФП. Это ведь самый минимум, а уже начинаются оговорки.
Был такой проект реализации ФЯ с управлением памятью с выводом регионов — MLkit. Такой подход — это более универсальный, чем управление с помощью стека — его надмножество по возможностям. Тем не менее, функциональные программы в такое прокрустово ложе не легли и оказалась распространенной ситуацией, когда память выделяется в общем регионе — т.е. проще говоря, утекает, потому, что этот регион "открывается" в начале работы программы, а "закрывается", соответственно, в конце. Пришлось добавлять ГЦ, так как фактически оказалось, что в ФП статическое управление памятью (по областям видимости) годится для уменьшения нагрузки на ГЦ — но не более того.
EP>В языках где есть готовые решения только для памяти, но нет ничего для остальных ресурсов — действительно, такой номер не пройдёт.
И чем в этом общем случае будет лучше ваше средство управления ресурсами, которое даже для памяти решения не дает?
EP>Потому что GC для памяти это полумера, и не решает UFP в общем случае
UFP как раз и решает. А то, что решение UFP само по себе создает сложности для точного и детерминированного управления ресурсами — ну так жизнь это не только музыка и цветы.
EP>Часто открытие/закрытие ресурсов может быть накладным, не говоря о том что может быть вообще недопустимо (например квота на сессии).
Так при таком подходе открытие/закрытие один раз и происходит.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Проблема в том, что вы заранее не знаете, где какой код. У вас может смешиваться код, "знающий", что такое optional, и код, который ничего о нём не знает. Чтобы это решить, вам придётся либо явно описывать упаковку/распаковку в перегрузках LibFunc, либо всё-таки сделать из Optional монаду.
Ну так если в вашем пример функции уже есть упаковка в optional, то почему бы не быть и распаковке? ) Причём поясню, что это имеет смысл только если LibFunc действительно как-то работает с optional (т.е. например может генерировать nothing), а иначе обычная функция отлично работает. И это будет не перегрузка, а единственный вариант.
S>Это потому, что вы задумали неправильно. Ваш код работает ровно на одном тестовом примере, а шаг вправо/влево приводит к неожиданностям.
Никаких неожиданностей. Всё работает предсказуемо и корректно. Собственно даже можно получить прямо из этого требуемый результат, если ввести функцию join (что для optional тривиально). Но смысла в этом никакого нет.
S>Пока нет. Но и код неуниверсальный. Когда вы его почините, у вас будет полная монада.
Правильно ли я понимаю, что из скажем Хаскеля надо удалить все функции fmap (как не универсальные) и соответственно само понятие функтора? )
S>Это и есть функтор (в математическом смысле, а не в смысле С++). Какая разница, в какой момент он работает? Важна семантика.
Ну в общем то да. Просто при разговоре о монадах/функторах в смысле программирования постоянно происходит оглядывание на Хаскель, а в нём такое нереализуемо. Поэтому возможно и кажется странным.
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>C++ предоставляет выбор — можно сделать move, можно copy, можно ref-counted, а можно вообще зарегистрировать deleter в scope повыше. Причём это работает для любых ресурсов, а не только для памяти как в языках с GC. K>Выбор-то он предоставляет, вот только того варианта, который лучше всего подходит для ФП кода — нормального ГЦ — среди предложенных нет.
В ISO C++11 определён интерфейс для консервативного GC. Более того готовые реализации есть уже более 10 лет, вот только GC для C++ не популярен, что говорит об его необходимости.
K>В принципе, F# функция могла бы имплементировать IDisposable, если захватывает в замыкание что-то имплементирующее IDisposable. Технических проблем тут, на первый взгляд, нет, но это не сделано. Пришлось мне это сделать самому, отнаследовавшись от FSharpFunc: K>
K> public static class DispFun
K> {
K> public static FSharpFunc<T, R> Create<T, R>(IDisposable disp, FSharpFunc<T, R> f)
K> {
K> return new DispFun<T, R>(disp, f);
K> }
K>
1. Везде придётся расставлять using'и вручную?
2. Если забыть using, то будет не-детерминированный finalize? Т.е. компилятор не сделает это сам или не подскажет ошибкой?
3. Если такое замыкание станет частью другого объекта, то сам этот объект и все его пользователи — транзитивно становятся IDisposable. Что предполагается делать в этом случае? Вручную проверять все места или всё же компилятор чем-то поможет?
4. DispFun работает только для функций с одним аргументом?
EP>>Работающего [&] при передачи вверх естественно не будет. Но говорить что работающий [&] это необходимое условие для решения UFP — неправильно. Вот например цитата из wiki: EP>>[q] EP>>Another solution is to simply copy the value of the variables into the closure at the time the closure is created. EP>> В разных языках разные подходы K>С практической точки зрения, наиболее полезный способ — это именно нормальный [&].
С практической точки зрения, в большинстве случаев нужен именно move, а не GC. GC прогибается под нагрузкой, поэтому и занимаются такими вещами как off-heap cache, escape analisys, раскладывание структур вручную по массивам байт и т.п.
Т.е. GC в одном месте немного упрощает использование, но платить за это всё же приходится в другом.
K>>>При сколько нибудь существенном использовании ФП вы устанете ждать, пока там что-то копируется, EP>>Копировать необязательно, часто достаточно move. EP>>Во-первых в большинстве полезных случаев ref-counted не нужен K>С моей точки зрения, копирование и передача владения удовлетворяют всяким предельным и маргинальным случаям. K>Какой смысл вообще связываться с ФП, если оно останется на игрушечном уровне и придется ходить держась за стенку? K>Никакого нормального перехода к высокоуровневому коду не будет, если программист не получит абстракции, которые просто работают.
Высокоуровневый код возможен не только с чистым ФП. И я не вижу смысла в использовании ФП абстракций во всех местах (т.е. ФП, только ФП, и ради ФП).
Цель абстракции — описать мир, причём эффективно, а не придумать его. Пока у нас у всех фон-Нейманавские машины — чистый ФП будет находится на академической обочине.
EP>>код не замусоривается: EP>>
x->>>baz();
EP>>
K>Конечно он замусоривается, если для чего-то использующегося как правило нужно писать и читать дополнительную писанину, а для исключений — не нужно. Должно быть наоборот.
Разделение владения ресурсом из одного scope между несколькими замыканиями переживающими этот scope — это скорее исключение в C++, чем default-use-case. И это не потому что нет GC, а потому что на практике требуется редко (и для таких случаев вполне подходит ref-counting).
K>>>Не говоря уж о том, что в ФП циклические ссылки в порядке вещей. EP>>Они действительно возможны, но разве это прям в порядке вещей? Особенно учитывая иммутабельность. K>Да, в порядке вещей. Особенно учитывая, что ленивость — это такая замаскированная мутабельность, которая позволяет сконструировать иммутабельную структуру с элементами "из будущего".
ФП ведь не предполагает ленивость by-default?
K>>>Вообще говоря, тут утечка ресурса. EP>>Где? K>Вы возвращаете функцию, владеющую открытым ресурсом. В реальном ФП коде ее время жизни будет определятся динамически, а не статически по лексическому скоупу и т.д.
Динамическое время жизни это разве обязательная характеристика "реального ФП"?
На практике, динамическое время жизни объектов обычно вытекает из внешней неопределённости, а не алгоритмической структуры. Например при реакции на внешние события.
Возможно если ещё и сам язык добавляет неопределённости во время жизни — то это не самая лучшая абстракция?
K>В результате никакого преимущества перед финализацией ГЦ тут нет. Вообще, я считаю, что захват и передача вверх портит все автоматическое управление ресурсами с помощью стека. Это для нее плохой сценарий, на который такая система не расчитана, а в ФП он типичный.
Такой сценарий типичен при асинхронной работе с сетью (замыкание регистрируются как реакция на внешнее событие), например через Boost.Asio. Там как раз типичный UFP — и никаких проблем с этим нет.
Более того — если сделать re-inversion of control с помощью stackful coroutines, то UFP уходит за кулисы.
EP>>Это только иллюстрация проблемы UFP, естественно в большинстве use-case'ов это замыкание будет вызываться несколько раз, и возможно будет передаваться ещё выше. Например: EP>>ccode EP>>Как сделать подобное в C# или Haskell? K>См. мой код на F# выше.
То есть будет возвращаться не само замыкание, а завёрнутое во wrapper добавляющий IDisposable, с ограничением на сигнатуру замыкания в один аргумент, с необходимостью ручной расстановки using, причём все объекты в которых находится это замыкание транзитивно становятся IDisposable, со всеми вытекающими.
И разве это приемлемое решение UFP? Это же фактически контроль за временем жизни на каждом уровне вручную.
ОК, с C#/F# понятно, а как это будет выглядеть в Haskell? (код не обязательно)
EP>>В языках где есть готовые решения только для памяти, но нет ничего для остальных ресурсов — действительно, такой номер не пройдёт. K>И чем в этом общем случае будет лучше ваше средство управления ресурсами, которое даже для памяти решения не дает?
C++ даёт решение и для памяти, и для ресурсов, причём решение единообразное. Да оно менее автоматическое чем GC, но работает для всех ресурсов, и не имеет минусов GC.
K>Более-менее осмысленное решение, это делать функцию вида ЭтоНамНадоЧтобПолучитьРесурс -> (ОткрытыйРесурс -> Результат) -> Результат, которая сначала собирает через второй аргумент функции, которые что-то будут с ресурсом делать, а потом выполняется сама, открывая ресурс, скармливая всем этим функциям и закрывая его. Т.е. те самые брекеты и их развитие вроде pipes-safe и resourcet. EP>>Часто открытие/закрытие ресурсов может быть накладным, не говоря о том что может быть вообще недопустимо (например квота на сессии). K>Так при таком подходе открытие/закрытие один раз и происходит.
То есть предполагается что все действия над ресурсом должны обязательно собраться в одном месте? Это серьёзное ограничение.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
EP>>Поэтому, естественно, в случае C++/D лучше воспользоваться встроенными исключениями в язык (причём оптимизированными). _>Ну думаю и для optional можно найти узкое место применения в C++, но естественно не в виде монады или чего-то подобного, а вот прямо как в Boost'e.
Для использования "в виде монады" подойдёт просто звёздочка, без предварительной проверки. При необходимости звёздочка вызовет встроенную "монаду" — Exception.
_>Например для случая, когда nothing является вполне себе регулярным результатом, а не признаком исключительной ситуации.
Или другой use-case: отложенная инициализация объекта без default constructor.
_>Только тогда планировать его в код изначально и использовать через if.
Да, в таких случаях обычно ещё и else есть с нетривиальным кодом. То есть использование в стиле алгебраического типа — и это даже не функтор Maybe.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ага, но опять же в дело вступает вопрос соотношения объёмов. Не думаю, что можно считать хорошей программой такую, в которой большую часть занимают абстракции, а не занятия собственно делом. А делом у нас занимаются как раз вызовы системного апи, последовательности которых нам и надо будет выписывать (и побольше, чем введений всяких абстракций). А именно этот процесс и сопровождается в Хаскеле лишними (по отношению к обычным императивным языкам) плясками.
Странная точка зрения. Вы что, серьёзно считаете, что в каком-нибудь VirtualDub "занятия делом" — это только обращения к *Alloc() и WriteFile()? А я-то думал, что там рулят собственно кодеки и фильтры.
Или, скажем, SQL сервер — там вообще кроме WriteFile ничего нету, в сокеты да в диск.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Ну так если в вашем пример функции уже есть упаковка в optional, то почему бы не быть и распаковке? ) Причём поясню, что это имеет смысл только если LibFunc действительно как-то работает с optional (т.е. например может генерировать nothing), а иначе обычная функция отлично работает. И это будет не перегрузка, а единственный вариант. S>>Это потому, что вы задумали неправильно. Ваш код работает ровно на одном тестовом примере, а шаг вправо/влево приводит к неожиданностям. _>Никаких неожиданностей. Всё работает предсказуемо и корректно.
Для вас — конечно нет никаких неожиданностей. Потому, что вы не планировали пользоваться вашим кодом, а писали его в качестве упражнения. А для обычных пользователей получить optional<optional<double>> будет весьма неожиданно.
И реальные функции, которые встречаются в реальной жизни, будут устроены не как arg*10, а как что-то вроде
public Manager? GetManagerById(int managerID)
{
var dataRow = Repository.ManagerTable.GetByID(managerID);
if (DataRow == null)
return null;
else
return Manager.CreateFromDataRow(dataRow);
}
Вот такая функция совершенно случайно может получить int? аргумент — например, у нас есть свойство Customer.PreferredManagerID, которое оказалось nullable. Наличие монады позволило бы нам писать var PreferredManager = GetManagerById(customer.PreferredManagerID). Ваш функтор вернёт Nullable<Nullable<Manager>>, что вовсе не то, чего мы ожидаем.
Вы предлагаете чинить это при помоши замены типа аргумента, и переписывания нашей функции примерно вот в это:
public Manager? GetManagerById(int? managerID)
{
if (!managerID.HasValue)
return null;
var dataRow = Repository.ManagerTable.GetByID(managerID.Value);
if (DataRow == null)
return null;
else
return Manager.CreateFromDataRow(dataRow);
}
Это называется "дублирование логики", и именно этого передовики производства стараются избегать. Зачем нам эти строчки в каждой функции, если они уже есть в монаде? _>Правильно ли я понимаю, что из скажем Хаскеля надо удалить все функции fmap (как не универсальные) и соответственно само понятие функтора? )
Зачем? Эти функции прекрасно решают поставленные перед ними задачи. А ваша — нет, не решает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Разделение владения ресурсом из одного scope между несколькими замыканиями переживающими этот scope — это скорее исключение в C++, чем default-use-case. И это не потому что нет GC, а потому что на практике требуется редко (и для таких случаев вполне подходит ref-counting).
Это именно потому, что нет GC — очень трудно писать, еще труднее отладить и совершенно невозможно майнтейнить такой код.
Там где есть GC, циклические ссылки и разделение владения ресурсом используется направо-налево даже не задумываясь.
Именно по этой причине возврат замыкания из using вещь крайне странная.
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В ISO C++11 определён интерфейс для консервативного GC.
А смысл? Консервативный ГЦ бесполезен. Это практически никаких плюсов точного сборщика, практически все его минусы да еще куча минусов сверх того.
EP>1. Везде придётся расставлять using'и вручную?
писать use вместо let
EP>2. Если забыть using, то будет не-детерминированный finalize? Т.е. компилятор не сделает это сам или не подскажет ошибкой?
Нет, сам не сделает.
EP>3. Если такое замыкание станет частью другого объекта, то сам этот объект и все его пользователи — транзитивно становятся IDisposable. Что предполагается делать в этом случае? Вручную проверять все места или всё же компилятор чем-то поможет?
Нет, не поможет.
EP>4. DispFun работает только для функций с одним аргументом?
Это же F#-функция. Там только функции с одним аргументом — других нет.
Все перечисленное, впрочем, не важно. Никто так не делает, потому что передача куда-то замыкания с захваченным ресурсом — это проблема которая в общем случае ничем не лечится. А ради вырожденного юзкейса никто не станет огород городить. Это просто демонстрация технической возможности и ответ на вопрос о том, "где using писать?"
EP>С практической точки зрения, в большинстве случаев нужен именно move, а не GC.
Не в ФП.
EP>GC прогибается под нагрузкой,
Ну а вы что хотели? За высокоуровневость нужно платить.
EP>поэтому и занимаются такими вещами как off-heap cache, escape analisys, раскладывание структур вручную по массивам байт и т.п.
Не сказал бы, что эскейп-анализ сильно на нагрузку на ГЦ влияет. То, что устраняет ЭА обычно короткоживущие объекты, для ГЦ в основном безвредные. Просто какой-нибудь объект Complex в куче или пара даблов в регистрах — это по производительности смешно даже сравнивать.
EP>Т.е. GC в одном месте немного упрощает использование, но платить за это всё же приходится в другом.
Естественно. Тут вместо GC можно подставить что угодно и будет правильно — это просто трюизм. Речь о том, что если мы говорим о поддержке ФП, то он облегчает в таком месте, без облегчения в котором никто с ФП даже связываться не станет. В C++ просто противоположный выбор сделан, который облегчает там, где нужно для естественной области применимости C++, а там где нужно облегчать для ФП — наоборот осложняет.
EP>Высокоуровневый код возможен не только с чистым ФП. И я не вижу смысла в использовании ФП абстракций во всех местах (т.е. ФП, только ФП, и ради ФП). EP>Цель абстракции — описать мир, причём эффективно, а не придумать его. Пока у нас у всех фон-Нейманавские машины — чистый ФП будет находится на академической обочине.
Мы вообще тут говорили не о том нужно ФП или нет, а о том, что есть какие-то минимальные требования, для того чтоб можно было сказать "есть поддержка ФП" и которым C++ не соответствует. Отход от темы начался заявлением, что в C++ все якобы решено. Закончилось все ожидаемо: заявлением о том, что ФП не нужно. Видимо это и есть подразумеваемое решение.
EP>Разделение владения ресурсом из одного scope между несколькими замыканиями переживающими этот scope — это скорее исключение в C++, чем default-use-case.
Ну разумеется. Потому, что C++ не ФЯ.
EP>И это не потому что нет GC, а потому что на практике требуется редко (и для таких случаев вполне подходит ref-counting).
Нет, именно поэтому. Потому, что хоть сколько-нибудь неигрушечных реализаций высокоуровневых языков без ГЦ не бывает. Две известных мне попытки реализовать высокоуровневый язык без ГЦ провалились.
EP>ФП ведь не предполагает ленивость by-default?
Мы вроде бы в соседней ветке выяснили, что без ленивости комбинирование функций теряет смысл из-за непрактичности. Также из-за непрактичности без ленивости теряют смысл иммутабельность и персистентные структуры данных. После этого от ФП уже ничего и не остается.
Другое дело, что это иная степень необходимости. Обсуждаемая здесь UFP — это, допустим, кислород, а ленивость — пища. Т.е. без нее в функциональном программировании как-то существовать можно, но плохо и недолго.
EP>Динамическое время жизни это разве обязательная характеристика "реального ФП"?
Ну я же рассказывал о печальном опыте MLKit. Вот краткая выжимка. Ключевой момент "We believe that it is the case that common SML idioms tend to work better under GC than under regions." Обратите внимание, что речь идет о SML, достаточно императивном и относительно низкоуровневом, если с каким-нибудь хаскелем сравнивать. В более продвинутом ФЯ все будет только хуже. Реализация Хаскеля, в которой пытались обойтись регионами без ГЦ тоже была (JHC), и тоже неудачная.
EP>Возможно если ещё и сам язык добавляет неопределённости во время жизни — то это не самая лучшая абстракция?
Ну, абстракция — это тоже трейдофф. При полной определенности никакой абстракции не останется.
EP>Такой сценарий типичен при асинхронной работе с сетью (замыкание регистрируются как реакция на внешнее событие), например через Boost.Asio. Там как раз типичный UFP — и никаких проблем с этим нет.
Непонятно, правда, зачем нужна асинхронность I/O через колбек-лапшу в высокоуровневом языке.
Если очень постараться, можно, конечно, пользу и от чемодана без ручки какую-нибудь найти, вот только какой-то поддерживаемый юзкейс не означает, что неподдерживаемые — не проблема.
EP>То есть будет возвращаться не само замыкание, а завёрнутое во wrapper добавляющий IDisposable
Не понятно, что за "не само замыкание". Все F#-функции такие вот наследники. Из кода, который я опубликовал вроде видно, что добавлятель IDisposable принимает 'a -> 'b и возвращает 'a -> 'b. Что не так-то?
EP>с ограничением на сигнатуру замыкания в один аргумент
Странная претензия в случае F#. А скольких аргументов должны быть замыкания? И с какой стати это ограничение? Если тут возникло какое-то недопонимание, на всякий случай поясню, что вот это
fun s -> DispFun.Create(f, fun t ->
(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f.Write(s + t + "!")
x + y)
let bar () =
let f = foo () "!"
use d = DispFun.ToDisposable(f)
f "OMG"(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f "OMG!"
f "OMG!!"
и вот это
DispFun.Create(f, fun s t ->
(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f.Write(s + t + "!")
x + y)
let bar () =
let f = foo ()
use d = DispFun.ToDisposable(f)
f "OMG" "!"(* failwith "BANG!" //тут ресурс будет освобожден детерминированно *)
f "OMG!" "!"
f "OMG!!" "!"
будет работать.
EP>И разве это приемлемое решение UFP?
Это вообще не решение UFP. UFP — это работающий [&] только и всего. Понятно, что тема эта для плюсистов больная, но это не значит, что нужно перескакивать с нее то на копирование (как будто оно когда-то представляло из себя что-то проблемное для реализации), то на prompt finalization (я понимаю, что на это переводится любой разговор о C++ в ста случаях из ста), то на ненужность ФП. Вы можете, конечно, утверждать, что высокоуровневое программирование не нужно (учитывая, что практически все высокоуровневые фичи: ленивость, континьюейшены и т.д., а не только решение UFP создают какие-то сложности той или иной степени тяжести для prompt finalization) но как это связано с тем, что по вашему заявлению в плюсах все это якобы решено?
EP>Это же фактически контроль за временем жизни на каждом уровне вручную.
На каждом уровне, на котором вы хотите закрывать ресурс.
Впрочем, как я уже заметил выше, обсуждать такие извращения с практической точки зрения нет смысла.
EP>а как это будет выглядеть в Haskell? (код не обязательно)
Это решение вполне приемлемое для низкоуровневых языков и соответствующих идиом, но для идиоматического ФП это вообще не решение.
EP>Да оно менее автоматическое чем GC, но работает для всех ресурсов, и не имеет минусов GC.
Да обсуждаемая проблема даже не в недостаточной автоматизированности (хотя, кончено, если программист начнет управлять памятью в ФП вручную — он от ФП устанет за один вечер и на всю жизнь). Я же говорю, существует серьезный ресерч по большей автоматизации/увеличению гибкости такого подхода. Тем не менее, даже такая существенно более продвинутая система, как оказалось, для ФП не подходит (в качестве основной).
EP>и не имеет минусов GC.
Во-первых, большинство минусов у способов управления динамической памятью общие. Их — этих минусов — только в каком-нибудь Фортране 77 нет.
Во-вторых, плюсов GC тоже не будет. И, что важно в обсуждаемом случае, как раз тех, которые для ФП и важны.
EP>То есть предполагается что все действия над ресурсом должны обязательно собраться в одном месте? Это серьёзное ограничение.
Ну да. В хаскеле вон вообще все действия "собираются в одном месте".
Да, к вопросу о циклах, изменении "неизменяемых" структур данных и уникальности указателей.
Вот, что представляет из себя в памяти функциональный "хеллоуворлд" — список чисел Фибоначчи после обращения ко второму элементу списка:
и к третьему:
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Обобщённым программированием принято называть конкретную реализацию параметрического полиморфизма,
Кем принято? Вот, к примеру, обзор и сравнение средств обобщенного программирования от плюсовиков (разработчиков концептов, контрибьюторов в Boost и т.д.) вовсе это никакая не "конкретная реализация параметрического полиморфизма".
_>используемую в языках типа C++, Java, C#, D и т.п.
Вопрос о существовании параметрического полиморфизма в C++ вообще спорный. Код для любого типа там в типизированном виде не существует, существует только специализированный для конкретных типов. т.е. полиморфизм там ad-hoc.
_>Хааа, ну так если мы поставляем вместе с объектным файлом ещё и по сути исходник (интерфейсный файл с AST), который потом используется для сборки других модулей, то это вообще то даже близко не компиляция. Это скорее просто некая оптимизация процесса сборки для настроек без оптимизации.
Поставляем малую часть исходника в предкомпилированном виде. Очевидно, что вклад в итоговую производительность у кода сильно неравномерный, так что на практике большая честь кода компилируется раздельно.
_>Т.е. получается, что обобщённый код на Хаскеле действительно может компилироваться в самостоятельный двоичный код, но, как тут и указывали, этот код получается тормозной, так что его используют разве что для процесса разработки. Но можно получить и нормальный код, резко забыв про раздельную компиляцию... )))
Не резко, а как раз плавно. Немного забыли про раздельную — а производительность уже и сильно подросла.
_>Ну так на то они и дженерики, а не шаблоны и как следствие имеют намного более слабые возможности. И я здесь совсем не про метапрограммирование, а именно про возможности обобщённого программирования.
В одних случаях слабее, в других — сильнее. Какие у вас, к примеру, претензии к слабости хаскельных "дженериков" (дженериками там называются совсем другие вещи) по части обобщенного программирования, например?
_>Ага, но опять же в дело вступает вопрос соотношения объёмов. Не думаю, что можно считать хорошей программой такую, в которой большую часть занимают абстракции, а не занятия собственно делом. А делом у нас занимаются как раз вызовы системного апи, последовательности которых нам и надо будет выписывать (и побольше, чем введений всяких абстракций). А именно этот процесс и сопровождается в Хаскеле лишними (по отношению к обычным императивным языкам) плясками.
Есть, конечно, мнение, что думать не надо — а надо трясти, педалить побольше кода, который "делает реальные дела" и т.д., но я его не разделяю.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[20]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ммм не собираюсь влезать в вашу с Евгением непосредственную дискуссию, но после прочтение этого сразу же возник вопрос. Вы конечно же знаете, что в C++ кроме операций "передача ссылки" и операции "копирование" возможна ещё и операция "перемещение"? И что она определена например для всех stl коллекции и для них не особо отличима по потреблению ресурсов от передачи ссылки на коллекцию, хотя при этом происходит полная передача владения?
Много ли от "полной передачи владения" пользы в ФП, где коллекции персистентные и типична ситуация, когда на какую-то часть иммутабельной структуры данных куча ссылок от разных ее версий?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Все перечисленное, впрочем, не важно. Никто так не делает, потому что передача куда-то замыкания с захваченным ресурсом — это проблема которая в общем случае ничем не лечится. А ради вырожденного юзкейса никто не станет огород городить.
Это же и есть upwards funarg?
K>Мы вообще тут говорили не о том нужно ФП или нет, а о том, что есть какие-то минимальные требования, для того чтоб можно было сказать "есть поддержка ФП" и которым C++ не соответствует. Отход от темы начался заявлением, что в C++ все якобы решено. Закончилось все ожидаемо: заявлением о том, что ФП не нужно. Видимо это и есть подразумеваемое решение.
Не так. ФП нужно, но далеко не везде. Писать на C++ только в ФП стиле не имеет смысла.
Нужен ленивый map? Пожалуйста:
use(x | transformed(_1 * _1));
Энергичный inplace? Тоже не проблема:
transform(x, begin(x), _1 * _1);
use(x);
EP>>ФП ведь не предполагает ленивость by-default? K>Мы вроде бы в соседней ветке выяснили, что без ленивости комбинирование функций теряет смысл из-за непрактичности.
В том примере нужна не ленивость, а monadic код. Ленивость помогла только в одном случае из двух, и как видно в общем случае не позволяет сделать обычный код монадичным.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Странная точка зрения. Вы что, серьёзно считаете, что в каком-нибудь VirtualDub "занятия делом" — это только обращения к *Alloc() и WriteFile()? А я-то думал, что там рулят собственно кодеки и фильтры. S>Или, скажем, SQL сервер — там вообще кроме WriteFile ничего нету, в сокеты да в диск.
Внутренность кодеков и фильтров — это как раз и есть занятие делом. А вот архитектура плагинов, через которую они подключаются, — это в данном случае абстракция.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Для вас — конечно нет никаких неожиданностей. Потому, что вы не планировали пользоваться вашим кодом, а писали его в качестве упражнения. А для обычных пользователей получить optional<optional<double>> будет весьма неожиданно.
Дааа? ) А почему тогда fmap в том же haskell'е именно так и работает? )))
S>Вот такая функция совершенно случайно может получить int? аргумент — например, у нас есть свойство Customer.PreferredManagerID, которое оказалось nullable. Наличие монады позволило бы нам писать var PreferredManager = GetManagerById(customer.PreferredManagerID). Ваш функтор вернёт Nullable<Nullable<Manager>>, что вовсе не то, чего мы ожидаем.
Такой "GetManagerById(customer.PreferredManagerID)" код — это следствие не "монадности", а встроенных средств компилятора, причём только для этой конкретной монады. А для некой обобщённой монады (может мы не optional хотим, а list) у вас будет код вида "PreferredManager = customer.PreferredManagerID>>=GetManagerById;". Т.е. вы не решили нашу изначальную задачу (неизменность кода при переходе на монаду) вообще.
S>Вы предлагаете чинить это при помоши замены типа аргумента, и переписывания нашей функции примерно вот в это: S>
S>Это называется "дублирование логики", и именно этого передовики производства стараются избегать. Зачем нам эти строчки в каждой функции, если они уже есть в монаде?
Кстати говоря, реакция на null не обязательно может быть в виде передачи его дальше, а вполне возможна выдача какого-то нетривиального результата. Так что функции вида M<R>(T) не являются самым общим случаем, а наиболее универсальным решением является функция вида M<R>(M<T). Причём если мы посмотрим на монады (и не только монады, но и вообще подобные контейнеры) других типов (тот же list например), то там вообще функций работающих над целой монадой может быть больше, чем работающих с внутренним значением.
S>Зачем? Эти функции прекрасно решают поставленные перед ними задачи. А ваша — нет, не решает.
А чем fmap отличается от моего варианта? ) Ну кроме автоматического применения, которое в Хаскеле (и в C++ и в C#) просто не сделать.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Кем принято? Вот, к примеру, обзор и сравнение средств обобщенного программирования от плюсовиков (разработчиков концептов, контрибьюторов в Boost и т.д.) вовсе это никакая не "конкретная реализация параметрического полиморфизма".
И? ) Читаем оттуда:
"The Haskell community uses the term “generic” to describe a form of generative programming with respect to algebraic datatypes (Backhouse et al., 1999; Hinze & Jeuring, 2003; Jeuring & Jansson, 1996). Thus the typical use of the term “generic” with respect to Haskell is somewhat different from our use of the term. However, Haskell does provide support for generic programming as we have defined it here and that is what we present in this section."
K>Вопрос о существовании параметрического полиморфизма в C++ вообще спорный. Код для любого типа там в типизированном виде не существует, существует только специализированный для конкретных типов. т.е. полиморфизм там ad-hoc.
Нормальный там параметрический полиморфизм, просто он времени компиляции. Это не в том смысле что он имеет статическое связывание (такое во многих языках), а в том, что он "исполняется" во время компиляции.
Если мы посмотрим на язык D (развивающий дальше эту концепцию), то там во время компиляции можно вообще выполнять практически произвольный пользовательский код. И это можно использовать для очень разных интересных возможностей. Например можно ввести полноценный (а не встроенный в язык, как Спирит) DSL, файлы которого будут парситься в процессе компиляции некого D кода и это всё вместе будет превращаться в единый бинарники с полными оптимизациями, включая инлайны. Это несколько другой уровень программирования вообще.
Ну а то, что мы имеет в C++, это так сказать зародыш подобной техники. )
K>Не резко, а как раз плавно. Немного забыли про раздельную — а производительность уже и сильно подросла.
Кстати, а есть возможно указывать подобное руками или всё управляется только компилятором, а мы влиять не можем (кроме опций компилятора)? Т.е. можем ли мы сказать что например "вот данная сущность должна инлайниться вообще всегда"
K>В одних случаях слабее, в других — сильнее. Какие у вас, к примеру, претензии к слабости хаскельных "дженериков" (дженериками там называются совсем другие вещи) по части обобщенного программирования, например?
Под дженериками естественно Java/C# подразумевались и они заметно слабее варианта C++ именно по части обобщённого программирования. Что касается Хаскеля, то там вообще другая концепция и сравнивать их напрямую глупо. Однако если посмотреть по набору возможностей, то тут видится приблизительный паритет со своим набором плюсов и минусов с каждой стороны.
P.S. Как я понял, ни одного примера заявленных (вами) преимуществ реализации ST/IO Хаскеля над другими языками мы так и не увидим... Несмотря на мои многочисленные напоминания об этом. Ну что же, ладно, так и запишем и закроем эту тему.
Re[21]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Много ли от "полной передачи владения" пользы в ФП, где коллекции персистентные и типична ситуация, когда на какую-то часть иммутабельной структуры данных куча ссылок от разных ее версий?
Хехе, первая часть этой фразы действительно относится к ФП вообще, а вот вторая относится уже всего лишь к одной из конкретных реализаций в конкретном языке.
В C++ перемещение как раз оптимально для передачи некой иммутабельной коллекции куда-то за пределы контроля стека (внутри которого отлично действует простая константная ссылка), т.к. при этом полностью сохраняется контроль за владением и нет никаких накладных расходов (как при тупом копирование).
А вот если у нас стоит уже другая (довольно специфическая кстати) задачка, в которой нам необходимо иметь множество таких коллекции из одних и тех же элементов (причём элементы имеют не маленький размер), то для этого есть отдельное простейшее решение. Типа vector<shared_ptr<T>>. И кстати перекидывать куда-то "наверх" такую коллекцию с помощью "перемещения" так же очень удобно и выгодно.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Динамическое время жизни это разве обязательная характеристика "реального ФП"? K>Ну я же рассказывал о печальном опыте MLKit. Вот краткая выжимка. Ключевой момент "We believe that it is the case that common SML idioms tend to work better under GC than under regions."
Насколько я понял, именно опыта там и не было. Вот что написано перед вышеприведённой цитатой:
MLton does not use region-based memory management; it uses traditional GarbageCollection. We have considered integrating regions with MLton, but in our opinion it is far from clear that regions would provide MLton with improved performance, while they would certainly add a lot of complexity to the compiler and complicate reasoning about and achieving SpaceSafety. Region-based memory management and garbage collection have different strengths and weaknesses; it’s pretty easy to come up with programs that do significantly better under regions than under GC, and vice versa.
То есть они рассматривали, но не пробовали.
EP>>И разве это приемлемое решение UFP? K>Это вообще не решение UFP. UFP — это работающий [&] только и всего. Понятно, что тема эта для плюсистов больная, но это не значит,
Про "неработающие" замыкания в C++ из-за UFP любители GC мне тут уже третий раз говорят, хотя "плюсисты" не имеют с этим проблем. На деле же оказывается что работают, и не только для памяти.
K>что нужно перескакивать с нее то на копирование (как будто оно когда-то представляло из себя что-то проблемное для реализации),
В примере с файлом как раз и использовалось копирование(ref_counted)/перемещение. Повторить без ручного контроля на каждом уровне в F# не получилось.
K>то на prompt finalization (я понимаю, что на это переводится любой разговор о C++ в ста случаях из ста), то на ненужность ФП.
ФП нужно, но не везде.
K>Вы можете, конечно, утверждать, что высокоуровневое программирование не нужно (учитывая, что практически все высокоуровневые фичи: ленивость, континьюейшены и т.д., а не только решение UFP создают какие-то сложности той или иной степени тяжести для prompt finalization)
Никто не говорил что высокоуровневое программирование не нужно. Высокоуровневое это далеко не только ФП.
K>но как это связано с тем, что по вашему заявлению в плюсах все это якобы решено?
Как минимум есть решение UFP в виде копирования (что является именно решением согласно wiki). Плюс есть другие варианты.
Причём это работает не только для памяти. В языках же с GC с этим начинаются проблемы, и раз там нет нормального решения для этого варианта UFP, то естественно проблема декларируется несущественной/надуманной/нереальной/непрактичной:
EP>>Это же фактически контроль за временем жизни на каждом уровне вручную. K>На каждом уровне, на котором вы хотите закрывать ресурс. K>Впрочем, как я уже заметил выше, обсуждать такие извращения с практической точки зрения нет смысла.
Из дочернего региона в родительский возвращаются сами handle'ы, а не замыкания с хэндлами внутри? Если да — то это же совсем не то, мы же про UFP говорим.
EP>>То есть предполагается что все действия над ресурсом должны обязательно собраться в одном месте? Это серьёзное ограничение. K>Ну да. В хаскеле вон вообще все действия "собираются в одном месте".
Собираются все действия над всеми ресурсами в одном месте, причём они могут быть interleaved, и зависить один от другого.
В описанном же выше варианте действия над одним ресурсом собираются в одном месте, и только в нём. Это и есть ограничение.
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Да, к вопросу о циклах, изменении "неизменяемых" структур данных и уникальности указателей. K>Вот, что представляет из себя в памяти функциональный "хеллоуворлд" — список чисел Фибоначчи после обращения ко второму элементу списка:
Хороший пример цикла привнесённого самим языком.
По графу видно насколько неэффективно мэпится решение простой задачи в железо. Кстати, про эффективность, а как thunk'и обновляются в многопоточной среде?
K>Много ли от "полной передачи владения" пользы в ФП, где коллекции персистентные и типична ситуация, когда на какую-то часть иммутабельной структуры данных куча ссылок от разных ее версий?
Это пример разделяемого владения. Если у нас есть персистентная и полностью иммутабельная структура, типа rope, где ссылки и узлы образуют directed acyclic graph — то прекрасно подходит ref-counting.
Причём move/"полная передача владения" и тут полезена — только move'ается не сама структура, а shared_ptr — это позволяет существенно уменьшить ref-count increment/decrement.
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Это же и есть upwards funarg?
Нет, это сначала непонятно на чем основанное связывание prompt finalization проблемы и UFP, констатация простого факта, что их решения сочетаются плохо и выведение отсюда того, UFP не решается. Какой смысл связывать в ФЯ управление памятью в куче, которую эти языки выделяют гигабайтами в секунду и управлением дефицитными ресурсами, требующими закрытия сразу по окончанию использования?
EP>Не так. ФП нужно, но далеко не везде. Писать на C++ только в ФП стиле не имеет смысла.
Я сильно сомневаюсь, что писать на C++ в ФП стиле не то что имеет смысл, а вообще возможно. Если только не трактовать ФП стиль сильно расширительно.
EP>В том примере нужна не ленивость, а monadic код. Ленивость помогла только в одном случае из двух, и как видно в общем случае не позволяет сделать обычный код монадичным.
Ничего не понимаю. Ленивость не делает код монадическим. Она нужна, чтоб функции, полученные как результат комбинации других не делали лишние вычисления/проходы. Т.е. в обсуждаемом случае нужна, чтоб монадический код нормально работал.
И что за один случай из двух?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И? ) Читаем оттуда:
"The Haskell community uses the term “generic” to describe a form of generative programming with respect to algebraic datatypes (Backhouse et al., 1999; Hinze & Jeuring, 2003; Jeuring & Jansson, 1996). Thus the typical use of the term “generic” with respect to Haskell is somewhat different from our use of the term. However, Haskell does provide support for generic programming as we have defined it here and that is what we present in this section."
А вы точно читали оттуда? С.м. выделенное.
Вообще, то, что называется обобщенным программированием в С++ и других языках, где возможности для него появились в ходе развития языка, в языках где такие возможности были с самого начала вроде хаскеля никак специально не называется. Ну, нет ситуации, когда есть сформированная культура кодирования, и вдруг появляется новая, с использованием параметрического полиморфизма. Потому и дженериками там называются совсем другие вещи.
_>Нормальный там параметрический полиморфизм, просто он времени компиляции.
Параметрический полиморфизм, как и все что касается типов, бывает только времени компиляции. Речь о том, что то, что есть в плюсах не типизируется и потому типов как-то особо и не касается, а больше похоже на кодогенерацию.
_>Если мы посмотрим на язык D (развивающий дальше эту концепцию), то там во время компиляции можно вообще выполнять практически произвольный пользовательский код. И это можно использовать для очень разных интересных возможностей. Например можно ввести полноценный (а не встроенный в язык, как Спирит) DSL, файлы которого будут парситься в процессе компиляции некого D кода и это всё вместе будет превращаться в единый бинарники с полными оптимизациями, включая инлайны. Это несколько другой уровень программирования вообще.
Не понимаю, зачем протягивать в язык метапрограммирование через такую гм... заднюю дверь. Я D не знаю, но судя по увиденным примерам, это именно метапрограммирование, а не код на тайплевеле как в языках с полноценной системой типов т.е. с омегой/завтипами.
_>Кстати, а есть возможно указывать подобное руками или всё управляется только компилятором, а мы влиять не можем (кроме опций компилятора)? Т.е. можем ли мы сказать что например "вот данная сущность должна инлайниться вообще всегда"
Да, можем. Т.е. есть некоторые эвристики, обеспечивающие хороший результат автоматически, есть возможность регулировать эти эвристики (вроде указания своих лимитов на максимальный размер разверток и т.д.), а есть возможность ставить конкретные хинты для компилятора в коде, для крайних случаев, когда автоматика нужного результата не дает, вот это инлайнить, это ни в коем случае не инлайнить, это в интерфейсный файл, это специализировать для такого типа и т.д.
_>Под дженериками естественно Java/C# подразумевались и они заметно слабее варианта C++ именно по части обобщённого программирования.
В основном, да, но это не строгое подмножество возможностей. Они позволяют и такое, что в C++ невозможно.
_>Что касается Хаскеля, то там вообще другая концепция и сравнивать их напрямую глупо.
Почему? Параметрический полиморфизм совершенно точно есть и в хаскеле и в сишарпе и в яве. Просто в хаскеле даже без расширений возможностей больше, вроде абстрагирования от конструктора типа. Сравнивать вполне можно. В статье на которую я ссылку давал продемонстрированы подходы, которые отличаются гораздо сильнее.
_>P.S. Как я понял, ни одного примера заявленных (вами) преимуществ реализации ST/IO Хаскеля над другими языками мы так и не увидим... Несмотря на мои многочисленные напоминания об этом. Ну что же, ладно, так и запишем и закроем эту тему.
Неужели вы уже где-то запостили сравнение и критику "кода в большой монаде" или как там вы это называете и императивного? Думаете, если вы будете бесконечно требовать что-то от меня, полностью игнорируя мои требования я о них забуду? Сразу говорю: этого не произойдет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[22]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Много ли от "полной передачи владения" пользы в ФП, где коллекции персистентные и типична ситуация, когда на какую-то часть иммутабельной структуры данных куча ссылок от разных ее версий?
_>Хехе, первая часть этой фразы действительно относится к ФП вообще, а вот вторая относится уже всего лишь к одной из конкретных реализаций в конкретном языке.
Да ну? Иммутабельные структуры данных для того и нужны, чтоб иметь несколько версий, разделяющих значительную часть данных, одновременно. Какая же это специфика языка?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Насколько я понял, именно опыта там и не было. Вот что написано перед вышеприведённой цитатой: EP>
MLton does not use region-based memory management; it uses traditional GarbageCollection. We have considered integrating regions with MLton, but in our opinion it is far from clear that regions would provide MLton with improved performance, while they would certainly add a lot of complexity to the compiler and complicate reasoning about and achieving SpaceSafety. Region-based memory management and garbage collection have different strengths and weaknesses; it’s pretty easy to come up with programs that do significantly better under regions than under GC, and vice versa.
EP>То есть они рассматривали, но не пробовали.
Как не было? Одни разработчики компилятора SML (преимущественно экспериментального) — MLKit попробовали, сделали работающую реализацию, описали свой опыт в статьях. Другие разработчики другого компилятора SML (преимущественно "практического") — MLton, которые и сами собирались работать в этом направлении, оценили результаты как провальные и сами в этом направлении работать не стали. То, что вы цитируете — это именно из их заключения, но ссылки на статьи, на основании которых они его сделали там есть.
EP>Про "неработающие" замыкания в C++ из-за UFP любители GC мне тут уже третий раз говорят, хотя "плюсисты" не имеют с этим проблем. На деле же оказывается что работают, и не только для памяти.
Ну правильно: используют не ФЯ, идиомы не ФП — с чего бы им испытывать с этим проблемы, если все тропы протоптаны там, где их нет. Проблемы никуда не делись, просто они обходятся. Если же такие "решения" будут в ФП языке и программировать на нем будут с использованием ФП идиом — эти несчастные поимеют все проблемы по полной программе.
EP>ФП нужно, но не везде.
Особенно оно не нужно там, где невозможно.
EP>Никто не говорил что высокоуровневое программирование не нужно. Высокоуровневое это далеко не только ФП.
Точно, еще и ЛП есть. Как в плюсах с ЛП? Хотя чего там, с ним везде плохо.
EP>Как минимум есть решение UFP в виде копирования (что является именно решением согласно wiki).
Это, конечно, здорово, что какой-то обидевшийся за свой язык без решения UFP (тут просто бездна вариантов, конечно), написал это в викистатье, но вы сами-то рассудите здраво: копирование появилось задолго до того, как изобрели ссылки и сформулировали UFP. Как же так получается? Придумали проблему через годы после решения?
EP>Причём это работает не только для памяти.
Оно "работает" не только для памяти именно потому, что нормально не работает для памяти. Про странное сшивание управления дефицитными ресурсами с ресурсами которые в высокоуровневых языках дефицитными не считаются я уже в соседнем посте упоминал.
В языках же с GC с этим начинаются проблемы, и раз там нет нормального решения для этого варианта UFP, то естественно проблема декларируется несущественной/надуманной/нереальной/непрактичной:
Да ну? А что вы скажете о том, когда проблемой UFP называют что-то иное, и на этом основании объявляют решенной.
Ладно, вы можете считать UFP все что угодно, я просто сформулирую свой критерий поддержки ФП другими словами, в контексте разговора понятными: нет работающего [&] — нет базовой поддержки ФП.
EP>Из дочернего региона в родительский возвращаются сами handle'ы, а не замыкания с хэндлами внутри?
Вообще-то смысл систем с регионами в том, чтоб предотвратить утечку хэндла из региона, но "при этом действия с ресурсами могут быть interleaved, и зависить один от другого". Вам же нужна система автоматизации утекания хендлов в неизвестном направлении, о бессмысленности которой я не устаю повторять. Т.е. вы отождествляете систему управления ресурсами, требующими систему вроде регионов (файлов), и систему управления ресурсами, которые дефицитными не являются и потому могут управляться системой, ограничения "регионов" преодолевающей. В плюсах принципиальной разницы между ресурсами может и нет, но низкоуровневый язык на таком основании не построить. Полное решение UFP как раз и требует второй системы, а идиоматический код, который пишут в языках с решенной UFP использует ее по полной программе.
Соответственно, и использовать одну и ту же систему для управления обеими категориями ресурсов мы не можем.
EP>это же совсем не то, мы же про UFP говорим.
Вот именно. Говорили про UFP а вы все какое-то закрытие ресурсов по завершении использования приплетаете. Просто как в анекдоте про студента, который выучил только билет про блох, а попался вопрос про рыб.
EP>Собираются все действия над всеми ресурсами в одном месте, причём они могут быть interleaved, и зависить один от другого. EP>В описанном же выше варианте действия над одним ресурсом собираются в одном месте, и только в нём. Это и есть ограничение.
В описанном выше варианте речь именно о "действия над всеми ресурсами в одном месте, причём они могут быть interleaved, и зависить один от другого".
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Хороший пример цикла привнесённого самим языком.
В данном случае — идиоматическим ФП-кодом. На языке можно вычисление числе Фибоначчи и как на паскале написать. Другое дело — зачем тогда вообще ФЯ пользоваться?
EP>Кстати, про эффективность, а как thunk'и обновляются в многопоточной среде?
Глава 3
EP>Это пример разделяемого владения. Если у нас есть персистентная и полностью иммутабельная структура, типа rope, где ссылки и узлы образуют directed acyclic graph — то прекрасно подходит ref-counting.
Ну да, а еще на эти узлы будут ссылки из структур с циклами. Да и в ФП rope будет скорее построена на структуре данных, использующей ленивость вроде finger-tree.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Это же и есть upwards funarg? K>Нет, это сначала непонятно на чем основанное связывание prompt finalization проблемы и UFP, констатация простого факта, что их решения сочетаются плохо и выведение отсюда того, UFP не решается.
Оставим prompt finalization в стороне. Вот есть у нас using на ресурс в C#, или регион в Haskell — можем ли мы сделать замыкание на идентификатор ресурса (в funarg ведь про идентификаторы речь) и передать это замыкание наверх?
EP>>Не так. ФП нужно, но далеко не везде. Писать на C++ только в ФП стиле не имеет смысла. K>Я сильно сомневаюсь, что писать на C++ в ФП стиле не то что имеет смысл, а вообще возможно. Если только не трактовать ФП стиль сильно расширительно.
The following table shows which languages support functional programming (by supporting first-class functions) and for which the functional style is the dominant one.
В этой табличке для C++: support functional programming by supporting first-class function
functional style is NOT the dominant one
EP>>В том примере нужна не ленивость, а monadic код. Ленивость помогла только в одном случае из двух, и как видно в общем случае не позволяет сделать обычный код монадичным. K>Ничего не понимаю. Ленивость не делает код монадическим. Она нужна, чтоб функции, полученные как результат комбинации других не делали лишние вычисления/проходы. Т.е. в обсуждаемом случае нужна, чтоб монадический код нормально работал.
Для монады Maybe, ленивость позволяет foldr работать так, как работал бы foldrm.
K>И что за один случай из двух?
foldl
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Я сильно сомневаюсь, что писать на C++ в ФП стиле не то что имеет смысл, а вообще возможно. Если только не трактовать ФП стиль сильно расширительно.
Только вот в большинстве случаев ФП не эффективно, так что используют подобное редко, скорее для развлечения. Причём речь не реализации ФП в каком-то конкретном языке, а о противоречие самих принципов ФП оптимальной производительности.
Простой пример. Вот делаем мы фильтрацию видео в реальном времени, причём набор фильтров настраивается пользователем. Казалось бы чисто алгоритмическая задачка и оптимальна для ФП. Но что мы получим, следуя классическим принципам ФП, типа иммутабельности данных? Допустим у нас будет десяток фильтрующих функций (последовательно применяющихся, в зависимости от настроек пользователя) и каждая из них должна будет создавать новую копию кадра (а это между прочим 2 миллиона точек по 2 или 4 байта)? И это всё 30 или 60 раз в секунду? А уж как кэш процессора реагирует на подобные вещи... ))) В то время как в любом императивном языке у нас будет работать ровно один буфер для данных, начиная от захвата и заканчивая выводом кадра. Причём для всех кадров. И все функции будут спокойно работать с этим буфером.
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Про "неработающие" замыкания в C++ из-за UFP любители GC мне тут уже третий раз говорят, хотя "плюсисты" не имеют с этим проблем. На деле же оказывается что работают, и не только для памяти. K>Ну правильно: используют не ФЯ, идиомы не ФП — с чего бы им испытывать с этим проблемы, если все тропы протоптаны там, где их нет.
Нет — речь была не про ФП.
EP>>ФП нужно, но не везде. K>Особенно оно не нужно там, где невозможно.
Особенно оно не нужно там, где плохо мэппится в реальное железо.
EP>>Никто не говорил что высокоуровневое программирование не нужно. Высокоуровневое это далеко не только ФП. K>Точно, еще и ЛП есть. Как в плюсах с ЛП? Хотя чего там, с ним везде плохо.
В сам язык ЛП не встроено. Но возможны библиотечные средства, причём как runtime, так и compile-time (на базе шаблонов или чистых функций).
EP>>Как минимум есть решение UFP в виде копирования (что является именно решением согласно wiki). K>Это, конечно, здорово, что какой-то обидевшийся за свой язык без решения UFP (тут просто бездна вариантов, конечно), написал это в викистатье,
Приведите другое определение UFP.
K>но вы сами-то рассудите здраво: копирование появилось задолго до того, как изобрели ссылки и сформулировали UFP. Как же так получается? Придумали проблему через годы после решения?
Очевидно же: у проблем могут быть разные решения, с разными свойствами.
Например не во всех языках встроен удобный deep copy.
EP>>Причём это работает не только для памяти. K>Оно "работает" не только для памяти именно потому, что нормально не работает для памяти.
Почему не работает для памяти?
K>Про странное сшивание управления дефицитными ресурсами с ресурсами которые в высокоуровневых языках дефицитными не считаются я уже в соседнем посте упоминал.
Они не считаются дефицитными до тех пор, пока GC не начинает захлёбываться.
Например GC'шники знают про stop-the-wrold, generations, off-heap, фрагментация Large Object Heap и т.п., подстраивают свой код соответствующим образом — и это как раз потому, что нет никакого "just works".
EP>>В языках же с GC с этим начинаются проблемы, и раз там нет нормального решения для этого варианта UFP, то естественно проблема декларируется несущественной/надуманной/нереальной/непрактичной: K>Да ну? А что вы скажете о том, когда проблемой UFP называют что-то иное, и на этом основании объявляют решенной.
1. UFP объявлен решённым, потому что есть несколько вариантов решения. Один из которых явно называется решением в wiki.
2. UFP — это передача замыкания выше области free variables, так? Free variable может чем угодно, а не только памятью
K>Ладно, вы можете считать UFP все что угодно, я просто сформулирую свой критерий поддержки ФП другими словами, в контексте разговора понятными: нет работающего [&] — нет базовой поддержки ФП.
Работающего [&] не будет даже при включённом GC. Даже при использовании GC нужен будет [=]
EP>>Из дочернего региона в родительский возвращаются сами handle'ы, а не замыкания с хэндлами внутри? K>Вообще-то смысл систем с регионами в том, чтоб предотвратить утечку хэндла из региона, но "при этом действия с ресурсами могут быть interleaved, и зависить один от другого".
Вообще-то вопрос был про то, как в Haskell передать замыкание с ресурсом-free-variable наверх. Region'ы судя по всему это проблему никак не решают, поэтому вопрос остаётся открытым.
K>Вам же нужна система автоматизации утекания хендлов в неизвестном направлении, о бессмысленности которой я не устаю повторять.
Ну да, нет нормального решения — "бессмысленно"
K>Т.е. вы отождествляете систему управления ресурсами, требующими систему вроде регионов (файлов), и систему управления ресурсами, которые дефицитными не являются и потому могут управляться системой, ограничения "регионов" преодолевающей.
Я просто прошу показать, или описать — как подобное возможно в Haskell. Какими средствами это будет достигнуто неважно (неважно будет ли эта система тождественна управлению дефицитными ресурсами или нет) — важен результат.
EP>>это же совсем не то, мы же про UFP говорим. K>Вот именно. Говорили про UFP а вы все какое-то закрытие ресурсов по завершении использования приплетаете. Просто как в анекдоте про студента, который выучил только билет про блох, а попался вопрос про рыб.
public delegate void fireworks();
public static fireworks fire()
{
using (var fs = File.Open("file", FileMode.Open))
{
return () => fs.Read(new byte[10], 0, 10);
}
}
1. замыкание есть?
2. free-variable в замыкании есть?
3. замыкание передаётся выше области free-variable?
EP>>Собираются все действия над всеми ресурсами в одном месте, причём они могут быть interleaved, и зависить один от другого. EP>>В описанном же выше варианте действия над одним ресурсом собираются в одном месте, и только в нём. Это и есть ограничение. K>В описанном выше варианте речь именно о "действия над всеми ресурсами в одном месте, причём они могут быть interleaved, и зависить один от другого".
Это в этом варианте:
K>Более-менее осмысленное решение, это делать функцию вида ЭтоНамНадоЧтобПолучитьРесурс -> (ОткрытыйРесурс -> Результат) -> Результат, которая сначала собирает через второй аргумент функции, которые что-то будут с ресурсом делать, а потом выполняется сама, открывая ресурс, скармливая всем этим функциям и закрывая его. Т.е. те самые брекеты и их развитие вроде pipes-safe и resourcet.
?
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В данном случае — идиоматическим ФП-кодом. На языке можно вычисление числе Фибоначчи и как на паскале написать. Другое дело — зачем тогда вообще ФЯ пользоваться?
Что означает "идиоматический ФП-код"? Это синоним кода который тормозит?
Кстати, про <b>числа Фибоначчи через мемоизацию</b>.
EP>>Кстати, про эффективность, а как thunk'и обновляются в многопоточной среде? K>Глава 3
То есть на равном месте вводится межпоточная синхронизация, об этом и речь.
Кстати, а что делать с thunk'ом который точно не будет использоваться, но держит ссылку на большую структуру или ресурс? Утечка?
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Вообще, то, что называется обобщенным программированием в С++ и других языках, где возможности для него появились в ходе развития языка, в языках где такие возможности были с самого начала вроде хаскеля никак специально не называется. Ну, нет ситуации, когда есть сформированная культура кодирования, и вдруг появляется новая, с использованием параметрического полиморфизма. Потому и дженериками там называются совсем другие вещи.
Так с этим никто и не спорит. Собственно поэтому термин "обобщённое программирование" и относят обычно к указанным языкам, хотя в Хаскеле это тоже полностью реализовано.
K>Параметрический полиморфизм, как и все что касается типов, бывает только времени компиляции. Речь о том, что то, что есть в плюсах не типизируется и потому типов как-то особо и не касается, а больше похоже на кодогенерацию.
Работа во время компиляции просто разная может быть. Возможно строго по правилам компилятора и всё. А возможно по указаниям программиста. )
K>Не понимаю, зачем протягивать в язык метапрограммирование через такую гм... заднюю дверь. Я D не знаю, но судя по увиденным примерам, это именно метапрограммирование, а не код на тайплевеле как в языках с полноценной системой типов т.е. с омегой/завтипами.
Речь немного не о том. Вот допустим у нас есть некая чистая функция. В Хаскеле или C++ (у C++ есть свои способы исполнения кода во время компиляции, но он должен быть сформирован очень особым образом и имеет много ограничений) мы можем её исполнить только в рантайме. В D мы можем спокойно вызвать прямо эту функцию во время компиляции (при условии, что передадим ей данные, доступные во время компиляции, но это может быть и например содержимое внешнего файла). Причём в этом случае компилятор именно исполнит всё и вставит результат (кстати возможно тоже код) в бинарник, а кода самой функции там не будет вообще.
Т.е. мы можем писать нормальный регулярный код, например интерпретатора некого языка. Этот код вполне можно использовать в рантайме с произвольными файлами. А можно заставить выполнить на этапе компиляции, передав ему некие файлы на том языке. Причём это всё соберётся в бинарник с супербыстродействием. Кстати, это всего лишь один из примеров использования подобной возможности языка, но он совсем не теоретический, а реализован в весьма интересном, удобном и естественно крайне быстродействующем веб-фреймворке.
Естественно это всё уже не относится к теме обобщённого программирования — это я просто отвлёкся на пересекающуюся тему.
K>Почему? Параметрический полиморфизм совершенно точно есть и в хаскеле и в сишарпе и в яве. Просто в хаскеле даже без расширений возможностей больше, вроде абстрагирования от конструктора типа. Сравнивать вполне можно. В статье на которую я ссылку давал продемонстрированы подходы, которые отличаются гораздо сильнее.
Я же говорю, напрямую нет смысла сравнивать. А по возможностям вполне можно.
K>Неужели вы уже где-то запостили сравнение и критику "кода в большой монаде" или как там вы это называете и императивного? Думаете, если вы будете бесконечно требовать что-то от меня, полностью игнорируя мои требования я о них забуду? Сразу говорю: этого не произойдет.
Да пожалуйста. ))) Такое впечатление, что демонстрация аргументации под ваши тезисы — это мне надо. ))) Ну нет, так нет. Значит тот ваш тезис так и останется просто болтовнёй. )
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Да ну? Иммутабельные структуры данных для того и нужны, чтоб иметь несколько версий, разделяющих значительную часть данных, одновременно. Какая же это специфика языка?
С чего бы это? Иммутабательные структуры нам нужны для того, чтобы у функций не было состояний. Не надо путать принципы ФП и конкретную реализацию. Если вы замените в реализации ФП языка все ссылки на копирования, то абсолютно ничего, кроме быстродействия, не изменится.
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>С чего бы это? Иммутабательные структуры нам нужны для того, чтобы у функций не было состояний. Не надо путать принципы ФП и конкретную реализацию. Если вы замените в реализации ФП языка все ссылки на копирования, то абсолютно ничего, кроме быстродействия, не изменится.
У функций не было состояний — это сильно. Состояние нужно что бы реализовывать поведение, то есть, зависимость выхода от предыстории вызовов.
Иммутабельность нужна для решения проблемы разделяемых ресурсов. Вместо того, что бы придумывать логику владения, синхронизации и тд, делается копия для которой есть гарантия, что все такие же экземпляры будет эквивалентны.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Только вот в большинстве случаев ФП не эффективно
Каким образом мерить эффективность?
> так что используют подобное редко, скорее для развлечения. Причём речь не реализации ФП в каком-то конкретном языке, а о противоречие самих принципов ФП оптимальной производительности.
ФП ничему не противоречит. Ты путаешь особенности вычислителя и требования ФП.
_>Простой пример. Вот делаем мы фильтрацию видео в реальном времени, причём набор фильтров настраивается пользователем. Казалось бы чисто алгоритмическая задачка и оптимальна для ФП.
Из чего следует это "казалось бы" ?
>Но что мы получим, следуя классическим принципам ФП, типа иммутабельности данных? Допустим у нас будет десяток фильтрующих функций (последовательно применяющихся, в зависимости от настроек пользователя) и каждая из них должна будет создавать новую копию кадра (а это между прочим 2 миллиона точек по 2 или 4 байта)? И это всё 30 или 60 раз в секунду? А уж как кэш процессора реагирует на подобные вещи... ))) В то время как в любом императивном языке у нас будет работать ровно один буфер для данных, начиная от захвата и заканчивая выводом кадра. Причём для всех кадров. И все функции будут спокойно работать с этим буфером.
А теперь представь себе распределенное приложение. Внезапно <любой императивный язык> слился весьма бесславно. Ты, конечно, можешь выкрутиться навроде "даже если одна функция написана на С++" значит и всё приложение написано на С++.
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
S>>Проблема в том, что вы заранее не знаете, где какой код. У вас может смешиваться код, "знающий", что такое optional, и код, который ничего о нём не знает. Чтобы это решить, вам придётся либо явно описывать упаковку/распаковку в перегрузках LibFunc, либо всё-таки сделать из Optional монаду.
_>Ну так если в вашем пример функции уже есть упаковка в optional, то почему бы не быть и распаковке? )
Выдай правило, которое расскажет когда же делать эту распаковку, а когда — нет.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
K>>Вот именно. Говорили про UFP а вы все какое-то закрытие ресурсов по завершении использования приплетаете. Просто как в анекдоте про студента, который выучил только билет про блох, а попался вопрос про рыб.
EP>
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Цель абстракции — описать мир, причём эффективно, а не придумать его. Пока у нас у всех фон-Нейманавские машины — чистый ФП будет находится на академической обочине.
Вычислители уже давно переросли фон-Неймановскую архитектуру. Пример — распределенные вычисления.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Причём это работает не только для памяти. K>>Оно "работает" не только для памяти именно потому, что нормально не работает для памяти.
EP>Почему не работает для памяти?
Потому что надо руками следить за тем, что где будет как копироваться-передаваться-использоваться.
K>>Про странное сшивание управления дефицитными ресурсами с ресурсами которые в высокоуровневых языках дефицитными не считаются я уже в соседнем посте упоминал.
EP>Они не считаются дефицитными до тех пор, пока GC не начинает захлёбываться. EP>Например GC'шники знают про stop-the-wrold, generations, off-heap, фрагментация Large Object Heap и т.п., подстраивают свой код соответствующим образом — и это как раз потому, что нет никакого "just works".
У плюсовиков балласта гораздо больше — указатели, смартпоинтеры, операторы копирования, приведения типа, счетчики ссылок, строки, аллокаторы, хипы, пулы и тд и тд.
Я бы сказал что нативный и менеджед миры изоморфны, т.е. любой из баззвордов типа "generations" имеет прямое отражение в с++.
Разница всего лишь в кривой вхождения. Если в менеджед эти баззворды нужны для экспертов, то в С++ первые три года люди получают самые азы — указатели, смартпоинтеры, счетчики ссылок и тд и тд и тд
Без этого просто нереально разрабатывать на с++.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Да пожалуйста. ))) Такое впечатление, что демонстрация аргументации под ваши тезисы — это мне надо. ))) Ну нет, так нет. Значит тот ваш тезис так и останется просто болтовнёй. )
Я тут на выходных посмотрел этот тред и чет не пойму твоих стонов про IO/ST в Хаскеле, поставил даже wxHaskell и wxwidgets и всё равно не ясно.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
1. замыкание есть? EP>>2. free-variable в замыкании есть? EP>>3. замыкание передаётся выше области free-variable? I>Ты снова путаешь замыкания и управление ресурсами.
Для начала ответь на вопросы выше — там про управление ресурсами ничего не сказано.
I>Можно ли в замыкание С++ передать скажем, неинициализированый указатель или указатель на освобожденную память ?
Можно, точно также как и в других языках:
public delegate void fireworks();
public static fireworks fire()
{
unsafe
{
int x = 11;
int* p1 = &x, p2 = null;
return () => { *p1 = 111; Console.WriteLine("alive!"); *p2 = 111; };
}
}
public static void Main()
{
var closure = fire();
closure();
}
:
I>Опаньки !
Re[23]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Цель абстракции — описать мир, причём эффективно, а не придумать его. Пока у нас у всех фон-Нейманавские машины — чистый ФП будет находится на академической обочине. I>Вычислители уже давно переросли фон-Неймановскую архитектуру. Пример — распределенные вычисления.
Узлы до сих пор фон-Неймановские
Что же касается организации распределённых вычислений — то да, тут естественно используются некоторые элементы присущие ФП стилю.
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Узлы до сих пор фон-Неймановские
Это чтото новое, очень интересное — внезапно архитектура системы определяется архитектурой подсистем.
Надо полагать танковый батальон устроен точно так же как и танк ?
EP>Что же касается организации распределённых вычислений — то да, тут естественно используются некоторые элементы присущие ФП стилю.
Некоторые элементы присущие ФП стилю используюся везде. Сейчас 90% кода это не нативный код и в ём обычное дело функциональщина.
Более того — ФП влазло и в нативный код.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Для начала ответь на вопросы выше — там про управление ресурсами ничего не сказано.
Ну разумеется, всё есть.
I>>Можно ли в замыкание С++ передать скажем, неинициализированый указатель или указатель на освобожденную память ?
EP>Можно, точно также как и в других языках:
То есть — аналогичная проблема — вернуть в лямбде мусор есть и в С++. Или в С++ есть некий фокус компилятора, благодаря которому юзер догадается что надо написать специальный оператор присваивания или конструктор копирования ?
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Оставим prompt finalization в стороне. Вот есть у нас using на ресурс в C#, или регион в Haskell
Ну да. Оставляем prompt finalization в стороне и сразу переходим к prompt finalization!
EP>можем ли мы сделать замыкание на идентификатор ресурса (в funarg ведь про идентификаторы речь) и передать это замыкание наверх?
В C# можем, в хаскеле есть средства для предотвращения этого а-ля ST.
EP>На haskell.org написанно: EP>
EP>The following table shows which languages support functional programming (by supporting first-class functions) and for which the functional style is the dominant one.
EP>В этой табличке для C++: EP>support functional programming by supporting first-class function EP>functional style is NOT the dominant one
А если я в какой-нибудь вики напишу, что луна из сыра — вы поверите? Ну попробуйте тот же функциональный "хэллоуворлд" на C++ написать
И расскажете потом, сильно ли вам помогло то, что в какой-то вики написано, что C++ поддерживает ФП.
EP>Для монады Maybe, ленивость позволяет foldr работать так, как работал бы foldrm.
Не знаю, что вы подразумеваете под foldrm, foldr работает как foldr, а foldM совсем другая функция:
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
т.е. сворачивание с эффектом.
foldr же в обсуждаемом примере просто расставляет лифтнутые (+) между элементами списка.
foldr (+) :: (Monad m, Num a) => m a -> [m a] -> m a
EP>foldl
Ленивость позволяет не вычислять невостребованное. А левая свертка cons списка востребует все, да еще как!
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Только вот в большинстве случаев ФП не эффективно, так что используют подобное редко, скорее для развлечения.
Да, чтоб производительность ФП-кода была более-менее приемлемой нужна серьезная поддержка как от компилятора, так и от рантайма.
_>Причём речь не реализации ФП в каком-то конкретном языке, а о противоречие самих принципов ФП оптимальной производительности.
Это, в основном, верно.
_>Простой пример. Вот делаем мы фильтрацию видео в реальном времени, причём набор фильтров настраивается пользователем. Казалось бы чисто алгоритмическая задачка и оптимальна для ФП. Но что мы получим, следуя классическим принципам ФП, типа иммутабельности данных? Допустим у нас будет десяток фильтрующих функций (последовательно применяющихся, в зависимости от настроек пользователя) и каждая из них должна будет создавать новую копию кадра (а это между прочим 2 миллиона точек по 2 или 4 байта)? И это всё 30 или 60 раз в секунду? А уж как кэш процессора реагирует на подобные вещи... ))) В то время как в любом императивном языке у нас будет работать ровно один буфер для данных, начиная от захвата и заканчивая выводом кадра. Причём для всех кадров. И все функции будут спокойно работать с этим буфером.
Мутабельность данных никак не противоречит идиоматическому ФП-подходу, если она семантически ненаблюдаема. Даже в обсуждаемом по соседству "хэллоуворлде" данные под капотом мутируются со страшной силой. Так и в вашем примере, промежуточные структуры данных не нужны, если не разделяются между несколькими потребителями, а просто передаются от производителя к одному потребителю.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Нет — речь была не про ФП.
Да. Разговор был именно о ФП, точнее о том, что усилия необходимые для использования зачаточного фп-стиля в C++ превышают бенефиты от использования зачаточного ФП-стиля.
EP>Особенно оно не нужно там, где плохо мэппится в реальное железо.
ФП, да и вообще высокоуровневый код обычно плохо мэппится на реальное железо. Высокоуровневый код хорошо мэппится на человеческие мозги. Тут именно трейдофф между первым и вторым.
EP>В сам язык ЛП не встроено. Но возможны библиотечные средства, причём как runtime, так и compile-time (на базе шаблонов или чистых функций).
Речь о том, что реализаций ЛП-языков даже с таким уровнем практичности в качестве языков общего назначения как у ФЯ в настоящее время не существует и не ожидается.
EP>Приведите другое определение UFP.
Захват в замыкание З ссылки на A продлевает жизнь А по крайней мере на время жизни замыкания З.
EP>Почему не работает для памяти?
Потому, что в высокоуровневых языках есть гарантия (разной степени силы/слабости, но достаточно хорошая, чтоб на нее можно было полагаться), что ссылка на некую языковую сущность работает: пока доступна ссылка, языковая сущность (объект в ООП, например) также существует. Такой гарантии в C++ нет.
EP>Они не считаются дефицитными до тех пор, пока GC не начинает захлёбываться.
Да, но этого достаточно, потому что в большинстве случаев он работает нормально. Исчерпать ресурсы, которые классифицируются как "дефицитные" несравнимо проще.
EP>Например GC'шники знают про stop-the-wrold, generations, off-heap, фрагментация Large Object Heap и т.п., подстраивают свой код соответствующим образом — и это как раз потому, что нет никакого "just works".
В основном есть. Потому, что сама система управления памяти "компактифицирующий GC с поколениями и некомпактифицируемым хипом для больших объектов" — это подстройка под типичный ООП/ФП код, обеспечивающий хорошую производительность для идиоматического кода. Проблемы начинаются после выхода из этой "благоприятной" области, на которую система и настроена.
EP>2. UFP — это передача замыкания выше области free variables, так? Free variable может чем угодно, а не только памятью
Free variable не может быть чем угодно. Это языковая сущность. "Память" — это уже другой, нижележащий уровень абстракции. UFP гарантирует продление жизни языковой сущности. Т.е. объекта File, а не файла, хендлером для которого этот файл является.
EP>Работающего [&] не будет даже при включённом GC. Даже при использовании GC нужен будет [=]
В высокоуровневом языке различие между передачей по ссылке и копированием вообще чаще всего семантически ненаблюдаемо. Соотвественно и никаких настроечных ручек у замыканий нет.
EP>Вообще-то вопрос был про то, как в Haskell передать замыкание с ресурсом-free-variable наверх. Region'ы судя по всему это проблему никак не решают, поэтому вопрос остаётся открытым.
Регионы предотвращают утечку ресурса.
EP>Ну да, нет нормального решения — "бессмысленно"
Но его нет. То, что вы считаете нормальным решением в условиях высокоуровневого языка нормальным не является. Связывание управления памятью с управлением дефицитными ресурсами там ни к чему хорошему не приводит.
EP>Я просто прошу показать, или описать — как подобное возможно в Haskell. Какими средствами это будет достигнуто неважно (неважно будет ли эта система тождественна управлению дефицитными ресурсами или нет) — важен результат.
Усилия при разработке библиотек для работы с дефицитными ресурсами в хаскеле направлены на то, чтоб это было невозможно.
EP>
Есть.
EP>3. замыкание передаётся выше области free-variable?
Да.
При использовании using с корректностью замыкания ничего не случится, время жизни объекта-хендлера будет продлено, но файл для которого он является хендлером будет закрыт в момент возвращения лямбды из функции. Если using убрать, то управление открытием файла будет связано с управлением временем жизни его хендлера-объекта. Память, занятая объектом будет переиспользована не раньше, чем объект перестанет быть доступным (что требуется для решения UFP), произойдет это через какое-то зависящее от разных обстоятельств время (что продиктовано свойствами системы управления памятью). Через какое-то время, зависящее от разных обстоятельств, после этого выполнится и код, закрывающий файл (что создает проблему для prompt finalization). Но не существует никакой гарантии, что это не произойдет до завершения жизни объекта-хендлера. Т.е. решить и UFP и проблему prompt finalization управляя двумя видами ресурсов одним способом нельзя.
EP>Это в этом варианте?
А в чем вы видите противоречие? Вы с тем, на что я ссылался ознакомились?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Что означает "идиоматический ФП-код"?
Комбинирование комбинаторов.
EP>Это синоним кода который тормозит?
Да. Чтоб такой код работал с более-менее приемлемой скоростью нужен специальный рантайм, заточенный под такие вещи и компилятор со специфическими оптимизациями. Поэтому в каком-нибудь гибриде, в который добавили функциональных фич потому, что это "модно" идиоматический ФП код (если его еще и получится написать) запросто может отличаться по производительности от кода а-ля фортран как скриптовый язык от компилируемого статтипизированного.
EP>То есть на равном месте вводится межпоточная синхронизация, об этом и речь.
А вы точно читали то, на что я ссылаюсь?
EP>Кстати, а что делать с thunk'ом который точно не будет использоваться, но держит ссылку на большую структуру или ресурс? Утечка?
"Точно не будет использоваться" только thunk, который ниоткуда не доступен — такой будет собран ГЦ (неизвестно, правда, когда). А вот thunk, который не использовался, хотя точно об этом можно сказать только по завершению работы программы — это да, утечка.
Чтоб организовать утечку, собственно, не требуется что-то никогда не использовать. Достаточно производить thunk-и медленнее, чем они потребляются.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так с этим никто и не спорит. Собственно поэтому термин "обобщённое программирование" и относят обычно к указанным языкам, хотя в Хаскеле это тоже полностью реализовано.
Не вижу никаких проблем, если программист на C++ называет такой подход и в хаскеле обобщенным программированием, особенно если обращается к другому программисту на C++ (работа по сравнению подходов, на которую я ссылался, сделана в рамках разработки концептов).
_>Работа во время компиляции просто разная может быть. Возможно строго по правилам компилятора и всё. А возможно по указаниям программиста. )
Это как-то можно раскрыть?
_>Речь немного не о том. Вот допустим у нас есть некая чистая функция. В Хаскеле или C++ (у C++ есть свои способы исполнения кода во время компиляции, но он должен быть сформирован очень особым образом и имеет много ограничений) мы можем её исполнить только в рантайме. В D мы можем спокойно вызвать прямо эту функцию во время компиляции (при условии, что передадим ей данные, доступные во время компиляции, но это может быть и например содержимое внешнего файла). Причём в этом случае компилятор именно исполнит всё и вставит результат (кстати возможно тоже код) в бинарник, а кода самой функции там не будет вообще.
Именно об этом. Ничего удивительного в этом как раз нет. В более-менее нормальных языках такое доступно:
{-# LANGUAGE TemplateHaskell #-}module Main (main) where
import Language.Haskell.TH.Syntax
-- main = print $ sum [1 .. 10000000 :: Integer] -- считаем в рантайме
main = print $(lift $ sum [1 .. 10000000 :: Integer]) -- считаем во время компиляции
Обычное метапрограммирование, параметрический полиморфизм тут не причем.
_>Причём это всё соберётся в бинарник с супербыстродействием.
Это точно про D? Он вроде супербыстродействием никогда похвастать не мог.
_>Я же говорю, напрямую нет смысла сравнивать. А по возможностям вполне можно.
Почему нет смысла сравнивать напрямую?
_>Да пожалуйста. ))) Такое впечатление, что демонстрация аргументации под ваши тезисы — это мне надо. ))) Ну нет, так нет. Значит тот ваш тезис так и останется просто болтовнёй. )
Такое впечатление, что демонстрация аргументации под ваши тезисы — это мне надо. Ну нет, так нет. Значит тот ваш тезис про "ужасы большой монады" так и останется просто болтовнёй.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[24]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Да ну? Иммутабельные структуры данных для того и нужны, чтоб иметь несколько версий, разделяющих значительную часть данных, одновременно. Какая же это специфика языка?
_>С чего бы это? Иммутабательные структуры нам нужны для того, чтобы у функций не было состояний. Не надо путать принципы ФП и конкретную реализацию. Если вы замените в реализации ФП языка все ссылки на копирования, то абсолютно ничего, кроме быстродействия, не изменится.
ОК, разделять данные между версиями в теории не обязательно. Но никакой специфики языка тут нет. В библиотеках для ФЯ эти структуры реализуются так, что данные разделяются.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>>>Кстати, про эффективность, а как thunk'и обновляются в многопоточной среде? K>>>Глава 3 EP>>То есть на равном месте вводится межпоточная синхронизация, об этом и речь. K>А вы точно читали то, на что я ссылаюсь?
Точно. Там используется lock-free алгоритм для межпоточной синхронизации
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Узлы до сих пор фон-Неймановские I>Это чтото новое, очень интересное — внезапно архитектура системы определяется архитектурой подсистем.
Ты вообще о чём? Распределённая система не снимает необходимости написания кода для узлов.
Если код для узлов будет в 10x раз медленней, то самих узлов понадобится минимум в 10x раз больше, а то и в 50x — за счёт расходов на коммуникацию
I>Надо полагать танковый батальон устроен точно так же как и танк ?
Танковый батальон — он "танковый", а не "пехотный". И между "танковыми батальоном" и "пехотным" — огромная разница
EP>>Что же касается организации распределённых вычислений — то да, тут естественно используются некоторые элементы присущие ФП стилю. I>Некоторые элементы присущие ФП стилю используюся везде.
И это же действительно хорошо — у этих элементов есть полезные свойства, которые часто необходимы
По большому счёту ФП элементы нужно использовать там где возможно, а использовать ИП — там где необходимо. Мой тезис в том, что использовать чистый ФП везде — достаточно непрактично, например с точки зрения производительности.
Я, например, стараюсь: делать чистые функции, там где чистые не получаются — регулярные, использовать функции высшего порядка — они часто являются действительно удобными, использовать non-member functions вместо методов, использовать ленивость по мере необходимости, использовать неизменяемые объекты или давать объектам value-semantics (привет referential transparency). Все эти элементы хорошо поддерживаются в C++, причём они прекрасно сочетаются с обычным ИП.
I>Более того — ФП влазло и в нативный код.
Подробнее.
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Это чтото новое, очень интересное — внезапно архитектура системы определяется архитектурой подсистем.
EP>Ты вообще о чём? Распределённая система не снимает необходимости написания кода для узлов. EP>Если код для узлов будет в 10x раз медленней, то самих узлов понадобится минимум в 10x раз больше, а то и в 50x — за счёт расходов на коммуникацию
Это цифры с потолка. Эрланг показывает и доказывает что твои рассуждения ошибочны.
I>>Надо полагать танковый батальон устроен точно так же как и танк ?
EP>Танковый батальон — он "танковый", а не "пехотный". И между "танковыми батальоном" и "пехотным" — огромная разница
Ну да, и устроен он как танк.
I>>Более того — ФП влазло и в нативный код.
EP>Подробнее.
Ты не заметил лямбды в С++ ? Чудеса !
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Для начала ответь на вопросы выше — там про управление ресурсами ничего не сказано. I>Ну разумеется, всё есть.
Значит есть UFP?
I>>>Можно ли в замыкание С++ передать скажем, неинициализированый указатель или указатель на освобожденную память ? EP>>Можно, точно также как и в других языках: I>То есть — аналогичная проблема — вернуть в лямбде мусор есть и в С++.
Да, в C++ в замыкании можно вернуть мусор, точно также как и в C# и в Haskell.
I>Или в С++ есть некий фокус компилятора, благодаря которому юзер догадается что надо написать специальный оператор присваивания или конструктор копирования ?
В каком случае? Если, например, в замыкание move'нуть unique_ptr — то оно будет movable, but not copyable — компилятор не даст скопировать такое замыкание.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Это чтото новое, очень интересное — внезапно архитектура системы определяется архитектурой подсистем. EP>>Ты вообще о чём? Распределённая система не снимает необходимости написания кода для узлов. EP>>Если код для узлов будет в 10x раз медленней, то самих узлов понадобится минимум в 10x раз больше, а то и в 50x — за счёт расходов на коммуникацию I>Это цифры с потолка. Эрланг показывает и доказывает что твои рассуждения ошибочны.
Какие именно рассуждения, и как он доказывает?
Кстати, про Erlang — выше приводили пример "идиоматичного ФП кода":
f = 0 : 1 : zipWith (+) f (tail f)
попробуй изобрази его на Erlang.
Да, и по-твоему Erlang это чистый ФП?
I>>>Надо полагать танковый батальон устроен точно так же как и танк ? EP>>Танковый батальон — он "танковый", а не "пехотный". И между "танковыми батальоном" и "пехотным" — огромная разница I>Ну да, и устроен он как танк.
Устроен танковый батальон естественно не как танк, но без танков нет батальона. Ты что сказать-то хотел своей метафорой?
I>>>Более того — ФП влазло и в нативный код. EP>>Подробнее. I>Ты не заметил лямбды в С++ ? Чудеса !
Это не чистое ФП, а как раз полезные его элементы. И "влазло" оно очень давно.
См. например STL — там же кругом value semantics (привет referential transparency) и higher order functions.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Для начала ответь на вопросы выше — там про управление ресурсами ничего не сказано. I>>Ну разумеется, всё есть.
EP>Значит есть UFP?
Есть.
I>>Или в С++ есть некий фокус компилятора, благодаря которому юзер догадается что надо написать специальный оператор присваивания или конструктор копирования ?
EP>В каком случае? Если, например, в замыкание move'нуть unique_ptr — то оно будет movable, but not copyable — компилятор не даст скопировать такое замыкание.
То есть, в кратце, тебе не нравится, что IDisposable это всего лишь рекомендация, и нет способа сделать это обязательным требованием. Правильно?
Вопрос — при чем здесь замыкания ?
RelationalFlatFileReader F()
{
using(var f = File.Open(...))
{
return new RelationalFlatFileReader{File = f};
}
}
Something удерживает и использует ссылку на File. Вопрос — очевидно ли, что
1 проблема та же, что и с замыканием ?
2 замыканий нигде нет ?
Снова вопрос — при чем здесь замыкания ?
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>Для начала ответь на вопросы выше — там про управление ресурсами ничего не сказано. I>>>Ну разумеется, всё есть. EP>>Значит есть UFP? I>Есть.
И в C# нет более-менее автоматического решения UFP для такого случая?
I>>>Или в С++ есть некий фокус компилятора, благодаря которому юзер догадается что надо написать специальный оператор присваивания или конструктор копирования ? EP>>В каком случае? Если, например, в замыкание move'нуть unique_ptr — то оно будет movable, but not copyable — компилятор не даст скопировать такое замыкание. I>То есть, в кратце, тебе не нравится, что IDisposable это всего лишь рекомендация, и нет способа сделать это обязательным требованием. Правильно?
Я просто привёл один из примеров UFP — для которого в C# и Haskell нет более-менее автоматического решения, а в C++ есть.
Даже если использовать определение UFP, которое ограничивается только памятью — то сама проблема никуда не девается, и то что она очень похожа на UFP — это факт.
I>Вопрос — при чем здесь замыкания ? I>[...] I>Something удерживает и использует ссылку на File. Вопрос — очевидно ли, что I>1 проблема та же, что и с замыканием ? I>2 замыканий нигде нет ? I>Снова вопрос — при чем здесь замыкания ?
Я согласен что подобная проблема существует и без замыканий. Возможно в UFP замыкания выделяются отдельным образом потому, что захват контекста происходит достаточно неявно.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Это цифры с потолка. Эрланг показывает и доказывает что твои рассуждения ошибочны.
EP>Какие именно рассуждения, и как он доказывает?
На нём пишутся распределенные системы, внезапно ! Эрланг собтсвенно и начал с того, что порвал С++ в распределенных приложениях для телекоммуникаций.
EP>Кстати, про Erlang — выше приводили пример "идиоматичного ФП кода": EP>
EP>f = 0 : 1 : zipWith (+) f (tail f)
EP>
попробуй изобрази его на Erlang. EP>Да, и по-твоему Erlang это чистый ФП?
Это скучно.
I>>>>Надо полагать танковый батальон устроен точно так же как и танк ? EP>>>Танковый батальон — он "танковый", а не "пехотный". И между "танковыми батальоном" и "пехотным" — огромная разница I>>Ну да, и устроен он как танк.
EP>Устроен танковый батальон естественно не как танк, но без танков нет батальона. Ты что сказать-то хотел своей метафорой?
Я говорю про отношение часть-целое и характеристики составляющих. У узла узкое место процессор и система ввода-вывода, а у распределенной системы узким местом будет не процессоры и ввод-вывод, а отзывчивость по причине корректности-качества работы диспетчера, которые, в свою очередь, могут никак не зависеть ни от процессора ни от ввода-вывода.
I>>Ты не заметил лямбды в С++ ? Чудеса !
EP>Это не чистое ФП, а как раз полезные его элементы. И "влазло" оно очень давно.
Ажно с первых версий stl.
EP>См. например STL — там же кругом value semantics (привет referential transparency) и higher order functions.
Вот-вот. Сколько лет stl ?
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>У функций не было состояний — это сильно. Состояние нужно что бы реализовывать поведение, то есть, зависимость выхода от предыстории вызовов.
Если это состояние хранится в самой функции, то это уже не ФП. А если передаётся в неё как параметр (и при этом естественно является иммутабельным), то никаких проблем.
I>Иммутабельность нужна для решения проблемы разделяемых ресурсов. Вместо того, что бы придумывать логику владения, синхронизации и тд, делается копия для которой есть гарантия, что все такие же экземпляры будет эквивалентны.
Не придумывай. ))) Это всего лишь одно из полезных побочных свойств ФП, а совсем не причина такого устройства. Более того, существование подобных плюсов проявилось относительно недавно, когда появилось многопоточное программирование и т.п., хотя языки с таким устройством существовали уже давным давно. )
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Каким образом мерить эффективность?
Ну да, я не совсем корректно сказал. Речь конечно же про быстродействие кода.
I>ФП ничему не противоречит. Ты путаешь особенности вычислителя и требования ФП.
Ты можешь предложить реализацию ФП с не иммутабельными данными? )
I>А теперь представь себе распределенное приложение. Внезапно <любой императивный язык> слился весьма бесславно. Ты, конечно, можешь выкрутиться навроде "даже если одна функция написана на С++" значит и всё приложение написано на С++.
Что ты подразумеваешь под "распределённым приложением"? Что-то типа MPI? И почему это любой императивный язык тут сливается? )
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Значит есть UFP? I>>Есть.
EP>И в C# нет более-менее автоматического решения UFP для такого случая?
Есть, с экземпляром класса File всё в порядке, он не разрушается и тд. Скажем, при подходе как в старом турбопаскале ты бы получил непойми что уже при попытке вызова метода, навроде Access Violation и тд.
I>>>>Или в С++ есть некий фокус компилятора, благодаря которому юзер догадается что надо написать специальный оператор присваивания или конструктор копирования ? EP>>>В каком случае? Если, например, в замыкание move'нуть unique_ptr — то оно будет movable, but not copyable — компилятор не даст скопировать такое замыкание. I>>То есть, в кратце, тебе не нравится, что IDisposable это всего лишь рекомендация, и нет способа сделать это обязательным требованием. Правильно?
EP>Я просто привёл один из примеров UFP — для которого в C# и Haskell нет более-менее автоматического решения, а в C++ есть.
UFP это про локальное состояние, т.е. когда функция теряет связь с локальными переменными. Не ресурсы теряет, а всего лишь переменные из скопа.
EP>Даже если использовать определение UFP, которое ограничивается только памятью — то сама проблема никуда не девается, и то что она очень похожа на UFP — это факт.
I>>Вопрос — при чем здесь замыкания ? I>>[...] I>>Something удерживает и использует ссылку на File. Вопрос — очевидно ли, что I>>1 проблема та же, что и с замыканием ? I>>2 замыканий нигде нет ? I>>Снова вопрос — при чем здесь замыкания ?
EP>Я согласен что подобная проблема существует и без замыканий. Возможно в UFP замыкания выделяются отдельным образом потому, что захват контекста происходит достаточно неявно.
1 Она существует без замыканий
2 Замыкания не теряют связь с локальными переменными, никогда, ни при каких случаях, до момента сборки мусора.
Единственное исключение в C# это указатели в unsafe. В С++ добавляется еще куча исключений из за отсутствия GC .
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Я просто привёл один из примеров UFP — для которого в C# и Haskell нет более-менее автоматического решения, а в C++ есть. I>UFP это про локальное состояние, т.е. когда функция теряет связь с локальными переменными. Не ресурсы теряет, а всего лишь переменные из скопа.
[...] I>2 Замыкания не теряют связь с локальными переменными, никогда, ни при каких случаях, до момента сборки мусора.
Допустим у нас такое определение — ОК.
Что делать в случае, когда захватываются ресурсы? (пусть это не относится к UFP по данному выше определению)
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я тут на выходных посмотрел этот тред и чет не пойму твоих стонов про IO/ST в Хаскеле, поставил даже wxHaskell и wxwidgets и всё равно не ясно.
Мой вопрос про ST/IO в Хаскеле не имеет никакого отношения к wxHaskell, просто Klapaucius не отвечает на мой вопрос под предлогом того, что я не ответил на его вопрос про wxHaskell (хотя на самом деле ответил даже два раза). А мой вопрос был вызван тем, что Klapaucius заявил, что система ST/IO Хаскеля предоставляет некие дополнительные возможности, которых просто нет в других языках вообще. Я Хаскель смотрел когда-то, но не очень подробно (он мне не понравился после написания нескольких тестовых приложений и я его стёр), так что вполне допускаю, что мог это пропустить. Поэтому я попросил Klapaucius'а развить эту мысль и желательно на практических примерах. Однако, как видишь, никаких примеров в темке так и не было, так что подозреваю, что ничего такого я тогда так и не пропустил... )))
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Мутабельность данных никак не противоречит идиоматическому ФП-подходу, если она семантически ненаблюдаема. Даже в обсуждаемом по соседству "хэллоуворлде" данные под капотом мутируются со страшной силой. Так и в вашем примере, промежуточные структуры данных не нужны, если не разделяются между несколькими потребителями, а просто передаются от производителя к одному потребителю.
Формально говоря, да. Но фактически, есть ли у нас сейчас ФП языки программирования, способные записать такое? )
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Если это состояние хранится в самой функции, то это уже не ФП. А если передаётся в неё как параметр (и при этом естественно является иммутабельным), то никаких проблем.
Если буквально, то состояние никогда не хранится в функции Замыкание, это состояние, которое как бэ хранится в функции. Как бэ — потому что у функции может быть много замыканий.
I>>Иммутабельность нужна для решения проблемы разделяемых ресурсов. Вместо того, что бы придумывать логику владения, синхронизации и тд, делается копия для которой есть гарантия, что все такие же экземпляры будет эквивалентны.
_>Не придумывай. ))) Это всего лишь одно из полезных побочных свойств ФП, а совсем не причина такого устройства.
Я вроде ясно говорю — "иммутабельность нужна для решения" а не "иммутабельность есть причина". Для чего еще нужна иммутабельность — дело десятое.
>Более того, существование подобных плюсов проявилось относительно недавно, когда появилось многопоточное программирование и т.п., хотя языки с таким устройством существовали уже давным давно. )
Недавно это лет 50-60 назад ?
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Каким образом мерить эффективность?
_>Ну да, я не совсем корректно сказал. Речь конечно же про быстродействие кода.
В распределенной системе быстродействие кода каждого из узлов вполне может оказаться незначительной деталью. Пример — берём 1000 узлов и организуем последовательную обработку информации — каждый следующий узел берет всю пачку данных у предыдудщего, обрабатывает отдаёт следующему. Итого — быстродействие на высоте, а работает в один момент только один узел.
То есть, быстродействие кода каждого из узлов всего лишь необходимое условие для некоего минимального уровня выходного сигнала.
I>>ФП ничему не противоречит. Ты путаешь особенности вычислителя и требования ФП.
_>Ты можешь предложить реализацию ФП с не иммутабельными данными? )
Я могу предложить пример вычислителя, где императивный ЯП будет сливать любому ФЯ — это асинхронный вычислитель.
I>>А теперь представь себе распределенное приложение. Внезапно <любой императивный язык> слился весьма бесславно. Ты, конечно, можешь выкрутиться навроде "даже если одна функция написана на С++" значит и всё приложение написано на С++.
_>Что ты подразумеваешь под "распределённым приложением"? Что-то типа MPI? И почему это любой императивный язык тут сливается? )
Я не знаю что такое MPI
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Выдай правило, которое расскажет когда же делать эту распаковку, а когда — нет.
_>В смысле когда? Всегда естественно) Ну если конечно эта функция не сводится к комбинации нескольких других такого же типа.
А как быть с функцией, которая уже умеет работать с optional<double> и ей не нужны никакие распаковки ? Заворачивать её в другую фунцию, которая сделает упаковку после распаковки ?
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Это как-то можно раскрыть?
Речь шла про метапрограммирование средствами самого языка (а не внешними средствами).
K>Именно об этом. Ничего удивительного в этом как раз нет. В более-менее нормальных языках такое доступно: K>.. K>Обычное метапрограммирование, параметрический полиморфизм тут не причем.
Ну да, я в том сообщение прямо так и написал, что уже отвлёкся на другую тему.
А МП у нас действительно есть во многих языках, но очень разного уровня. И уровень D я мало где видел, разве что в Nemerle ещё сильнее, но там только МП и есть по сути, так что практической пользы от этого пока нет. Ну и макросы Лиспа конечно же, но это уже совсем другая история. )))
Да, так вот, возвращаясь к другим областям... Если у языка есть развитое МП, то даже если в нём и не заложены изначально некоторые возможности, то их практически всегда можно добавить, используя МП.
K>Это точно про D? Он вроде супербыстродействием никогда похвастать не мог.
Сам D конечно помедленнее чем C/C++, хотя быстрее Java/C#. Но здесь речь вообще не об этом шла. Подразумевалось супербыстродействие в сравнение с вариантом "поставлять тексты на том DSL в конечном приложение и просто запускать рантайм интерпретатор их". Т.е. грубо говоря идёт сравнение вариантов типа PHP или как если бы мы транслировали PHP код в C код и потом вкомпилировали бы их в http сервер. Кстати, интересный нюанс: практически к такому же решению и пришли Фейсбук и Вконтакте на своих серверах, только очень сложным и мучительным путём (например пришлось разрабатывать подмножество PHP и т.п.). А тут у нас всё из коробки работает.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Оставим prompt finalization в стороне. Вот есть у нас using на ресурс в C#, или регион в Haskell — можем ли мы сделать замыкание на идентификатор ресурса (в funarg ведь про идентификаторы речь) и передать это замыкание наверх? K>Ну да. Оставляем prompt finalization в стороне и сразу переходим к prompt finalization!
Неудобно как-то получается, да? Вроде UFP (захват free variable замыканием) — а GC ничем помочь не может
EP>>можем ли мы сделать замыкание на идентификатор ресурса (в funarg ведь про идентификаторы речь) и передать это замыкание наверх? K>В C# можем,
Как? Транзитивно заражая все места использования ручным using'ом?
EP>>можем ли мы сделать замыкание на идентификатор ресурса (в funarg ведь про идентификаторы речь) и передать это замыкание наверх? K>в хаскеле есть средства для предотвращения этого а-ля ST.
ST не работает в Haskell 98, то есть требует расширение?
Потом, предотвращение — это не решение задачи. Вот, например, нужно чтобы работало что-то типа:
import System.IO
main = do
closure <- withFile "test.out" WriteMode $ \f -> do
hPutStr f "ok"
return $ \s -> do
hPutStr f "logging: "
hPutStrLn f s
closure "fail"-- test.out: hPutStr: illegal operation (handle is closed)
как?
EP>>На haskell.org написанно: EP>>[...] EP>>В этой табличке для C++: EP>>support functional programming by supporting first-class function EP>>functional style is NOT the dominant one K>А если я в какой-нибудь вики напишу, что луна из сыра — вы поверите?
В случае с C++ я знаю как и насколько он поддерживает functional programming. Относительно UFP — я вам приводил несколько вариантов решения, причём которые работают не только для памяти.
Этого видимо недостаточно, поэтому я привёл цитату из haskel.org wiki — чтобы сослаться хоть на какой-то авторитет (естественно wiki это не то, но всё же).
K>>>>>>Мы вроде бы в соседней ветке выяснили, что без ленивости комбинирование функций теряет смысл из-за непрактичности. EP>>>>В том примере нужна не ленивость, а monadic код. Ленивость помогла только в одном случае из двух, и как видно в общем случае не позволяет сделать обычный код монадичным. K>>>Ничего не понимаю. Ленивость не делает код монадическим. Она нужна, чтоб функции, полученные как результат комбинации других не делали лишние вычисления/проходы. Т.е. в обсуждаемом случае нужна, чтоб монадический код нормально работал. EP>>Для монады Maybe, ленивость позволяет foldr работать так, как работал бы foldrm. K>Не знаю, что вы подразумеваете под foldrm, foldr работает как foldr, а foldM совсем другая функция: K>[...] K>foldr же в обсуждаемом примере просто расставляет лифтнутые (+) между элементами списка. K>[...] K>Ленивость позволяет не вычислять невостребованное. А левая свертка cons списка востребует все, да еще как!
Так, восстанавливаем контекст:
1. Изначально речь шла про автоматическое преобразование обычного кода в монадический.
2. Implicit лифтированние операторов помогает только в некоторых случаях, и не позволяет получить монадические эффекты в общем случае. Например alex_public показал автоматическое лифтирование в D, так вот — там и foldl и foldr не дают необходимого монадического эффекта для Maybe (будут обрабатываться все элементы, даже если есть Nothing).
3. В Haskell, за счёт ленивости — получается достичь необходимых монадических эффектов за счёт лифтирования в большем классе случаев, но далеко не во всех. Например для foldr+Maybe работает, а для foldl — нет.
Т.е. в общем случае код всё равно придётся переделывать на монадический — ленивость помогает только в некоторых специфичных случаях.
В языках же с call-with-current-continuation: любой код можно сделать монадическим без модификаций (либо нужно сделать минимальные модификации, заменив "x" на "get(x)" — если нет перегрузки всего как в D. И то, такая замена можно потребоваться только в листах call-tree, а не по всему коду). Так вот, в языках с call/cc — и foldl и foldr станут монадическими без изменения структуры foldl/foldr.
4. Вы сказали:
K>Мы вроде бы в соседней ветке выяснили, что без ленивости комбинирование функций теряет смысл из-за непрактичности.
Хотя ничего подобного мы не выясняли
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>2 Замыкания не теряют связь с локальными переменными, никогда, ни при каких случаях, до момента сборки мусора.
EP>Допустим у нас такое определение — ОК. EP>Что делать в случае, когда захватываются ресурсы? (пусть это не относится к UFP по данному выше определению)
Контролировать ресурсы явно, руками. Проблема с ФП в том, что циклические ссылки это норма. Это поначалу просто убивает мозг.
Предположим, ты открываешь ресурс и using разрушит ресурс только когда разрушится замыкание.
Совершенно не ясно как ты собираешься это использовать из за наличия циклических ссылок.
Варианты
1 "вон это замыкание из вон той функции использовать только один раз и сразу разрушать"
2 "вот это замыканиние из вон той функции не трогаем, как отсохнет, само отвалится, хрен его знает как это происходит, но на прошлой неделе это происходило в среднем за 500мс"
Других нет, точнее, они сводятся к двум этим
1 — если используешь один раз, это равносильно вызову в правильном месте
2 — если используешь много раз, получаешь хрень с занятым ресурсом и недетерминированым временем использования. То есть разрушение как бы детерминировано — но вот сколько ресурс будет использовася, хрен его знает, например сильно вряд ли ты просчитаешь сложную рекурсию и тд и тд. Но как только перестанет использоваться — сразу разрушится. Очевидно, этот вариант есть просто некорректный код.
Итого — если делать "как в С++" то надо бороться с циклическими ссылками и желательно что бы эти циклические ссылки искал компилятор, а вот компилятор этого как раз и не умеет. То есть, в итоге пришли к ручному управлению, когда, казалось бы, нужна была автоматизация. Все чего добились — ручная неявная работа с ресурсами.
В С++ придется следить за циклическими ссылками, приседать, обрезать и тд и тд и тд и всё это руками, но ресурсы будут освобождаться неявно. То есть, руками задаёшь стратегию использования, а вызов произойдет неявно.
Что предлагает ФП — работа с ресурсом делается в изолированом контексте. Нужно думать не о ресурсах, а о результатах операций, а ресурсы использовать унутре каждой из операций. И разумеется явно, руками.
В ФП не надо следить за циклическими сслыками, не надо приседать, обрезать и тд и тд. Делаешь всё как с другими функциями — комбинируешь, вызываешь, параметризуешь и тд. Ресурсами управляешь руками — задаёшь руками стратегию использования по месту вызова, в этом случае вызов разрушения будет сделан неявно.
Итого — оба варианта на деле означают одно и то же — ручной контроль ресурсов. Отдельно можно поговорить про аггрегирование.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Это цифры с потолка. Эрланг показывает и доказывает что твои рассуждения ошибочны. EP>>Какие именно рассуждения, и как он доказывает? I>На нём пишутся распределенные системы, внезапно !
И как это доказывает то, что он работает не медленнее чем аналогичный код на императивном языке?
I>Эрланг собтсвенно и начал с того, что порвал С++ в распределенных приложениях для телекоммуникаций.
Erlang рулит в первую очередь из-за инфраструктуры, а не из-за самого языка. Точно также как рулит и node.js за счёт инфраструктуры.
EP>>Кстати, про Erlang — выше приводили пример "идиоматичного ФП кода": EP>>
EP>>f = 0 : 1 : zipWith (+) f (tail f)
EP>>
попробуй изобрази его на Erlang. EP>>Да, и по-твоему Erlang это чистый ФП? I>Это скучно.
Конечно, мы же обсуждаем чистые ФП и эффективность их мэппинга в железо. Если тебе скучно — то я
Кстати, ранее в обсуждении утверждалось что ленивость — это пища ФП (весьма тормозная). И пример с zipWith выше как раз и использует ленивость. Но в Erlang'е никакой ленивости нет — к чему бы это?
EP>>Устроен танковый батальон естественно не как танк, но без танков нет батальона. Ты что сказать-то хотел своей метафорой? I>Я говорю про отношение часть-целое и характеристики составляющих. У узла узкое место процессор и система ввода-вывода, а у распределенной системы узким местом будет не процессоры и ввод-вывод,
У распределённых число-дробилок в большинстве случаев узким местом будет как раз процессор.
I>а отзывчивость по причине корректности-качества работы диспетчера, которые, в свою очередь, могут никак не зависеть ни от процессора ни от ввода-вывода.
А диспетчер где исполняется? На каком-то чудесном ФП-железе?
I>>>Ты не заметил лямбды в С++ ? Чудеса ! EP>>Это не чистое ФП, а как раз полезные его элементы. И "влазло" оно очень давно. I>Ажно с первых версий stl.
STL это только конкретный известный пример.
EP>>См. например STL — там же кругом value semantics (привет referential transparency) и higher order functions. I>Вот-вот.
Что "вот-вот"? Я же говорю — использование элементов ФП это хорошо.
I>Сколько лет stl ?
Около 20.
Re[25]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>ОК, разделять данные между версиями в теории не обязательно. Но никакой специфики языка тут нет. В библиотеках для ФЯ эти структуры реализуются так, что данные разделяются.
Вот вот. Собственно говоря, из-за иммутабельности данных в ФП языках вообще нет понятия ссылки, как её понимают в C++ (поменяем данные в одном месте кода и это уловил код в другом месте), а есть только копирование (то, что внутри оно может оптимизироваться через ссылки, значения не имеет). Поэтому:
1. Непонятно с чего вы требуете от C++ наличия [&] вверх по стеку, в то время как чистые ФП языки не имеют этого даже вниз по стеку? Собственно сама конструкция & — это признак скорее императивного языка. Да, и кстати [&] вверх по стеку в C++ тоже есть — shared_ptr. Только это получается нужно в основном для той редкой ситуации, которая в ФП языках вообще запрещена.
2. Непонятно почему вы пренебрегаете новой возможностью C++, обеспечивающей возможность осуществлять "копирование из покидаемой области" с нулевыми накладными расходами — она же как раз полностью решает проблему эффективности [=], делая его таким же эффективным как в ФП языка?
Вообще, когда вы говорите про & и чистые функциональные языки, то на самом деле подразумевается всего лишь const&, которая отличается от = только быстродействием. Соответственно в ФП у нас имеется = или же const& (оптимизированная версия), вниз и вверх по стеку. А например в C++ мы имеем:
1. = вверх и вниз по стеку естественно.
2. const& вниз по стеку, т.е. оптимизированное = вниз по стеку
3. && (то самое перемещение), т.е. оптимизированное = вверх по стеку
4. & вниз по стеку, причём оно оптимизировано от рождения
5. shared_ptr, как реализация & вверх по стеку
Т.е. C++ предоставляет все возможности ФП языков в этой области, и плюс ещё несколько (пункты 4 и 5) вариантов.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Если буквально, то состояние никогда не хранится в функции Замыкание, это состояние, которое как бэ хранится в функции. Как бэ — потому что у функции может быть много замыканий.
Если мы говорим про ФП, то там захватываемые величины становятся просто константами. Так что они явно не могут быть состоянием.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В распределенной системе быстродействие кода каждого из узлов вполне может оказаться незначительной деталью. Пример — берём 1000 узлов и организуем последовательную обработку информации — каждый следующий узел берет всю пачку данных у предыдудщего, обрабатывает отдаёт следующему. Итого — быстродействие на высоте, а работает в один момент только один узел. I>То есть, быстродействие кода каждого из узлов всего лишь необходимое условие для некоего минимального уровня выходного сигнала.
И какое это имеет отношение к неэффективности (по быстродействию) языков с чистым ФП?
I>Я могу предложить пример вычислителя, где императивный ЯП будет сливать любому ФЯ — это асинхронный вычислитель.
Ну предложи) С удовольствием посмотрим. )
_>>Что ты подразумеваешь под "распределённым приложением"? Что-то типа MPI? И почему это любой императивный язык тут сливается? ) I>Я не знаю что такое MPI
Эмммм... Вообще то это самый распространённый инструмент для написания распределённых приложений. Вот http://ru.wikipedia.org/wiki/Message_Passing_Interface ссылочка. Кстати, надо пояснять на каком языке там основные реализации?)))
Хех, мне теперь даже страшно предположить, что ты имел в виду под "распределёнными приложениями", если при этом не в курсе про MPI... )
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А как быть с функцией, которая уже умеет работать с optional<double> и ей не нужны никакие распаковки ? Заворачивать её в другую фунцию, которая сделает упаковку после распаковки ?
Вот как раз такие функции и остаются) Плюс "голые" (без optional вообще). Про это и речь. ) Ты похоже уже запутался в нашей с Синклером дискуссии. Он то хотел вообще третий вид функций привлечь (как раз которые для монад только)... )))
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И какое это имеет отношение к неэффективности (по быстродействию) языков с чистым ФП?
Непосредственное — эффективность языка зависит от вычислителя. В императивных языках нет ничего для асинхронщины. Вообще ничего.
I>>Я могу предложить пример вычислителя, где императивный ЯП будет сливать любому ФЯ — это асинхронный вычислитель.
_>Ну предложи) С удовольствием посмотрим. )
Уже.
_>Эмммм... Вообще то это самый распространённый инструмент для написания распределённых приложений. Вот http://ru.wikipedia.org/wiki/Message_Passing_Interface ссылочка. Кстати, надо пояснять на каком языке там основные реализации?)))
Ты снова про производительность отдельного нода и его АПИ
_>Хех, мне теперь даже страшно предположить, что ты имел в виду под "распределёнными приложениями", если при этом не в курсе про MPI... )
Я не в курсе твоих аббревиатур. Эрланг в свое время порвал С++, странно что ты этого не знаешь.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Если буквально, то состояние никогда не хранится в функции Замыкание, это состояние, которое как бэ хранится в функции. Как бэ — потому что у функции может быть много замыканий.
_>Если мы говорим про ФП, то там захватываемые величины становятся просто константами. Так что они явно не могут быть состоянием.
Это чушь. Поведение не реализуется без состояния. А ФП, мягко говоря, ничем не мешает описывать поведение, более того, активно помогает.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>>>Что ты подразумеваешь под "распределённым приложением"? Что-то типа MPI? И почему это любой императивный язык тут сливается? ) I>>Я не знаю что такое MPI
_>Эмммм... Вообще то это самый распространённый инструмент для написания распределённых приложений. Вот http://ru.wikipedia.org/wiki/Message_Passing_Interface ссылочка. Кстати, надо пояснять на каком языке там основные реализации?)))
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>>>Это цифры с потолка. Эрланг показывает и доказывает что твои рассуждения ошибочны. EP>>>Какие именно рассуждения, и как он доказывает? I>>На нём пишутся распределенные системы, внезапно !
EP>И как это доказывает то, что он работает не медленнее чем аналогичный код на императивном языке?
Код никого не интересует. Интересуют выходные характеристики конечной системы.
I>>Эрланг собтсвенно и начал с того, что порвал С++ в распределенных приложениях для телекоммуникаций.
EP>Erlang рулит в первую очередь из-за инфраструктуры, а не из-за самого языка. Точно также как рулит и node.js за счёт инфраструктуры.
Это инфраструктуру без подобного языка заюзать невозможно, в принципе.
I>>Это скучно.
EP>Конечно, мы же обсуждаем чистые ФП и эффективность их мэппинга в железо. Если тебе скучно — то я
Это тебе интересно обсуждать ислючительно мапинг в железо.
EP>Кстати, ранее в обсуждении утверждалось что ленивость — это пища ФП (весьма тормозная). И пример с zipWith выше как раз и использует ленивость. Но в Erlang'е никакой ленивости нет — к чему бы это?
Наверное к тому, что Эрлан это энергичный язык ?
I>>Я говорю про отношение часть-целое и характеристики составляющих. У узла узкое место процессор и система ввода-вывода, а у распределенной системы узким местом будет не процессоры и ввод-вывод,
EP>У распределённых число-дробилок в большинстве случаев узким местом будет как раз процессор.
То есть, ты хочешь сказать, что некоторые распределенные системы есть множество всех распределенных систем ?
I>>а отзывчивость по причине корректности-качества работы диспетчера, которые, в свою очередь, могут никак не зависеть ни от процессора ни от ввода-вывода.
EP>А диспетчер где исполняется? На каком-то чудесном ФП-железе?
Диспетчер выполняется, грубо говоря, сразу на всех узлах.
EP>Что "вот-вот"? Я же говорю — использование элементов ФП это хорошо.
Ты почему то начал спрашивать, когда это ФП попало в нативный код
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>1. Непонятно с чего вы требуете от C++ наличия [&] вверх по стеку, в то время как чистые ФП языки не имеют этого даже вниз по стеку?
Имеют.
>Собственно сама конструкция & — это признак скорее императивного языка. Да, и кстати [&] вверх по стеку в C++ тоже есть — shared_ptr. Только это получается нужно в основном для той редкой ситуации, которая в ФП языках вообще запрещена.
Наоборот, вверх по стеку используется постоянно.
_>2. Непонятно почему вы пренебрегаете новой возможностью C++, обеспечивающей возможность осуществлять "копирование из покидаемой области" с нулевыми накладными расходами — она же как раз полностью решает проблему эффективности [=], делая его таким же эффективным как в ФП языка?
Она ничего не решает, если точнее. Я рядом уже пояснил.
_>1. = вверх и вниз по стеку естественно. _>2. const& вниз по стеку, т.е. оптимизированное = вниз по стеку _>3. && (то самое перемещение), т.е. оптимизированное = вверх по стеку _>4. & вниз по стеку, причём оно оптимизировано от рождения _>5. shared_ptr, как реализация & вверх по стеку
_>Т.е. C++ предоставляет все возможности ФП языков в этой области, и плюс ещё несколько (пункты 4 и 5) вариантов.
Нет никакого "дополнительно", все что ты показал это вверх и вниз.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Непосредственное — эффективность языка зависит от вычислителя. В императивных языках нет ничего для асинхронщины. Вообще ничего.
А что есть для неё в функциональных языках? )
_>>Ну предложи) С удовольствием посмотрим. ) I>Уже.
Это типа "асинхронный вычислитель"? ) Мне эта фраза ни о чём не говорит вообще. Давай конкретный пример кода или хотя бы статью в вики на описание архитектуры.
I>Ты снова про производительность отдельного нода и его АПИ
Ээээ что что? ) С помощью указанного выше инструмента программируют большинство современных суперкомпьютеров, вычислительных кластеров и т.п. )
I>Я не в курсе твоих аббревиатур. Эрланг в свое время порвал С++, странно что ты этого не знаешь.
Эрланг ничего так язык. Мне всегда нравился Пролог (жаль что в Эрланге от него только синтаксис и остался, без реального наполнения). И модель акторов тоже хороша (правда сейчас её уже начали спокойно использовать и в C++, а D она вообще входит в стандартную библиотеку). Но насчёт "порвал" — это ты мягко говоря преувеличил. ))) Даже в целевой нише Эрланга только небольшая часть софта пишется на нём. Так что он вообще никого не порвал, а пока что просто сумел выжить и даже имеет парочку примеров написания известного софта (только в других языках таких примеров сотни в той же области). В общем его позиция выглядит намного лучше чем у D или Haskell, но о мейнстриме (даже в своей нише!) ему ещё мечтать и мечтать... )))
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Непосредственное — эффективность языка зависит от вычислителя. В императивных языках нет ничего для асинхронщины. Вообще ничего.
_>А что есть для неё в функциональных языках? )
Композиция функций.
_>Это типа "асинхронный вычислитель"? ) Мне эта фраза ни о чём не говорит вообще. Давай конкретный пример кода или хотя бы статью в вики на описание архитектуры.
Я уже раз 100 упомянул, но ты никуда не заглянул. Что изменит 101 раз ?
I>>Ты снова про производительность отдельного нода и его АПИ
_>Ээээ что что? ) С помощью указанного выше инструмента программируют большинство современных суперкомпьютеров, вычислительных кластеров и т.п. )
Ля-ля-ля.
курсе твоих аббревиатур. Эрланг в свое время порвал С++, странно что ты этого не знаешь.
_>Эрланг ничего так язык. Мне всегда нравился Пролог (жаль что в Эрланге от него только синтаксис и остался, без реального наполнения). И модель акторов тоже хороша (правда сейчас её уже начали спокойно использовать и в C++, а D она вообще входит в стандартную библиотеку). Но насчёт "порвал" — это ты мягко говоря преувеличил. )))
Читай историю Эрланга.
>Даже в целевой нише Эрланга только небольшая часть софта пишется на нём.
Эрланг давно вышел из этой ниши.
>Так что он вообще никого не порвал, а пока что просто сумел выжить и даже имеет парочку примеров написания известного софта (только в других языках таких примеров сотни в той же области). В общем его позиция выглядит намного лучше чем у D или Haskell, но о мейнстриме (даже в своей нише!) ему ещё мечтать и мечтать... )))
У него популярность растет и растет и в основном в распределенных приложениях.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>А как быть с функцией, которая уже умеет работать с optional<double> и ей не нужны никакие распаковки ? Заворачивать её в другую фунцию, которая сделает упаковку после распаковки ?
_>Вот как раз такие функции и остаются) Плюс "голые" (без optional вообще). Про это и речь. ) Ты похоже уже запутался в нашей с Синклером дискуссии. Он то хотел вообще третий вид функций привлечь (как раз которые для монад только)... )))
Нет, я говорю про то же что и Синклер.
Твоя функция, раз "такие функции и остаются", никакая не универсальная. А нужна универсальная и это возможно только с монадами.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>>>Про "неработающие" замыкания в C++ из-за UFP любители GC мне тут уже третий раз говорят, хотя "плюсисты" не имеют с этим проблем. На деле же оказывается что работают, и не только для памяти. K>>>Ну правильно: используют не ФЯ, идиомы не ФП — с чего бы им испытывать с этим проблемы, если все тропы протоптаны там, где их нет. EP>>Нет — речь была не про ФП. K>Да. Разговор был именно о ФП, точнее о том, что усилия необходимые для использования зачаточного фп-стиля в C++ превышают бенефиты от использования зачаточного ФП-стиля.
В выделенном разговор был не про ФП.
EP>>Особенно оно не нужно там, где плохо мэппится в реальное железо. K>ФП, да и вообще высокоуровневый код обычно плохо мэппится на реальное железо. Высокоуровневый код хорошо мэппится на человеческие мозги. Тут именно трейдофф между первым и вторым.
What do I mean when I say that an algorithm does not "impose any performance penalty"? In other words, how do you know that a generic algorithm is efficient? An algorithm is called rel atively efficient if it's as efficient as a nongeneric version written in the same language, and it's called absolutely efficient if it's as efficient as a nongeneric assembly language version.
For many years, I tried to achieve relative efficiency in more advanced languages (e.g., Ada and Scheme) but failed. My generic versions of even simple algorithms were not able to compete with built-in primitives. But in C++ I was finally able to not only accomplish relative efficiency but come very close to the more ambitious goal of absolute efficiency. To verify this, I spent countless hours looking at the assembly code generated by different compilers on different architectures.
I found that efficiency and generality were not mutually exclusive. In fact, quite the reverse is true. If a component is not efficient enough, it usually means that it's not abstract enough. This is because efficiency and abstractness both require a clean, orthogonal design. A similar phenomenon occurs in mathematics: Making a proof more abstract makes it more concise and elegant.
То что где-то дорогие абстракции — не означает что они дорогие везде. Естественно, если использовать связанные списки которые плохо мэппятся в железо, thunk'и которые на ровном месте добавляют меж-потоковую синхронизацию и излишние циклы требующие GC — то всё будет тормозить.
В железе есть: изменяемая память(доступ к которой происходит большими порциями ~64B), многоуровневые кэши, синхронизация между кэшами, изменяемые регистры, стэк (с готовыми инструкциями для работы с ним), указатель на текущую инструкцию и разнообразные переходы. Само собой, если даже самые низкоуровневые абстракции в языке делают вид что ничего этого нет и вносят большое penalty сами по себе — то всё будет тормозить.
EP>>2. UFP — это передача замыкания выше области free variables, так? Free variable может чем угодно, а не только памятью K>Free variable не может быть чем угодно. Это языковая сущность. "Память" — это уже другой, нижележащий уровень абстракции. UFP гарантирует продление жизни языковой сущности. Т.е. объекта File, а не файла, хендлером для которого этот файл является.
Так я об этом и говорю — в языках с GC абстракции скрывающие памяти есть, а для других ресурсов как-то не завезли. Поэтому и оперируют такими низкоуровневыми вещами как "открыть файл получить хэндл", "закрыть хэндл", "открыть хэндл и закрыть в конце этого блока".
Ну да — сам хэндл захватится замыканием, и будет жить как минимум столько же, сколько и само замыкание. Но толку-то от закрытого хэндла?
Например в C# — если какой-то из объектов, где-то в глубине композиции начнёт использовать ресурс как поле, то начнётся ад — вся цепочка объектов становится ресурсами, это означает что требуется добавить новый код во всех местах пользования. Особенно весело будет если мы работаем над библиотекой, которая используется клиентами.
В C++ же абстракция есть для всех ресурсов, и при добавление поля-ресурса зависимый код менять не нужно:
class Foo // used at many places
{
Resource x;
// ...
};
EP>>Работающего [&] не будет даже при включённом GC. Даже при использовании GC нужен будет [=] K>В высокоуровневом языке различие между передачей по ссылке и копированием вообще чаще всего семантически ненаблюдаемо.
import Control.Monad.ST
import Data.STRef
import Control.Monad
foo x = modifySTRef x (+1)
main = print $ runST $ do
x <- newSTRef 0
foo x -- by reference!
foo x -- by reference!
readSTRef x
-- prints 2
А тут что?
Кстати, а зачем используют эту венгерскую ноткацию? Почему не просто "modify" вместо "modifySTRef"?
EP>>Вообще-то вопрос был про то, как в Haskell передать замыкание с ресурсом-free-variable наверх. Region'ы судя по всему это проблему никак не решают, поэтому вопрос остаётся открытым. K>Регионы предотвращают утечку ресурса.
Вопрос в том как передать это замыкание наверх, а не запретить передачу.
EP>>Ну да, нет нормального решения — "бессмысленно" K>Но его нет. То, что вы считаете нормальным решением в условиях высокоуровневого языка нормальным не является.
Естественно — лучше запретить.
K>Связывание управления памятью с управлением дефицитными ресурсами там ни к чему хорошему не приводит.
О каком управлением памятью идёт речь?
В C++ есть объекты, у этих объектов есть lifetime. Объекты могут абстрагировать работу с любым ресурсом — память, файлы, соединения и т.п.
EP>>Это в этом варианте?
K>Более-менее осмысленное решение, это делать функцию вида ЭтоНамНадоЧтобПолучитьРесурс -> (ОткрытыйРесурс -> Результат) -> Результат, которая сначала собирает через второй аргумент функции, которые что-то будут с ресурсом делать, а потом выполняется сама, открывая ресурс, скармливая всем этим функциям и закрывая его. Т.е. те самые брекеты и их развитие вроде pipes-safe и resourcet.
EP>>? K>А в чем вы видите противоречие?
В этом варианте все функции для работы над одним ресурсом должны собраться в одном месте, так?
Что делать в случае когда у нас несколько ресурсов, время жизни которых пересекаются и зависят друг от друга? (решение с использованием одного большого scope — естественно неинтересно)
K>Вы с тем, на что я ссылался ознакомились?
С чем именно? С тем вариантом где хэндлы явно передаются через return? Так вопрос же про возвращение замыкания.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это чушь. Поведение не реализуется без состояния. А ФП, мягко говоря, ничем не мешает описывать поведение, более того, активно помогает.
В чистом ФП это описывают так:
new_state=process_event(state, event);
тогда функция process_event остаётся чистой и все довольны. )
Естественно где-то там в коде должно быть столкновение с "грубой реальностью внешнего мира", но для этого в ФП используются спец. средства, типа монад ST/IO в Хаскеле.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нет, я говорю про то же что и Синклер.
I>Твоя функция, раз "такие функции и остаются", никакая не универсальная. А нужна универсальная и это возможно только с монадами.
Ты похоже вообще уже забыл о том, какая задача решалась в той дискуссии. Мы решали проблему "добавление optional в некий существующий код, без его модификации". Монады тут вообще ни при чём, т.к. не дают в принципе подобных решений. Это вопрос скорее из области гибкости языка. Я показал, что на D это в принципе возможно (хотя Евгений указал на недостатки такого решения в области производительности). Причём моё добавление монадой не являлось. Синклер же указал, что подобное решение будет странно работать с функциями "монадного вида". Ну с этим никто и не спорит, только за отсутствием монад у нас и функций таких не должно быть (в старом коде их в принципе быть не может, а новый мы пишем с максимальным обобщением).
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>То есть на равном месте вводится межпоточная синхронизация, об этом и речь. K>>А вы точно читали то, на что я ссылаюсь? EP>Точно. Там используется lock-free алгоритм для межпоточной синхронизации
Выделено. Вы не поняли, для чего это нужно или есть идеи получше?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Это чушь. Поведение не реализуется без состояния. А ФП, мягко говоря, ничем не мешает описывать поведение, более того, активно помогает.
_>В чистом ФП это описывают так: _>
_>new_state=process_event(state, event);
_>
тогда функция process_event остаётся чистой и все довольны. )
Важно, что состояние никуда не девается. Просто новое состояние берётся посредством вычисления из старого, а не так, как в императивном программировании, путем модификации старого.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Вот, нашел специально для тебя, про эрланг и mpi I>>http://www.slideshare.net/norbu09/mpi-erlang-and-the-web
_>Я как бы в курсе, что в Эрланге реализован некий свой аналог MPI. ))) И что с того? )
Ну стало быть, согласно твоим словам, ты считаешь что Эрлан это другое название для С++, других объяснений нет
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Ню-ню.
I>>У него популярность растет и растет и в основном в распределенных приложениях.
_>Ну так когда растёшь от нуля, то можно и 500% роста в год показывать, но при этом занимать на рынке 1%. )))
Ога. Ты по прежнему доказываешь, что танковый батальон устроен точно так же как и танк
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Формально говоря, да.
Мы вроде бы говорили о принципах ФП? Ну, вот контролируемая мутабельность этим принципам не противоречит, она нормально встраивается в чистый код. Мутабельность может быть деталью реализации библиотеки, а код ее использующий — полностью идиоматическим.
_>Но фактически, есть ли у нас сейчас ФП языки программирования, способные записать такое? )
Такое — это какое? Имеется в виду контролируемая мутабельность? Она, разумеется, во всех чистых языках есть. Развитая система для контроля уникальности ссылок есть в Clean. Оптимизации, устраняющие промежуточные результаты, там где это возможно есть в GHC, для списков в стандартной библиотеке и пакете stream-fusion, для массивов в пакетах vector и repa. Вполне работающие.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Нет, я говорю про то же что и Синклер.
I>>Твоя функция, раз "такие функции и остаются", никакая не универсальная. А нужна универсальная и это возможно только с монадами.
_>Ты похоже вообще уже забыл о том, какая задача решалась в той дискуссии. Мы решали проблему "добавление optional в некий существующий код, без его модификации".
Правильно и это значит, что нужна универсальная функция.
>Синклер же указал, что подобное решение будет странно работать с функциями "монадного вида". Ну с этим никто и не спорит, только за отсутствием монад у нас и функций таких не должно быть (в старом коде их в принципе быть не может, а новый мы пишем с максимальным обобщением).
Ты предлагаешь законодательно запретить использовать промисы ? Или optional это просто название, а на сама деле это double ? Не пойму чтото. Если новый код пишется с максимальным обобщением, то ожидается универсальная функция
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Речь шла про метапрограммирование средствами самого языка (а не внешними средствами).
Погодите. Начали мы с того, что обобщенный код в плюсах нетипизирован. Вы заявили, что обобщенный код везде такой. Когда выяснилось, что это не так, вы заявили, что в плюсах он такой потому, что работает во время компиляции. Когда выяснилось, что тот же параметрический полиморфизм именно во время компиляции и работает, вы заявили, что работа во время компиляции может быть разная. Это, конечно, верно. И именно это и следовало бы обсудить подробнее. Но вы вдруг написали про то, что бывает метапрограммирование внешними средствами, а бывает — средствами языка. При чем тут это? Я запутался.
_>Если у языка есть развитое МП, то даже если в нём и не заложены изначально некоторые возможности, то их практически всегда можно добавить, используя МП.
"Практически всегда" — это очень сильное преувеличение. В некоторых случаях можно, да.
_>Сам D конечно помедленнее чем C/C++, хотя быстрее Java/C#.
Это если не упереться в дишный тормозной GC.
_>Подразумевалось супербыстродействие в сравнение с вариантом "поставлять тексты на том DSL в конечном приложение и просто запускать рантайм интерпретатор их".
Ну это-то понятно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>>>То есть на равном месте вводится межпоточная синхронизация, об этом и речь. K>>>А вы точно читали то, на что я ссылаюсь? EP>>Точно. Там используется lock-free алгоритм для межпоточной синхронизации K>Выделено. Вы не поняли, для чего это нужно или есть идеи получше?
В смысле? Возможно одновременное изменение/чтение одних и тех же данных из нескольких потоков — поэтому и вводится синхронизация.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Неудобно как-то получается, да? Вроде UFP (захват free variable замыканием) — а GC ничем помочь не может
Еще как может. Время жизни продлевает, UFP решает. Вот только prompt finalization такое продлевание не способствует.
EP>>>можем ли мы сделать замыкание на идентификатор ресурса (в funarg ведь про идентификаторы речь) и передать это замыкание наверх? K>>В C# можем, EP>Как? Транзитивно заражая все места использования ручным using'ом?
Нет, наоборот, using никогда не используем. Тогда время "открытости" ресурса будет примерно совпадать со временем жизни захваченного в замыкание объекта. Примерно потому, что: 1) Финализируемый ресурс живет несколько дольше объекта. 2) Ресурс всегда можно закрыть вручную. Строго говоря, контроль рантайма за ресурсами вроде файлов меньше, чем за памятью. Т.е. с большей вероятностью произойдет что-то за пределами рантайма, что сделает файл непригодным для записи.
Т.е. в смысле продления жизни и решения UFP все обстоит лучше либо так же, как и в плюсах. С prompt finalization же все обстоит наоборот хуже. Ну так в этом трейдофф. Для памяти имеет смысл выбрать решение UFP, для файлов закрытие сразу по прекращению использования важнее.
EP>ST не работает в Haskell 98, то есть требует расширение?
Haskell 98 — это подмножество языка, выделенное для того, чтоб гарантировать компилируемость кода в учебниках для начинающих.
EP>как?
Я вам давал ссылку на монадические регионы.
EP>В случае с C++ я знаю как и насколько он поддерживает functional programming. Относительно UFP — я вам приводил несколько вариантов решения, причём которые работают не только для памяти.
Гарантии на продлевание жизни захваченных языковых сущностей ни одно из этих "решений" не дает, а значит и UFP не решает.
EP>Этого видимо недостаточно, поэтому я привёл цитату из haskel.org wiki — чтобы сослаться хоть на какой-то авторитет.
Почему haskell выделено жирным? Намекаете, что это авторитетный ресурс по C++? Я же говорю, перепишите на плюсах функциональный "хеллоуворлд", потом расскажете, как вам помогла авторитетность анонимного вики-контрибьютора.
EP>Так, восстанавливаем контекст: EP>1. Изначально речь шла про автоматическое преобразование обычного кода в монадический.
Ну да. Но это, строго говоря, непонятно как делать, потому что монадичность добавляет возможности, которых раньше не было. В том же вашем примере уже есть обработка пустого значения (одна из веток if возвращает () — не понятно, что это может значить в чистом коде), так что имеет место только замена одной монады на другую. Вот автоматический лифтинг в апплиативный функтр — это более реально.
EP>2. Implicit лифтированние операторов помогает только в некоторых случаях
Ну да, так я показывал именно то, что спрашивал Синклер — обобщенный аналог лифтинга операторов в Nullable.
EP>Например alex_public показал автоматическое лифтирование в D, так вот — там и foldl и foldr не дают необходимого монадического эффекта для Maybe (будут обрабатываться все элементы, даже если есть Nothing). EP>3. В Haskell, за счёт ленивости — получается достичь необходимых монадических эффектов за счёт лифтирования в большем классе случаев, но далеко не во всех. Например для foldr+Maybe работает, а для foldl — нет.
Тут не в монадах дело. foldr для cons и foldl для snoc (но не наоборот) просто можно вычислять с ранним прерыванием. Без всяких монад:
Именно за счет ленивости. foldr в этих примерах не делается монадическим. Вы на сигнатуры посмотрите.
Соотвественно и для операций с Maybe раннее завершение обеспечивает не "монадичность", а ленивость. И без ленивости и след. раннего завершения просто от Maybe мало толку.
EP>Т.е. в общем случае код всё равно придётся переделывать на монадический — ленивость помогает только в некоторых специфичных случаях.
Чем вам эта "монадичность" тут без ленивости поможет? Раннее завершение с помощью именно монады — это монада Cont[inuation].
А ленивость помогает во всех случаях, где это возможно. То, что востребовано для каких-то вычислений невычислить все равно нельзя.
EP>В языках же с call-with-current-continuation: любой код можно сделать монадическим без модификаций (либо нужно сделать минимальные модификации, заменив "x" на "get(x)" — если нет перегрузки всего как в D.
Чего его делать — он и так уже монадический. Одну монаду на другую заменить можно (ряд монад с помощью Cont[inuation] можно заменить, правда не все).
EP>
K>>Мы вроде бы в соседней ветке выяснили, что без ленивости комбинирование функций теряет смысл из-за непрактичности.
EP>Хотя ничего подобного мы не выясняли
Т.е. вычислять ненужное — это практично? Или непрактичность не делает комбинирование бессмысленным? Или имеется в виду, что call-with-current-continuation тоже дает возможность получать комбинаторый код, который не делает бессмысленных действий? Ну да, только реализация языка с континьюэйшенами, которая с более-менее приличной скоростью работает — это сложнее, чем реализация ленивого языка.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[26]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Вот вот. Собственно говоря, из-за иммутабельности данных в ФП языках вообще нет понятия ссылки, как её понимают в C++ (поменяем данные в одном месте кода и это уловил код в другом месте)
Я надеюсь, вы это все не всерьез пишете.
>
let foo n = do
r <- newIORef n
return (readIORef r, writeIORef r)
> (r, w) <- foo 2
> r
2
> w 42
> r
42
Это семантически наблюдаемое изменение.
Ленивость же использует мутабельность "под капотом", что важно для производительности, но наблюдается только в отладчике:
> let l = [1..]
> :sprint l
l = _
> let l2 = l
> :sprint l2
l2 = _
> l !! 3
4
> :sprint l
l = 1 : 2 : 3 : 4 : _
> :sprint l2
l2 = 1 : 2 : 3 : 4 : _
_>а есть только копирование (то, что внутри оно может оптимизироваться через ссылки, значения не имеет).
Да почему не имеет-то? Да, если не использовать мутабельные ссылки, то семантически наблюдаемой разницы между передачей по ссылке и копированием нет. Но эффективность реализации имеет критическое значение. Какой смысл в фиче, если ее нельзя использовать из-за неприемлимой тормознутости?
_>1. Непонятно с чего вы требуете от C++ наличия [&] вверх по стеку, в то время как чистые ФП языки не имеют этого даже вниз по стеку?
см. выше.
_>Собственно сама конструкция & — это признак скорее императивного языка.
Это не так, потому что в декларативных языках есть, в основном, все то же самое, что и в императивных — только в более управляемом виде. Но, даже если и так — так что с того? Императивному языку не нужно это поддерживать в лямбдах? Как раз наоборот, нужно. И императивные языки с решенной UFP вроде C# поддерживают.
> Да, и кстати [&] вверх по стеку в C++ тоже есть — shared_ptr.
Тормоза и проблемы с циклическими ссылками.
_>2. Непонятно почему вы пренебрегаете новой возможностью C++, обеспечивающей возможность осуществлять "копирование из покидаемой области" с нулевыми накладными расходами — она же как раз полностью решает проблему эффективности [=], делая его таким же эффективным как в ФП языка?
Чего непонятного-то? Я же объяснил. Этот самый "эффективный [=]" позволяет иметь сколько угодно "копий", а то, о чем вы говорите подразумевает только передачу, а не разделение.
_>А например в C++ мы имеем:
_>1. = вверх и вниз по стеку естественно. _>2. const& вниз по стеку, т.е. оптимизированное = вниз по стеку _>3. && (то самое перемещение), т.е. оптимизированное = вверх по стеку _>4. & вниз по стеку, причём оно оптимизировано от рождения _>5. shared_ptr, как реализация & вверх по стеку
Целый парад инвалидов. А нормальной ссылки как не было — так и нет. Выбор хорош тогда, когда его можно не делать — есть хорошее решение по умолчанию, а какое-то другое решение нужно принимать в краевых ситуациях. На C++ же нормального решения по умолчанию нет, есть только краевые, и вдоль вот этих вот стенок "пространства решений" программисту и предлагается двигатся. В результате ФП для него будет не средством облегчения написания и поддержки кода, а цирком с конями в лучшем случае, и изощренной пыткой в остальных.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>>>Про "неработающие" замыкания в C++ из-за UFP любители GC мне тут уже третий раз говорят, хотя "плюсисты" не имеют с этим проблем. На деле же оказывается что работают, и не только для памяти. EP>В выделенном разговор был не про ФП.
Ну а как можно не испытывать проблем с неработающими замыканиями, если только не пользоваться ими нормально, а рассказывать на форумах про то, что они якобы работающие?
EP>На C++ как раз высокоуровневый код отлично мэппится в железо. The Standard Template Library
Высокоуровневый код — это когда можно делать вид, что языковые сущности — это математические объекты, содержательно рассуждать о них в таком ключе и получать нормально работающий код. Код с использованием STL, конечно, повыше уровнем, чем код на языках 60-х годов, но сейчас уже 2010-е.
EP>То что где-то дорогие абстракции — не означает что они дорогие везде. Естественно, если использовать связанные списки которые плохо мэппятся в железо, thunk'и которые на ровном месте добавляют меж-потоковую синхронизацию и излишние циклы требующие GC — то всё будет тормозить.
Точно, а если копировать массивы, считать ссылки и вычислять то, что вычислять ненужно все будет летать. Сравнимый по высокоуровневости код с такими подходами не то, что тормозить будет — он вообще никуда не поедет. Поэтому никакого высокоуровневого кода и нет — есть только продвинутый интерфейс для двигания указателей. А поддержка высокоуровневых инструментов ограничивается заявлениями о их ненужности. В принципе, объявление всего, чего нет ненужным можно описать словами "все решено" — в каком-то смысле это решение.
EP>В железе есть: изменяемая память(доступ к которой происходит большими порциями ~64B), многоуровневые кэши, синхронизация между кэшами, изменяемые регистры, стэк (с готовыми инструкциями для работы с ним), указатель на текущую инструкцию и разнообразные переходы. Само собой, если даже самые низкоуровневые абстракции в языке делают вид что ничего этого нет и вносят большое penalty сами по себе — то всё будет тормозить.
Самая низкоуровневая абстракция в плюсах — указатель — как раз делает вид, что ничего этого нет. Что память плоская, а не иерархичная, что она с произвольным доступом и т.д.
EP>Так я об этом и говорю — в языках с GC абстракции скрывающие памяти есть, а для других ресурсов как-то не завезли.
Ну правильно, ссылки на абстракции для других ресурсов вроде pipes вы проигнорировали.
K>>В высокоуровневом языке различие между передачей по ссылке и копированием вообще чаще всего семантически ненаблюдаемо. EP>А тут что?
См. выделенное.
EP>Кстати, а зачем используют эту венгерскую ноткацию? Почему не просто "modify" вместо "modifySTRef"?
Зачем вообще венгерскую нотацию используют? По глупости, очевидно. Я тут по соедству уже такие имена высмеивал.
EP>Вопрос в том как передать это замыкание наверх, а не запретить передачу.
Передавайте без всяких брекетов и все будет жить неизвестно сколько. Впрочем, я это подробно описал в соседней подветке.
K>>Связывание управления памятью с управлением дефицитными ресурсами там ни к чему хорошему не приводит.
EP>О каком управлением памятью идёт речь? EP>В C++ есть объекты, у этих объектов есть lifetime. Объекты могут абстрагировать работу с любым ресурсом — память, файлы, соединения и т.п.
Ну понятно, про языки с ГЦ можно еще сказать, что управление памятью там абстрагировано. Но в каком смысле мы абстрагируемся от управления памятью в C++, если гарантии на доступность языковых сущностей нет и постоянно нужно выбирать каким способом и где именно их размещать, каким способом передавать/возвращать и т.д. Что абстрагировано-то?
EP>Что делать в случае когда у нас несколько ресурсов, время жизни которых пересекаются и зависят друг от друга? (решение с использованием одного большого scope — естественно неинтересно)
Ну так в пейпере про монадические регионы, ссылку на который я давал, описаны вложенные регионы.
EP>Так вопрос же про возвращение замыкания.
Какой смысл тогда вообще регионы использовать?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ну стало быть, согласно твоим словам, ты считаешь что Эрлан это другое название для С++, других объяснений нет
Нет) Я просто не пойму, почему ты считаешь, что факт существования каких-то аналогов MPI противоречит факту лидирующего положения MPI в программирование суперкомпьютеров и вычислительных кластеров.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Аналог это что бы и ссылка-указатель была и модификация состояния и синтаксис, как в С++ ?
_>Синтаксис не обязательно. )
let x = y + 10
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Мы вроде бы говорили о принципах ФП? Ну, вот контролируемая мутабельность этим принципам не противоречит, она нормально встраивается в чистый код. Мутабельность может быть деталью реализации библиотеки, а код ее использующий — полностью идиоматическим.
Контролируемая (т.е. всякие там монады st/io) или же не явная, скрытая внутри языка? Если первое, то это не подходит. А вот второе было бы классно, но я таких языков что-то не знаю...
K>Такое — это какое? Имеется в виду контролируемая мутабельность? Она, разумеется, во всех чистых языках есть. Развитая система для контроля уникальности ссылок есть в Clean. Оптимизации, устраняющие промежуточные результаты, там где это возможно есть в GHC, для списков в стандартной библиотеке и пакете stream-fusion, для массивов в пакетах vector и repa. Вполне работающие.
Мы про конкретный пример говорили (кадры видео и набор комбинаций фильтрующих функций). Так вот, можем ли мы написать чистый (это принципиально естественно, иначе весь смысл теряется) код, который при этом осуществлял бы фильтрацию на месте? ) В том смысле, что код был бы в обычном стиле "всё копируем", но при этом компилятор разглядел бы что можно оптимизировать и превратил бы это всё в фильтрацию массива на месте.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
_>>Ты похоже вообще уже забыл о том, какая задача решалась в той дискуссии. Мы решали проблему "добавление optional в некий существующий код, без его модификации". I>Правильно и это значит, что нужна универсальная функция.
Ну покажи как ты решаешь данную задачу, если у тебя допустим есть такая функция. )
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Погодите. Начали мы с того, что обобщенный код в плюсах нетипизирован. Вы заявили, что обобщенный код везде такой. Когда выяснилось, что это не так, вы заявили, что в плюсах он такой потому, что работает во время компиляции. Когда выяснилось, что тот же параметрический полиморфизм именно во время компиляции и работает, вы заявили, что работа во время компиляции может быть разная. Это, конечно, верно. И именно это и следовало бы обсудить подробнее. Но вы вдруг написали про то, что бывает метапрограммирование внешними средствами, а бывает — средствами языка. При чем тут это? Я запутался.
1. Я нигде не соглашался, что обобщённый код на C++ нетипизирован. Наоборот, я говорил что с этим никаких проблем нет.
2. Я утверждал, что нельзя реализовать одновременно и быстрый параметрический полиморфизм и раздельную компиляцию. В начале были какие-то непонятности насчёт Хаскеля в этой области (т.к. он позволяет и то и то, только не одновременно), но потом мы пришли к выводу, что в нём всё аналогично (правда не два крайних положения, а есть ещё и промежуточные), т.е. никаких чудес, как и в C++.
3. Разговор про метапрограммирование в D к теме обобщённого программирования имеет лишь косвенное отношение и является отклонением от темы, как я сам и указал ещё несколько сообщений назад.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ну стало быть, согласно твоим словам, ты считаешь что Эрлан это другое название для С++, других объяснений нет
_>Нет) Я просто не пойму, почему ты считаешь, что факт существования каких-то аналогов MPI противоречит факту лидирующего положения MPI в программирование суперкомпьютеров и вычислительных кластеров.
Я не знаю, про какие ты супер-копмьютеры говоришь. В суперкомпьютерах бОльшей частью не С++, а какой нибудь фортран или вовсе питон. Фортран потому что никто не хочет переписывать сотни миллионов строчек кода, а питон потому, что программы на суперкомпьютерах обычное дело, работают меньше, чем пишутся.
Эта куча супер-компьютеров, которые реально существуют и их нет на рынке и никогда не будет, в них может быть всё что угодно и это ничего не доказывает — исследования, наблюдения за погодой и тд и тд и тд.
Здравствуйте, Klapaucius, Вы писали:
K>Я надеюсь, вы это все не всерьез пишете.
Я специально там подчёркивал, что речь про чистый код. Понятно, что в грязном монадном коде, который по сути является встроенным императивный подъязыком, это всё без проблем делается. Но в этом смысла как раз нет.
K>Да почему не имеет-то? Да, если не использовать мутабельные ссылки, то семантически наблюдаемой разницы между передачей по ссылке и копированием нет. Но эффективность реализации имеет критическое значение. Какой смысл в фиче, если ее нельзя использовать из-за неприемлимой тормознутости?
Я и говорил, что семантической разницы нет. Разница в том что нам надо править для достижения результата. Базовые принципы или же оптимизацию.
K>Это не так, потому что в декларативных языках есть, в основном, все то же самое, что и в императивных — только в более управляемом виде. Но, даже если и так — так что с того? Императивному языку не нужно это поддерживать в лямбдах? Как раз наоборот, нужно. И императивные языки с решенной UFP вроде C# поддерживают.
Всё очень просто: если чистый функциональный язык полностью обходится в своей работе копированием (возможно оптимизированным) вверх/вниз, то C++, тоже имеющий оптимизированное копирование вверх/вниз, без проблем должен решать все задачи ФП.
K>Чего непонятного-то? Я же объяснил. Этот самый "эффективный [=]" позволяет иметь сколько угодно "копий", а то, о чем вы говорите подразумевает только передачу, а не разделение.
Ну так это же используется только при передаче вверх (т.е. когда старая копия всё равно разрушается сразу). А передав вверх, мы можем уже дальше размножать как угодно обычным const&.
K>Целый парад инвалидов. А нормальной ссылки как не было — так и нет. Выбор хорош тогда, когда его можно не делать — есть хорошее решение по умолчанию, а какое-то другое решение нужно принимать в краевых ситуациях. На C++ же нормального решения по умолчанию нет, есть только краевые, и вдоль вот этих вот стенок "пространства решений" программисту и предлагается двигатся. В результате ФП для него будет не средством облегчения написания и поддержки кода, а цирком с конями в лучшем случае, и изощренной пыткой в остальных.
Как раз это всё без проблем работает, т.к. за исключением shared_ptr это всё встроенные средства самого языка (а не стандартной библиотеки) и соответственно удобно и красиво обрабатывается. А вот при попытке поработать с неконстантной ссылкой в Хаскеле, мы действительно видим инвалидный код. Причём он ещё не просто сам страшный, но и заражает всё вокруг, так что просто так не избавишься от эффектов.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я не знаю, про какие ты супер-копмьютеры говоришь. В суперкомпьютерах бОльшей частью не С++, а какой нибудь фортран или вовсе питон. Фортран потому что никто не хочет переписывать сотни миллионов строчек кода, а питон потому, что программы на суперкомпьютерах обычное дело, работают меньше, чем пишутся.
Не, сейчас там в основном C.
I>Эта куча супер-компьютеров, которые реально существуют и их нет на рынке и никогда не будет, в них может быть всё что угодно и это ничего не доказывает — исследования, наблюдения за погодой и тд и тд и тд.
Вообще то MPI работает не только для суперкомпьютеров, но и для любых кластеров. Более того, он не требуется обязательно специальной ОС и настройки кластера на таком уровне, а позволяет сам построить эффективный кластер на базе произвольной сети компьютеров, работающих под разными ОС.
I>А вот что происходит реально http://www.slideshare.net/max_posedon/world-of-tanks-27831490
Ага, ага. Особенно мне понравился последний слайд с их базовыми идеями: "синхронный подход везде где можно". )))
I>Всего ничего — самая массовая онлайн игра в реальном времени, и это Питон и немного С++. Последний рекорд, позавчера, 1.1КК пользователей одновременно
Да, да, заглядывал туда позавчера. ) По 4 минуты в бой собирало — ужас. )))
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я не знаю, про какие ты супер-копмьютеры говоришь. В суперкомпьютерах бОльшей частью не С++, а какой нибудь фортран или вовсе питон. Фортран потому что никто не хочет переписывать сотни миллионов строчек кода, а питон потому, что программы на суперкомпьютерах обычное дело, работают меньше, чем пишутся.
_>Не, сейчас там в основном C.
Там винигрет всего подряд.
I>>Эта куча супер-компьютеров, которые реально существуют и их нет на рынке и никогда не будет, в них может быть всё что угодно и это ничего не доказывает — исследования, наблюдения за погодой и тд и тд и тд.
_>Вообще то MPI работает не только для суперкомпьютеров, но и для любых кластеров. Более того, он не требуется обязательно специальной ОС и настройки кластера на таком уровне, а позволяет сам построить эффективный кластер на базе произвольной сети компьютеров, работающих под разными ОС.
И где исследования рынка ? "С++ реализация MPI занимает XX(>50) процентов рынка распределенных приложений"
Я в курсе. Странно, что люди решили писать как проще, а не как быстрее, и построили один из наиболее нагруженых игровых проектов.
I>>Всего ничего — самая массовая онлайн игра в реальном времени, и это Питон и немного С++. Последний рекорд, позавчера, 1.1КК пользователей одновременно
_>Да, да, заглядывал туда позавчера. ) По 4 минуты в бой собирало — ужас. )))
Перформанс здесь ни при чем. Это балансер так работает, алгоритм подбора команд кривой. 9й-10й левел практически без задержек, а 8й ни разу не дождался. Я за день вкинул примерно 50 боёв и ни разу не было проблемы с пингом или лагами.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>И где исследования рынка ? "С++ реализация MPI занимает XX(>50) процентов рынка распределенных приложений"
Я не писал про C++ ничего такого. Я писал именно про MPI. И уточнил ещё, что это родная техника для C/C++. )
I>Я в курсе. Странно, что люди решили писать как проще, а не как быстрее, и построили один из наиболее нагруженых игровых проектов.
На самом деле он у них самый нагруженный только по числу пользователей. Но т.к. бои все не больше чем по 30 человек, то оно очень сильно и без всяких напрягов распараллеливается. Т.е. грубо говоря, если мы сумели построить шуструю систему для одного боя, то дальнейший рост не так сложен.
А действительно самый нагруженный игровой проект, это вроде как EVE Online, т.к. там чуть ли не единый мир для всех игроков. Т.е. там тоже есть какое-то деление на регионы, но технически все игроки могут собраться в одном. И когда такое бывает, то она адски тормозит. ))) Ну это по слухам, я сам не играл в неё.
I>Перформанс здесь ни при чем. Это балансер так работает, алгоритм подбора команд кривой. 9й-10й левел практически без задержек, а 8й ни разу не дождался. Я за день вкинул примерно 50 боёв и ни разу не было проблемы с пингом или лагами.
Нормальный там балансер, это просто сами игроки такое устроили (не знаю почему, акция что ли какая-то была?). Я там видел в процессе ожидания расклад типа 8000 человек в очереди на 8-ом уровне и по 500 человек на остальных. Т.е. балансер тупо не успевал раскидать 8-ок. Но при этом надо отдать должное, работал без единого сбоя, просто медленно (ну так и онлайн был рекордный). Т.е. в целом у них система отличная сейчас.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>И где исследования рынка ? "С++ реализация MPI занимает XX(>50) процентов рынка распределенных приложений"
_>Я не писал про C++ ничего такого. Я писал именно про MPI. И уточнил ещё, что это родная техника для C/C++. )
Какой то новый термин. Родная техника это когда для hello world нужны простыни кода ?
_>На самом деле он у них самый нагруженный только по числу пользователей. Но т.к. бои все не больше чем по 30 человек, то оно очень сильно и без всяких напрягов распараллеливается. Т.е. грубо говоря, если мы сумели построить шуструю систему для одного боя, то дальнейший рост не так сложен.
Шустрые системы для одного боя были еще в 90х и шота выходит, все кто ни брался, не знали твою истину. Так что ли ?
_>А действительно самый нагруженный игровой проект, это вроде как EVE Online, т.к. там чуть ли не единый мир для всех игроков. Т.е. там тоже есть какое-то деление на регионы, но технически все игроки могут собраться в одном. И когда такое бывает, то она адски тормозит. ))) Ну это по слухам, я сам не играл в неё.
Интересный аргумент — еще один Питон + немного С++.
I>>Перформанс здесь ни при чем. Это балансер так работает, алгоритм подбора команд кривой. 9й-10й левел практически без задержек, а 8й ни разу не дождался. Я за день вкинул примерно 50 боёв и ни разу не было проблемы с пингом или лагами.
_>Нормальный там балансер, это просто сами игроки такое устроили (не знаю почему, акция что ли какая-то была?). Я там видел в процессе ожидания расклад типа 8000 человек в очереди на 8-ом уровне и по 500 человек на остальных. Т.е. балансер тупо не успевал раскидать 8-ок. Но при этом надо отдать должное, работал без единого сбоя, просто медленно (ну так и онлайн был рекордный). Т.е. в целом у них система отличная сейчас.
И представь — это Питон, который такой тормозной против С++
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Какой то новый термин. Родная техника это когда для hello world нужны простыни кода ?
Это ты вообще о чём? )
I>Интересный аргумент — еще один Питон + немного С++.
Ты так говоришь, как будто бы это не два моих любимых языках. ))) Хотя да, D всё же на мой вкус лучше, но у него нет инфраструктуры...
I>И представь — это Питон, который такой тормозной против С++
Ну вообще то сайт и у нас на Питоне работает. ))) Так что я как-то не пойму что ты хочешь сказать этим. )
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Какой то новый термин. Родная техника это когда для hello world нужны простыни кода ?
_>Это ты вообще о чём? )
I>>Интересный аргумент — еще один Питон + немного С++.
_>Ты так говоришь, как будто бы это не два моих любимых языках. ))) Хотя да, D всё же на мой вкус лучше, но у него нет инфраструктуры...
Это очень интересные сведения. Наверное то хочешь сказать, что питон уже догнал С++ по производительности ?
I>>И представь — это Питон, который такой тормозной против С++
_>Ну вообще то сайт и у нас на Питоне работает. ))) Так что я как-то не пойму что ты хочешь сказать этим. )
Все ты понимаешь, только притворяешься, — и клиент и сервер eve online написаны в основном на питоне, точнее на stackless Python.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В смысле? Возможно одновременное изменение/чтение одних и тех же данных из нескольких потоков — поэтому и вводится синхронизация.
"на ровном месте" означает "без нужды". Тут может быть три варианта:
1) Вы считаете, что ленивость не нужна.
2) Вы не поняли зачем это нужно. (вычеркиваем)
3) У вас есть идея получше, как обеспечить ту же функциональность.
Предполагаю, что правильный ответ — 1.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это очень интересные сведения. Наверное то хочешь сказать, что питон уже догнал С++ по производительности?
Не) Даже pypy версия только отдалённо приближается к js(v8)/Java/C#, а в нормальном Питоне вообще мрак в этом смысле. ))) Но там, где мы его используем, скорость вообще не принципиальна.
I>Все ты понимаешь, только притворяешься, — и клиент и сервер eve online написаны в основном на питоне, точнее на stackless Python.
Ну я про это не в курсе, но если ты говоришь, то наверное так и есть. ) И что? )
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Это очень интересные сведения. Наверное то хочешь сказать, что питон уже догнал С++ по производительности?
_>Не) Даже pypy версия только отдалённо приближается к js(v8)/Java/C#, а в нормальном Питоне вообще мрак в этом смысле. ))) Но там, где мы его используем, скорость вообще не принципиальна.
Опаньки ! И это, представь, не является препятствием для построения суперкомпьютера навроде evo online, который входит в top 500.
I>>Все ты понимаешь, только притворяешься, — и клиент и сервер eve online написаны в основном на питоне, точнее на stackless Python.
_>Ну я про это не в курсе, но если ты говоришь, то наверное так и есть. ) И что? )
Это показывает, что твои аргументы про С++ несостоятельны.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Опаньки ! И это, представь, не является препятствием для построения суперкомпьютера навроде evo online, который входит в top 500.
Там вроде не суперкомпьютер, а просто жирный кластер. Суперкомпьютер они может и хотели бы, но это стоит совсем другие деньги. )))
I>Это показывает, что твои аргументы про С++ несостоятельны.
Ээээ какие аргументы? Я вообще не пойму с чем ты споришь последний день. ) Вроде бы всё началось с твоего утверждения, что функциональные языки имеют какие-то таинственные преимущества при создание распределённых программ. Тогда причём тут примеры с Питоном, который функциональный не более чем тот же C++?
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Опаньки ! И это, представь, не является препятствием для построения суперкомпьютера навроде evo online, который входит в top 500.
_>Там вроде не суперкомпьютер, а просто жирный кластер. Суперкомпьютер они может и хотели бы, но это стоит совсем другие деньги. )))
Я не знаю как проверить, раньше утверждалось что кластер eve входит в top500.
I>>Это показывает, что твои аргументы про С++ несостоятельны.
_>Ээээ какие аргументы?
Вот такие: "Речь конечно же про быстродействие кода."
Внезапно оказалось, что быстродействие кода вообще ни при чем. Питон недотягивает даже до джаваскрипта который заметно медленнее дотнета или джавы которые много медленее С++
>Тогда причём тут примеры с Питоном, который функциональный не более чем тот же C++?
Наоборот, он более функциональный относительно С++, например благодаря ленивости.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я не знаю как проверить, раньше утверждалось что кластер eve входит в top500.
Ну так я и говорю, что у них кластер. Т.е. по сути просто сеть обычных компьютеров. А суперкомпьютер — это другое совсем. Там идут прямые высокоскоростные каналы связи между процессорами, образующие сложную топологию (т.к. каждый с каждым всё равно не соединишь), оригинальную для каждого суперкомпьютера. Это позволяет спокойно использовать такие вещи как общую память и т.п. Т.е. тот же MPI естественно предоставляет такие же возможности и на обычной сети, но понятно, что они уступают аппаратному решению на порядки.
Кстати, eve online как раз суперкомпьютер был бы очень кстати, т.к. у них реально один мир. Только вот стоят они совсем астрономически...
I>Вот такие: "Речь конечно же про быстродействие кода."
В одних местах быстродействие важно, а в других нет. К примеру на нашем сервере (где Питон живёт) вообще не принципиально. А скажем фейсбук и вконтакте в начале тоже жили на php (скорость типа Питона), но в итоге потратили очень не мало сил на разработку своего подмножества php, которое можно компилировать в C, чтобы в итоге всё работало на нативном коде...
I>Внезапно оказалось, что быстродействие кода вообще ни при чем. Питон недотягивает даже до джаваскрипта который заметно медленнее дотнета или джавы которые много медленее С++
Ну там, где быстродействие не принципиально и проект не особо сложен, Питончик себя отлично чувствует. Хотя некоторые используют его и для больших проектов — это на мой вкус не очень с его типизацией. Вообще лично я предпочёл бы для очень многих целей (и там где у нас сейчас Питон используется и для части (не критичной по быстродействию) задач на C++) некий статически типизированный Питон. Но ни одного подобного языка я не знаю что-то...
I>Наоборот, он более функциональный относительно С++, например благодаря ленивости.
Ленивость в Питоне? Ничуть не больше чем в C++, буквально тот же самый набор компонентов. Разве что генераторы в явном виде есть (в C++ тоже можно завести такие, но никто этим не занимается, т.к. используется другая техника, на базе итераторов).
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Кстати, eve online как раз суперкомпьютер был бы очень кстати, т.к. у них реально один мир. Только вот стоят они совсем астрономически...
Нету там астрономических цифр, в Eve не 100 человек играет. Просто челы уже вложились в то что есть и менять уже поздно.
_>В одних местах быстродействие важно, а в других нет. К примеру на нашем сервере (где Питон живёт) вообще не принципиально. А скажем фейсбук и вконтакте в начале тоже жили на php (скорость типа Питона), но в итоге потратили очень не мало сил на разработку своего подмножества php, которое можно компилировать в C, чтобы в итоге всё работало на нативном коде...
Я думаю, если бы они взяли для решения проблем специалиста по Эрлангу, у них щас был бы вместо С++ эрланг.
I>>Внезапно оказалось, что быстродействие кода вообще ни при чем. Питон недотягивает даже до джаваскрипта который заметно медленнее дотнета или джавы которые много медленее С++
_>Ну там, где быстродействие не принципиально и проект не особо сложен, Питончик себя отлично чувствует. Хотя некоторые используют его и для больших проектов — это на мой вкус не очень с его типизацией. Вообще лично я предпочёл бы для очень многих целей (и там где у нас сейчас Питон используется и для части (не критичной по быстродействию) задач на C++) некий статически типизированный Питон. Но ни одного подобного языка я не знаю что-то...
То есть, worldoftanks и eveonline это несложные проектики ?
I>>Наоборот, он более функциональный относительно С++, например благодаря ленивости.
_>Ленивость в Питоне? Ничуть не больше чем в C++, буквально тот же самый набор компонентов. Разве что генераторы в явном виде есть (в C++ тоже можно завести такие, но никто этим не занимается, т.к. используется другая техника, на базе итераторов).
Ленивость уже больше чем в С++. А еще всякие comprehension и тд
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>А если я в какой-нибудь вики напишу, что луна из сыра — вы поверите? Ну попробуйте тот же функциональный "хэллоуворлд" на C++ написать K>
K>И расскажете потом, сильно ли вам помогло то, что в какой-то вики написано, что C++ поддерживает ФП.
Встроенной ленивости и ленивых списков естественно нет. Их нет не потому что C++ не поддерживает ФП — а потому что используются более эффективные техники (писать ФП ради самого ФП — нет смысла. есть смысл применять ФП там, где необходимы его полезные свойства). Да и вообще — ленивость не во всех функциональных языках есть.
Соответственно понадобится boilerplate для их определения: Lazy<T>, LazyList<T>, каррированные cons, zipWith, etc.
Пример выше запишется вот так:
auto fibs = fix(cons(0) * cons(1) * (zipWith(plus) <ap> tail));
Где * это композиция функций, а <ap> — это соответствующий named operator.
Re[27]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Что означает "идиоматический ФП-код"? K>Комбинирование комбинаторов. EP>>Это синоним кода который тормозит? K>Да. Чтоб такой код работал с более-менее приемлемой скоростью нужен специальный рантайм, заточенный под такие вещи и компилятор со специфическими оптимизациями. Поэтому в каком-нибудь гибриде, в который добавили функциональных фич потому, что это "модно" идиоматический ФП код (если его еще и получится написать) запросто может отличаться по производительности от кода а-ля фортран как скриптовый язык от компилируемого статтипизированного.
Нет, я о том, что этот "идиоматичный" пример тормозит даже со специальным runtime'ом. Например на ровном месте вводятся межпоточная синхронизации и медленные списки.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я думаю, если бы они взяли для решения проблем специалиста по Эрлангу, у них щас был бы вместо С++ эрланг.
В смысле устроили бы компиляцию php в эрланг? %) Это очень сомнительная идея)
I>То есть, worldoftanks и eveonline это несложные проектики ?
Для начала, если взять их клиентскую часть, то там совсем не python приложение, использующее C++ библиотеки, а чистое C++ приложение, использующее python в качестве встроенного языка для небольших внутренних скриптов. Это принципиально другая архитектура и такое решение я полностью одобряю по всем параметрам. Мы и сами подобное делали.
Если же говорить про их серверную архитектуру, то лично я не знаю как там у них что устроено. На тех слайдах про танчики конечно было указано, что у них в качестве БД mysql, а код на python без GC и C++, но это как бы слишком неконкретно. Но если там, как ты говоришь, всё реализовано в виде одного большого приложения на python'е, то лично мне такое решение не очень нравится. Даже если забыть о быстродействие, то подобный сложный код на языке без статической типизации я бы не стал писать. Но это уже лично мой вкус.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я думаю, если бы они взяли для решения проблем специалиста по Эрлангу, у них щас был бы вместо С++ эрланг.
_>В смысле устроили бы компиляцию php в эрланг? %) Это очень сомнительная идея)
В смысле использовали эрланговский подход а не плюсовый.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>>>Это цифры с потолка. Эрланг показывает и доказывает что твои рассуждения ошибочны. EP>>>>Какие именно рассуждения, и как он доказывает? I>>>На нём пишутся распределенные системы, внезапно ! EP>>И как это доказывает то, что он работает не медленнее чем аналогичный код на императивном языке? I>Код никого не интересует. Интересуют выходные характеристики конечной системы.
Пусть будут характеристики — суть вопроса от этого не меняется.
I>>>Эрланг собтсвенно и начал с того, что порвал С++ в распределенных приложениях для телекоммуникаций. EP>>Erlang рулит в первую очередь из-за инфраструктуры, а не из-за самого языка. Точно также как рулит и node.js за счёт инфраструктуры. I>Это инфраструктуру без подобного языка заюзать невозможно, в принципе.
Что мешает использовать подобную архитектуру для C++/D?
I>>>Это скучно. EP>>Конечно, мы же обсуждаем чистые ФП и эффективность их мэппинга в железо. Если тебе скучно — то я I>Это тебе интересно обсуждать ислючительно мапинг в железо.
В этой под-ветке мы как раз и обсуждаем мэппинг в железо
I>>>Я говорю про отношение часть-целое и характеристики составляющих. У узла узкое место процессор и система ввода-вывода, а у распределенной системы узким местом будет не процессоры и ввод-вывод, EP>>У распределённых число-дробилок в большинстве случаев узким местом будет как раз процессор. I>То есть, ты хочешь сказать, что некоторые распределенные системы есть множество всех распределенных систем ?
Нет, я говорю что выделенное твоё высказывание в общем случае не верно. Если ты имеешь ввиду какой-то конкретный нишевый use-case — то так и говори.
EP>>Что "вот-вот"? Я же говорю — использование элементов ФП это хорошо. I>Ты почему то начал спрашивать, когда это ФП попало в нативный код
Ты сказал
Более того — ФП влазло и в нативный код.
Тут вроде все согласны, что в нативном коде, в C++ в частности, ФП элементы есть давно. Поэтому не сосем понятно к чему ты это сказал. Я попросил всего лишь раскрыть твою мысль, так как не совсем понятно к чему это.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>И как это доказывает то, что он работает не медленнее чем аналогичный код на императивном языке? I>>Код никого не интересует. Интересуют выходные характеристики конечной системы.
EP>Пусть будут характеристики — суть вопроса от этого не меняется.
Меняется. Тормозной питон как то справляется с высоконагружеными приложениями
I>>Это инфраструктуру без подобного языка заюзать невозможно, в принципе.
EP>Что мешает использовать подобную архитектуру для C++/D?
Человеческий фактор, это очевидно. Нужно что бы язык страховал от большинства ошибок или позволял забесплатно и быстро найти их. В С++ ни того, ни другого нет.
EP>>>Что "вот-вот"? Я же говорю — использование элементов ФП это хорошо. I>>Ты почему то начал спрашивать, когда это ФП попало в нативный код
EP>Ты сказал EP>
EP>Более того — ФП влазло и в нативный код.
EP>Тут вроде все согласны, что в нативном коде, в C++ в частности, ФП элементы есть давно. Поэтому не сосем понятно к чему ты это сказал. Я попросил всего лишь раскрыть твою мысль, так как не совсем понятно к чему это.
Ты говорил про ФП на задворках империи. Это, внезапно, оказалось давно не так даже в С++.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>2 Замыкания не теряют связь с локальными переменными, никогда, ни при каких случаях, до момента сборки мусора. EP>>Допустим у нас такое определение — ОК. EP>>Что делать в случае, когда захватываются ресурсы? (пусть это не относится к UFP по данному выше определению) I>Контролировать ресурсы явно, руками.
Об этом и речь.
I>Проблема с ФП в том, что циклические ссылки это норма. Это поначалу просто убивает мозг.
Покажи пример циклической ссылки при использовании полностью immutable структур, и eager evaluation.
I>Итого — если делать "как в С++" то надо бороться с циклическими ссылками и желательно что бы эти циклические ссылки искал компилятор, а вот компилятор этого как раз и не умеет. То есть, в итоге пришли к ручному управлению, когда, казалось бы, нужна была автоматизация. Все чего добились — ручная неявная работа с ресурсами.
Да не надо "как в С++" — покажи хоть какое-то автоматическое решение этого варианта UFP.
I>В С++ придется следить за циклическими ссылками, приседать, обрезать и тд и тд и тд и всё это руками, но ресурсы будут освобождаться неявно.
Нет, не придётся следить за циклическими ссылками — представь что в этом примере их нет (да и вообще в C++ они редко встречаются).
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>ST не работает в Haskell 98, то есть требует расширение? K>Haskell 98 — это подмножество языка, выделенное для того, чтоб гарантировать компилируемость кода в учебниках для начинающих.
Ок. А как контролируется зоопарк расширений? Через reference implementation? Или есть какой-то стандарт?
EP>>
import System.IO
main = do
closure <- withFile "test.out" WriteMode $ \f -> do
hPutStr f "ok"
return $ \s -> do
hPutStr f "logging: "
hPutStrLn f s
closure "fail"-- test.out: hPutStr: illegal operation (handle is closed)
EP>>как? K>Я вам давал ссылку на монадические регионы.
Как они помогут в примере выше? Запретив использование такого замыкания? Это не интересно.
EP>>В случае с C++ я знаю как и насколько он поддерживает functional programming. Относительно UFP — я вам приводил несколько вариантов решения, причём которые работают не только для памяти. K>Гарантии на продлевание жизни захваченных языковых сущностей ни одно из этих "решений" не дает, а значит и UFP не решает.
Как минимум [=] даёт определённые гарантии.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>И как это доказывает то, что он работает не медленнее чем аналогичный код на императивном языке? I>>>Код никого не интересует. Интересуют выходные характеристики конечной системы. EP>>Пусть будут характеристики — суть вопроса от этого не меняется. I>Меняется. Тормозной питон как то справляется с высоконагружеными приложениями
Такими "высоконагруженными" что всё в IO упирается? Ну так приложения разные бывают, и естественно для разных приложений подходят разные языки. Где-то нужно по максимуму использовать потенциал железа, а где-то достаточно переложить пару байтиков из одного места в другое. Где-то дешевле добавить сто машин, где-то дешевле немного подумать
I>>>Это инфраструктуру без подобного языка заюзать невозможно, в принципе. EP>>Что мешает использовать подобную архитектуру для C++/D? I>Человеческий фактор, это очевидно. Нужно что бы язык страховал от большинства ошибок или позволял забесплатно и быстро найти их. В С++ ни того, ни другого нет.
От таких именно ошибок гарантированно страхует Erlang? (и от чего нельзя застраховаться в C++/D теми или иными спосабами)
EP>>Тут вроде все согласны, что в нативном коде, в C++ в частности, ФП элементы есть давно. Поэтому не сосем понятно к чему ты это сказал. Я попросил всего лишь раскрыть твою мысль, так как не совсем понятно к чему это. I>Ты говорил про ФП на задворках империи. Это, внезапно, оказалось давно не так даже в С++.
Не просто ФП, а именно чистый ФП.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>1. Изначально речь шла про автоматическое преобразование обычного кода в монадический.
K>Ну да. Но это, строго говоря, непонятно как делать, потому что монадичность добавляет возможности, которых раньше не было. В том же вашем примере уже есть обработка пустого значения (одна из веток if возвращает () — не понятно, что это может значить в чистом коде), так что имеет место только замена одной монады на другую. Вот автоматический лифтинг в апплиативный функтр — это более реально.
Никакого монадического кода там не было, если конечно не считать тривиальную монаду.
Там не обработка пустого значения — а возвращение (причём возвращать пустое значение не обязательно). Это просто void. Я добавил if чтобы продемонстрировать что это именно монада, а не АФ.
call-with-current-continuation — позволяет завернуть остаток кода в continuation, и что-то сделать с результатом. Тут для результата делается просто монадический return, каким бы он не был. Примерно также работает await в C#, только там много разных ограничений.
Например вот тут есть статья на эту тему:
We show that any monad whose unit and extension operations are expressible as purely functional terms can be embedded in a call-by-value language with "composable continuations". As part of the development, we extend Meyer and Wand's characterization of the relationship between continuation-passing and direct style to one for continuation-passing vs. general "monadic" style. We further show that the composable-continuations construct can itself be represented using ordinary, non-composable first-class continuations and a single piece of state. Thus, in the presence of two specific computational effects -- storage and escapes -- any expressible monadic structure (e.g., nondeterminism as represented by the list monad) can be added as a purely definitional extension, without requiring a reinterpretation of the whole language. The paper includes an implementation of the construction (in Standard ML with some New Jersey extensions) and several examples.
... The embedding result is also a strong argument for inclusion of firstclass continuations in practical eager languages especially ones like ML that already have mutable cells providing call/cc does not simply add yet another monadic effect it completes the language to all such effects Moreover a sophisticated module system like SMLs lets us expose as little or as much of this underlying raw power as we need by picking the appropriate monadic structure we can introduce effects ranging from simple exceptions to full composable continuations
K>Соотвественно и для операций с Maybe раннее завершение обеспечивает не "монадичность", а ленивость. И без ленивости и след. раннего завершения просто от Maybe мало толку.
Подробнее. В примере Scheme — никакой ленивости нет, но раннее завершение у maybe — есть.
EP>>В языках же с call-with-current-continuation: любой код можно сделать монадическим без модификаций (либо нужно сделать минимальные модификации, заменив "x" на "get(x)" — если нет перегрузки всего как в D. K>Чего его делать — он и так уже монадический. Одну монаду на другую заменить можно (ряд монад с помощью Cont[inuation] можно заменить, правда не все).
Приведите тогда пример немонадического кода на Scheme.
EP>>
K>>>Мы вроде бы в соседней ветке выяснили, что без ленивости комбинирование функций теряет смысл из-за непрактичности.
EP>>Хотя ничего подобного мы не выясняли K>Т.е. вычислять ненужное — это практично?
Ленивость позволяет не вычислять ненужное в тех случаях, когда функция/алгоритм описаны с ненужными вычислениями. Какое-то засилье ненужных вычислений в ФП, из-за которого ленивость необходима как пища, продемонстрировано не было. Более того, судя по Q&A на stackoverflow, когда нужна скорость — от этой ленивости бегут, точно также как и от GC.
K>Или непрактичность не делает комбинирование бессмысленным?
Непрактичность ленивости? Комбинирование обязательно влечёт за собой ленивость?
K>Или имеется в виду, что call-with-current-continuation тоже дает возможность получать комбинаторый код, который не делает бессмысленных действий?
Мы же вроде обсуждали монадический код?
K>Ну да, только реализация языка с континьюэйшенами, которая с более-менее приличной скоростью работает — это сложнее, чем реализация ленивого языка.
С этим я не спорю. Я просто показал, как в языках с call/cc обычный код легко превращается в монадичный.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>>>>>Про "неработающие" замыкания в C++ из-за UFP любители GC мне тут уже третий раз говорят, хотя "плюсисты" не имеют с этим проблем. На деле же оказывается что работают, и не только для памяти. EP>>В выделенном разговор был не про ФП. K>Ну а как можно не испытывать проблем с неработающими замыканиями, если только не пользоваться ими нормально, а рассказывать на форумах про то, что они якобы работающие?
Опять 25. Почему они не работающие? Они работают даже для ресурсов в отличии от.
EP>>На C++ как раз высокоуровневый код отлично мэппится в железо. The Standard Template Library K>Высокоуровневый код — это когда можно делать вид, что языковые сущности — это математические объекты, содержательно рассуждать о них в таком ключе и получать нормально работающий код.
На C++ есть всякие DSL библиотеки, позволяющие писать высокоуровневый, который отлично мэппятся в железо. Например Eigen может во время компиляции выбрать оптимальный путь вычисления матричного выражения, и автоматически векторизовать.
Опять-таки высокоуровневый != огромное penalty.
EP>>То что где-то дорогие абстракции — не означает что они дорогие везде. Естественно, если использовать связанные списки которые плохо мэппятся в железо, thunk'и которые на ровном месте добавляют меж-потоковую синхронизацию и излишние циклы требующие GC — то всё будет тормозить. K>Точно, а если копировать массивы, считать ссылки
В большинстве кода не то что shared_ptr нет, а даже unique_ptr.
K>и вычислять то, что вычислять ненужно все будет летать.
Где вычисляется то что ненужно?
K>Сравнимый по высокоуровневости код с такими подходами не то, что тормозить будет — он вообще никуда не поедет.
Выводы на основе ложных утверждений. Далеко не все абстракции дорогие.
K>Поэтому никакого высокоуровневого кода и нет — есть только продвинутый интерфейс для двигания указателей. А поддержка высокоуровневых инструментов ограничивается заявлениями о их ненужности.
См. Eigen.
K>В принципе, объявление всего, чего нет ненужным можно описать словами "все решено" — в каком-то смысле это решение.
Да — это именно то решение, которое вы описали для UFP с ресурсами: "ненужно, поэтому запретить".
EP>>В железе есть: изменяемая память(доступ к которой происходит большими порциями ~64B), многоуровневые кэши, синхронизация между кэшами, изменяемые регистры, стэк (с готовыми инструкциями для работы с ним), указатель на текущую инструкцию и разнообразные переходы. Само собой, если даже самые низкоуровневые абстракции в языке делают вид что ничего этого нет и вносят большое penalty сами по себе — то всё будет тормозить. K>Самая низкоуровневая абстракция в плюсах — указатель — как раз делает вид, что ничего этого нет. Что память плоская, а не иерархичная, что она с произвольным доступом и т.д.
1. Какую abstraction penalty вносит указатель сам по себе? Хм, может быть межпоточную синхронизацию?
2. Да, у разных машин есть особенности которые нужно учитывать.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>В смысле? Возможно одновременное изменение/чтение одних и тех же данных из нескольких потоков — поэтому и вводится синхронизация. K>"на ровном месте" означает "без нужды". Тут может быть три варианта:
Встроенная абстракция языка, которая как вы говорите является "пищей ФП" и которая судя по всему используется повсеместно, даже в hello world, вводит меж-поточную синхронизацию (относительная цена которой с каждым годом только возрастает) — это и называется "на ровном месте".
K>1) Вы считаете, что ленивость не нужна.
Нужна ли такая абстракция или нет, приемлема ли такое penalty или нет — естественно зависит от прикладной области.
K>2) Вы не поняли зачем это нужно. (вычеркиваем) K>3) У вас есть идея получше,
Я предполагаю что лучшего решения нет — мутабельные данные (модификация/чтение для которых может пересекаться) требуют синхронизации by-design, поэтому их и нужно избегать.
K>как обеспечить ту же функциональность. K>Предполагаю, что правильный ответ — 1.
Решение аналогичных задач (но через другую функциональность) в других языках достигается куда более дешёвыми средствами.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Меняется. Тормозной питон как то справляется с высоконагружеными приложениями
EP>Такими "высоконагруженными" что всё в IO упирается?
Есть разные примеры, например такие World of tanks, Eve online
Кроме того, есть всякие разные вычисления, где, казалось бы, нужен перформанс, перформанс, перформанс, о оказывается все не так просто http://www.adass.org/adass/proceedings/adass99/O3-02/
>Ну так приложения разные бывают, и естественно для разных приложений подходят разные языки. Где-то нужно по максимуму использовать потенциал железа, а где-то достаточно переложить пару байтиков из одного места в другое. Где-то дешевле добавить сто машин, где-то дешевле немного подумать
Есть одно правило — дешевле, проще, быстрее сделать корректное медленное быстрым, чем некорректное корректным.
I>>>>Это инфраструктуру без подобного языка заюзать невозможно, в принципе. EP>>>Что мешает использовать подобную архитектуру для C++/D? I>>Человеческий фактор, это очевидно. Нужно что бы язык страховал от большинства ошибок или позволял забесплатно и быстро найти их. В С++ ни того, ни другого нет.
EP>От таких именно ошибок гарантированно страхует Erlang? (и от чего нельзя застраховаться в C++/D теми или иными спосабами)
Ошибки с указателями, ошибки с изменением состояния, корректное взаимодействие и тд и тд.
"Теми или иными" это большей частью мифы, теоретическое рассуждение.
I>>Ты говорил про ФП на задворках империи. Это, внезапно, оказалось давно не так даже в С++.
EP>Не просто ФП, а именно чистый ФП.
Абсолютно чистого ФП в природе пока что нет, так что всё в порядке.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Проблема с ФП в том, что циклические ссылки это норма. Это поначалу просто убивает мозг.
EP>Покажи пример циклической ссылки при использовании полностью immutable структур, и eager evaluation.
А при чем здесь "полностью immutable" ? Функциональщина это отделение сайдэффектов в отдельную коробочку, а не когда всё абсолютно иммутабельное. Если всё абсолютно иммутабельное, то надо как то обеспечить бесконечную память.
I>>Итого — если делать "как в С++" то надо бороться с циклическими ссылками и желательно что бы эти циклические ссылки искал компилятор, а вот компилятор этого как раз и не умеет. То есть, в итоге пришли к ручному управлению, когда, казалось бы, нужна была автоматизация. Все чего добились — ручная неявная работа с ресурсами.
EP>Да не надо "как в С++" — покажи хоть какое-то автоматическое решение этого варианта UFP.
C UFP всё в порядке — передача лямбды наверх не разрушает связь с экземпляром и здесь не надо ничего автоматизировать, всё и так работает автоматически.
Если ты про управление ресурсами, а не UFP, то можешь заметить, я пишу о том, что ни там, ни там нет автоматического управления. В обоих случаях ручное управление, только вызов освобождения в одном случае делается явно, в другом неявно. То есть, разница только в местах, где ты раскладываешь подсказки компилятору что бы он вовремя вызвал нужный метод как ::close, .Dispose или delete .
Автоматическое управление, это использование обычных классов, безо всяких оберток, врапперов, смартпоинтеров и тд и тд и тд, и рантайм сам освобождает ресурсы, примерно как GC обходится с памятью. Вот это автоматическое, а то о чем ты говоришь это варианты ручного.
I>>В С++ придется следить за циклическими ссылками, приседать, обрезать и тд и тд и тд и всё это руками, но ресурсы будут освобождаться неявно.
EP>Нет, не придётся следить за циклическими ссылками — представь что в этом примере их нет (да и вообще в C++ они редко встречаются).
Как минимум придется руками обеспечивать разделяемое владение.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Контролируемая (т.е. всякие там монады st/io) или же не явная, скрытая внутри языка?
И та и другая.
_>Если первое, то это не подходит.
Отлично подходит. Вы, конечно, можете выдумать какое-то специальное убогое ФП, принципам которого такая контролируемая мутабельность не соответствует, а потом его критиковать, но к реальности это никакого отношения не имеет.
_>А вот второе было бы классно
Ну вот ленивость — это "неявная, скрытая" мутабельность, что продемонстрировано по соседству.
_>Мы про конкретный пример говорили (кадры видео и набор комбинаций фильтрующих функций). Так вот, можем ли мы написать чистый (это принципиально естественно, иначе весь смысл теряется) код, который при этом осуществлял бы фильтрацию на месте? ) В том смысле, что код был бы в обычном стиле "всё копируем", но при этом компилятор разглядел бы что можно оптимизировать и превратил бы это всё в фильтрацию массива на месте.
Конкретный пример — это код.
Я же говорю, оптимизации, которые устраняют промежуточные массивы, списки и т.д. в комбинации функций, каждая из которых по по отдельности копирует, а не меняет по месту существуют и вполне работают. Как и все оптимизации, работают они не всегда, но объем копирования существенно сокращают. Т.е. компилятор оптимизирующий код вида:
Здравствуйте, alex_public, Вы писали:
_>1. Я нигде не соглашался, что обобщённый код на C++ нетипизирован. Наоборот, я говорил что с этим никаких проблем нет.
То, что он нетипизирован (точнее, опционально типизирован) — это объективная реальность, тут от согласия ничего не зависит.
_>2. Я утверждал, что нельзя реализовать одновременно и быстрый параметрический полиморфизм и раздельную компиляцию.
Почему нельзя? Можно достигать высокие степени "раздельности" с помощью линктайм кодогенерации или AOT/JIT-компилятора, например.
_>В начале были какие-то непонятности насчёт Хаскеля в этой области (т.к. он позволяет и то и то, только не одновременно), но потом мы пришли к выводу, что в нём всё аналогично (правда не два крайних положения, а есть ещё и промежуточные), т.е. никаких чудес, как и в C++.
Непонятно, в каком смысле это аналогично C++ если там нет даже второго крайнего положения, не говоря уже о промежуточных, а есть только одно.
Тем не менее, раздельность компиляции и типизированность — вообще ортогональные понятия. Параметрический полиморфизм и параметризованные модули могут (и являются в ряде языков) генеративными, а не аппликативными, и тем не менее полностью типизированы. Существует также достаточно близкий родственник плюсовых шаблонов — F#-ные инлайн-функции, которые также полностью типизированы.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я специально там подчёркивал, что речь про чистый код.
Код с IO/ST как раз чистый, для того, чтоб он был таковым они и нужны. Чтоб сделать из них "нечистый" нужно воспользоваться каким-нибудь unsafePerformIO.
_>Понятно, что в грязном монадном коде, который по сути является встроенным императивный подъязыком, это всё без проблем делается. Но в этом смысла как раз нет.
Смысл в этом, разумеется, есть — куда же он делся?
_>Я и говорил, что семантической разницы нет. Разница в том что нам надо править для достижения результата. Базовые принципы или же оптимизацию.
Вы говорили про то, что чего-то нет, хотя очевидно и легко проверяется, что оно, наоборот, есть. Если тут нужно что-то править — так это процесс подготовки аргументов для дискуссии.
_>Всё очень просто: если чистый функциональный язык полностью обходится в своей работе копированием (возможно оптимизированным) вверх/вниз, то C++, тоже имеющий оптимизированное копирование вверх/вниз, без проблем должен решать все задачи ФП.
Во-первых, не обходится. Во вторых, то что вы называете "оптимизированным копированием" в языках с решенной UFP и в C++ существенно отличаются.
_>Ну так это же используется только при передаче вверх (т.е. когда старая копия всё равно разрушается сразу). А передав вверх, мы можем уже дальше размножать как угодно обычным const&.
А если мы возвращаем пару или вовсе список замыканий?
_>Как раз это всё без проблем работает, т.к. за исключением shared_ptr это всё встроенные средства самого языка (а не стандартной библиотеки) и соответственно удобно и красиво обрабатывается.
Доступность не гарантирует, тормозит в случае подсчета ссылок, циклы не поддерживает, заставляет постоянно выбирать "на ровном месте". Это все не проблемы разве?
_>А вот при попытке поработать с неконстантной ссылкой в Хаскеле, мы действительно видим инвалидный код.
Видим полностью рабочий код, который перечисленных выше недостатков не имеет.
_>Причём он ещё не просто сам страшный, но и заражает всё вокруг, так что просто так не избавишься от эффектов.
Про то, что он у вас вызывает какое-то отвращение (по всей видимости, полностью иррациональное потому, что вы так и не объяснили, что именно вам в нем не нравится) вы тут уже не раз писали. Для того, чтоб провозглашать, что в чистых ФЯ нет изменяемых ссылок такой аргументации, правда, не достаточно. "Зараженную" область, кстати, вполне можно изолировать средствами ST.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Опять 25. Почему они не работающие? Они работают даже для ресурсов в отличии от.
Не работают. Это обеспечивается _руками_. Что будет, я объявлю свой враппер, где не буду переопределять никакие операторы, а деструкторе тупо грохну ресурс через метод навроде ::Close() ?
Опаньки — наверх уходит разрушеный ресурс. Что бы наверх ушел нормальный ресурс, надо поработать руками, быть в курсе, как чего будет использоваться, что бы подсунуть правильный враппер ресурс.
Re[28]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Встроенной ленивости и ленивых списков естественно нет. Их нет не потому что C++ не поддерживает ФП
Ну да, логичнее было бы сказать, что C++ не поддерживает ФП потому, что их (в числе прочего, более важного) там нет.
EP>а потому что используются более эффективные техники (писать ФП ради самого ФП — нет смысла. есть смысл применять ФП там, где необходимы его полезные свойства).
Ну вот пусть программист решит, где применение ФП себя оправдывает, а где нет. В этом и заключается основная разница между высокоуровневым языком и низкоуровневым. Высокоуровневый язык предоставляет инструментарий для написания высокоуровневого кода, который обычно небесплатен даже в случае его неиспользования, имплементации такого языка стараются оптимизировать именно применение таких средств, сделать производительность высокоуровневого кода более-менее приемлемой. Низкоуровневый язык сначала не предоставляет большинство инструментов с обоснованием, что они небесплатны в случае неиспользования, а потом поддерживает такой подход: высокоуровневый код, даже когда он возможен тормозной, но делать с этим что-то бессмысленно: если нужна производительность — нужно низкоуровневый код писать.
Во втором подходе нет ничего плохого, он зачастую оправдан. Просто не нужно называть низкоуровневые языки высокоуровневыми. Также нет ничего плохого в отсутствии поддержки ФП, если ее себе позволить нельзя — проблема в том, когда отсутствие поодержки ФП называют поддержкой ФП.
Если вы утверждаете, что поддержка ФП в языке есть, то аргументы вроде "писать ФП ради самого ФП — нет смысла" и "вместо ФП можно использовать более эффективные техники" невалидные. Они пришлись бы к месту, если бы вы доказывали его ненужность, но доказанная ненужность ФП опять таки не означает доказанного наличия ФП там, где его нет.
EP>Да и вообще — ленивость не во всех функциональных языках есть.
Какая-то поддержка ленивости как раз почти во всех ФЯ есть, выбор дизайнера языка там обычно между "ленивость по умолчанию" и "аннотации ленивости". Хотя, о чем говорить, второй вариант сильно мотивирует разработчика имплементации сделать реализацию ленивости "для галочки", убогую в техническом смысле.
EP>Соответственно понадобится boilerplate для их определения: Lazy<T>, LazyList<T>, каррированные cons, zipWith, etc. EP>Пример выше запишется вот так: EP>
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Нет, я о том, что этот "идиоматичный" пример тормозит даже со специальным runtime'ом. Например на ровном месте вводятся межпоточная синхронизации и медленные списки.
Тормозит по сравнению с чем? Вот когда предоставите для сравнения control-structure для связывания комбинаторов с комбинаторами с аналогичной функциональностью (поддержка раннего завершения, циклов, автомемоизации, потокобезопасность и т.д.) тогда и сравним. Сразу говорю, что заявляемая ненужность комбинирования комбинаторов равноценной заменой для такого средства не является.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>В начале были какие-то непонятности насчёт Хаскеля в этой области (т.к. он позволяет и то и то, только не одновременно), но потом мы пришли к выводу, что в нём всё аналогично (правда не два крайних положения, а есть ещё и промежуточные), т.е. никаких чудес, как и в C++. K>Непонятно, в каком смысле это аналогично C++ если там нет даже второго крайнего положения, не говоря уже о промежуточных, а есть только одно.
Второе крайнее положение есть — type-erasure, но оно достигается специальным кодом, а не компилятором.
Например можно сделать так:
template<typename F>
int foo(F f)
{
return f(1.1);
}
а можно так:
int bar(std::function<int(double)> f)
{
return f(1.1);
}
Оба варианта работают с "callable" типа int(double), без всякого наследоавния. Но в первом случае код шаблона должен быть виден в месте использования (хотя конкретные специализации можно компилировать отдельно), а во втором — раздельная компиляция.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>А как контролируется зоопарк расширений? Через reference implementation?
Да.
EP>Как они помогут в примере выше? Запретив использование такого замыкания?
Да.
EP>Это не интересно.
Конечно не интересно. У вас же вся аргументация о том, что плюсолямбды UFP не решают строится так:
1) Да у вас самих ничего не решается! Уже на этом этапе не понятно, как (не)поддержка UFP в плюсах зависит от того, что где-то там негров линчуют, ну да ладно.
2) Обосновывается неподдержка закрыванием файла с использованием средства, которое как раз для этого и предназначено (решение проблемы prompt finalization). Полностью игнорируется то, что без использования этого средства (using, брекеты и т.д.) доступность файла гарантируется, примерно как и доступность объекта, но несколько слабее. По независимым от ГЦ причинам. Например потому, что у объекта нет метода "освободить память", а метод "закрыть файл" наоборот есть, как и у его плюсового аналога. Т.е. гарантия доступности точно не хуже плюсовой.
3) Подразумевается, но не говориться (и даже явно отрицается), что претензия к prompt finalization. Действительно, такой гарантии нет ни для освобождения памяти, ни для закрытия файла. Первое считается приемлемым, а для второго есть другие средства (using, брекеты, регионы etc.), которые не поддерживают UFP (потому что гарантия на доступность не сочетается с гарантией на неотложное освобождение).
При этом пример, который предлагается повторить, демонстрирует систему, которая не гарантирует ни доступность, ни неотложенную финализацию. Первое потому, что UFP не решена. Второе потому, что возвращая откуда-то замыкание, вы делегируете ответственность за время жизни "пользователю" функции, который может продлевать время ее жизни неограниченно. Естественно при разработке систем дающих гарантии на prompt finalization с такой лазейкой будут наоборот бороться.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну покажи как ты решаешь данную задачу, если у тебя допустим есть такая функция. )
Так и решается: функции вида Monad<A> F(B b) лифтятся до Monad<A> F(Monad<B> b) при помощи bind, а функции вида A G(B b) лифтятся до Monad<A> G(Monad<B>) в два приёма: сначала строится функция Monad<A> G'(B b) при помощи unit, а уже потом bind.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Что мешает использовать подобную архитектуру для C++/D?
Ничего. Но когда вы используете "подобную архитектуру" для C++/D, вы получите интерпретатор Erlang на C++/D. В рамках языка добиться тех же успехов не выйдет. Мы как-то уже обсуждали эту тему; оказалось, что написать "Эрланг.Net" невозможно — не тот рантайм.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Кроме того, есть всякие разные вычисления, где, казалось бы, нужен перформанс, перформанс, перформанс, о оказывается все не так просто I>http://www.adass.org/adass/proceedings/adass99/O3-02/
Ты читал что там написано?
Scripting languages have become a powerful tool for the construction of flexible scientific software because they provide scientists with an interpreted programming environment, can be easily interfaced with existing software written in C, C++, and Fortran, and can serve as a framework for modular software construction.
В таком контексте я и сам Python использую — библиотека на C++ вызывается из Python'а, в котором только всякий обвес. C++ API можно автоматически warp'ать через SWIG.
>>Ну так приложения разные бывают, и естественно для разных приложений подходят разные языки. Где-то нужно по максимуму использовать потенциал железа, а где-то достаточно переложить пару байтиков из одного места в другое. Где-то дешевле добавить сто машин, где-то дешевле немного подумать I>Есть одно правило — дешевле, проще, быстрее сделать корректное медленное быстрым, чем некорректное корректным.
Ты утверждаешь что это правило работает всегда?
http://stackoverflow.com/a/145559/1762344
"The going word at Facebook is that 'reasonably written C++ code just runs fast,' which underscores the enormous effort spent at optimizing PHP and Java code. Paradoxically, C++ code is more difficult to write than in other languages, but efficient code is a lot easier [to write in C++ than in other languages]."
– Herb Sutter at //build/, quoting Andrei Alexandrescu
I>>>>>Это инфраструктуру без подобного языка заюзать невозможно, в принципе. EP>>>>Что мешает использовать подобную архитектуру для C++/D? I>>>Человеческий фактор, это очевидно. Нужно что бы язык страховал от большинства ошибок или позволял забесплатно и быстро найти их. В С++ ни того, ни другого нет. EP>>От таких именно ошибок гарантированно страхует Erlang? (и от чего нельзя застраховаться в C++/D теми или иными спосабами) I>Ошибки с указателями,
Предупреждаются правильной инфраструктурой.
I>ошибки с изменением состояния,
Какое состояние, глобальное?
I>корректное взаимодействие и тд и тд.
Какой взаимодействие? Где? Сделай те же акторы или csp, и будет тебе корректное взаимодействие
I>>>Ты говорил про ФП на задворках империи. Это, внезапно, оказалось давно не так даже в С++. EP>>Не просто ФП, а именно чистый ФП. I>Абсолютно чистого ФП в природе пока что нет, так что всё в порядке.
Что ты конкретно имеешь ввиду? unsafePerformIO, или что-то более фундаментальное?
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Отлично подходит. Вы, конечно, можете выдумать какое-то специальное убогое ФП, принципам которого такая контролируемая мутабельность не соответствует, а потом его критиковать, но к реальности это никакого отношения не имеет.
Речь не про убогое ФП, а про чистый код. Да, я помню, что вы считаете код внутри монад равноправным обычному коду в Хаскеле. Но на мой взгляд это совсем не так. И не только на мой (могу привести цитаты из хороших книг по Хаскелю).
K>Ну вот ленивость — это "неявная, скрытая" мутабельность, что продемонстрировано по соседству.
Не, это не то совсем. Вот хорошая скрытая мутабельность реализуется например при превращение рекурсии в цикл.
K>Конкретный пример — это код. K>Я же говорю, оптимизации, которые устраняют промежуточные массивы, списки и т.д. в комбинации функций, каждая из которых по по отдельности копирует, а не меняет по месту существуют и вполне работают. Как и все оптимизации, работают они не всегда, но объем копирования существенно сокращают. Т.е. компилятор оптимизирующий код вида: K>... K>существует. Понятно, что без таких оптимизаций было бы затруднительно комбинировать комбинаторы более-менее безнаказанно.
Ну ок, пускай будет код. Мне интересно, в коде типа такого
f1 True x=map(+1) x
f1 False x=x
f2 True x=map(+2) x
f2 False x=x
f3 True x=map(+3) x
f3 False x=x
f o1 o2 o3 x=f1 o1 $ f2 o2 $ f3 o3 x
main = print (f True True True [1, 10, 100, 1000])
сколько будет произведено выделений памяти? В C++ аналоге этого кода будет ровно 0 выделений памяти.
Это такая моделька той самой фильтрации видео. Естественно подразумевается, что булевы значения вводятся пользователем (а не известны на время компиляции), вместо map(+1) что-то сложное, а список у нас не из 4 элементов, а из пары миллионов.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Проблема с ФП в том, что циклические ссылки это норма. Это поначалу просто убивает мозг. EP>>Покажи пример циклической ссылки при использовании полностью immutable структур, и eager evaluation. I>А при чем здесь "полностью immutable" ? Функциональщина это отделение сайдэффектов в отдельную коробочку, а не когда всё абсолютно иммутабельное. Если всё абсолютно иммутабельное, то надо как то обеспечить бесконечную память.
Например есть иммутабельная структура данных типа rope — где там взяться циклам?
I>>>Итого — если делать "как в С++" то надо бороться с циклическими ссылками и желательно что бы эти циклические ссылки искал компилятор, а вот компилятор этого как раз и не умеет. То есть, в итоге пришли к ручному управлению, когда, казалось бы, нужна была автоматизация. Все чего добились — ручная неявная работа с ресурсами. EP>>Да не надо "как в С++" — покажи хоть какое-то автоматическое решение этого варианта UFP. I>C UFP всё в порядке — передача лямбды наверх не разрушает связь с экземпляром и здесь не надо ничего автоматизировать, всё и так работает автоматически.
Это демагогия, с тем же успехом можно сказать что [&] решает UFP — сама ссылка-то жива, это просто объект уже уничтожен. Толку-то от мёртвого ресурса?
I>Если ты про управление ресурсами, а не UFP, то можешь заметить, я пишу о том, что ни там, ни там нет автоматического управления. В обоих случаях ручное управление, только вызов освобождения в одном случае делается явно, в другом неявно. То есть, разница только в местах, где ты раскладываешь подсказки компилятору что бы он вовремя вызвал нужный метод как ::close, .Dispose или delete .
В случае C++ — достаточно указать что использовать при захвате, в остальных N местах компилятор либо сам всё расставит, либо выдаст error.
В C# — нужно расставлять во всех N местах подсказки руками, причём происходит транзитивное заражение, таких мест много, и далеко не ко всем есть доступ.
То есть разница существенная: O(1) vs O(N)
I>Автоматическое управление, это использование обычных классов, безо всяких оберток, врапперов, смартпоинтеров и тд и тд и тд, и рантайм сам освобождает ресурсы, примерно как GC обходится с памятью. Вот это автоматическое, а то о чем ты говоришь это варианты ручного.
Да называй как хочешь. Только это "ручное" позволяет упростить код с O(N) до O(1)
I>>>В С++ придется следить за циклическими ссылками, приседать, обрезать и тд и тд и тд и всё это руками, но ресурсы будут освобождаться неявно. EP>>Нет, не придётся следить за циклическими ссылками — представь что в этом примере их нет (да и вообще в C++ они редко встречаются). I>Как минимум придется руками обеспечивать разделяемое владение.
"Руками" это добавить make_shared? Беда.
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>То, что он нетипизирован (точнее, опционально типизирован) — это объективная реальность, тут от согласия ничего не зависит.
Исходные коды, из которых генерируется бинарный код, полностью типизированы. А то, что копилятор не обращает внимания на куски исходников, не используемые для генерации бинарного кода, никак не снижает уровень типизации.
K>Почему нельзя? Можно достигать высокие степени "раздельности" с помощью линктайм кодогенерации или AOT/JIT-компилятора, например.
Ну так это же опять не компиляция в исполняемый код (как и в том случае в Хаскелем при соответствующей оптимизации), а просто некое переформатирование исходников. )))
K>Тем не менее, раздельность компиляции и типизированность — вообще ортогональные понятия. Параметрический полиморфизм и параметризованные модули могут (и являются в ряде языков) генеративными, а не аппликативными, и тем не менее полностью типизированы. Существует также достаточно близкий родственник плюсовых шаблонов — F#-ные инлайн-функции, которые также полностью типизированы.
Что-то вы всё время придумываете некоторые мысли за меня и потом успешно с ними боретесь. ))) Я же чётко противопоставлял скорость обобщённого кода и раздельность компиляции, а не типизированность и раздельность компиляции.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Кроме того, есть всякие разные вычисления, где, казалось бы, нужен перформанс, перформанс, перформанс, о оказывается все не так просто I>>http://www.adass.org/adass/proceedings/adass99/O3-02/
EP>Ты читал что там написано? EP>
EP>Scripting languages have become a powerful tool for the construction of flexible scientific software because they provide scientists with an interpreted programming environment, can be easily interfaced with existing software written in C, C++, and Fortran, and can serve as a framework for modular software construction.
В таком контексте я и сам Python использую — библиотека на C++ вызывается из Python'а, в котором только всякий обвес. C++ API можно автоматически warp'ать через SWIG.
И что тебя смущает ? Посмотри какие либы используются для научных вычислений. Там довольно часто код пишется дольше чем работает.
I>>Есть одно правило — дешевле, проще, быстрее сделать корректное медленное быстрым, чем некорректное корректным.
EP>Ты утверждаешь что это правило работает всегда? EP>
EP>http://stackoverflow.com/a/145559/1762344
EP>"The going word at Facebook is that 'reasonably written C++ code just runs fast,' which underscores the enormous effort spent at optimizing PHP and Java code. Paradoxically, C++ code is more difficult to write than in other languages, but efficient code is a lot easier [to write in C++ than in other languages]."
EP> – Herb Sutter at //build/, quoting Andrei Alexandrescu
Осталось всего ничего — найти второй фейсбук, писаный на С++ и сравнить. Я вот сильно сомневаюсь, что окажется экономически целесообразно заниматься таким делом. Раньше солнце погаснет, чем подобный проект появится.
I>>Ошибки с указателями,
EP>Предупреждаются правильной инфраструктурой.
Правильная инфраструтукра это такая, в которую глянув на минуту можно понять все подряд. С++ здесь уже сливает.
Я например на С++ писал в продакшн в общей сумме где то 6 лет. На питоне — меньше года. На С++ я не писал всерьез в продакшн с 2007го, на питоне — с 2003го. При этом Питон я до сих пор читаю как книгу, а С++ только ту часть, что без шаблонов, хотя в свое время всякие подобия буста и "александреску стайл" были моей любимой областью.
I>>ошибки с изменением состояния,
EP>Какое состояние, глобальное?
Любое.
I>>корректное взаимодействие и тд и тд.
EP>Какой взаимодействие? Где? Сделай те же акторы или csp, и будет тебе корректное взаимодействие
И в итоге, все суммировав, получится в лучшем случае как-бэ-функциональный-дсл, из которого будут торчать уши в виде указателей, смартпоинтеров, конские темплейты, простыни операторов, счетчиков ссылок и тд и тд и тд.
Вот смотри boost.phoenix или boost.spirit — будет такой же мрак. Кроме того, для корректного взаимодейтсвия в общем случае придется изобрести GC. Гугл со своим движком браузера зашел в тупик и капитулировал — щас пилит GC для плюсов.
I>>Абсолютно чистого ФП в природе пока что нет, так что всё в порядке.
EP>Что ты конкретно имеешь ввиду? unsafePerformIO, или что-то более фундаментальное?
Разумеется. Такие методы нарушают чистоту хаскеля, так что, по честному, его нельзя назвать чистым Все языки они хотя бы чуточку грязные Из за того, что память конечна.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
EP>>Что мешает использовать подобную архитектуру для C++/D? S>Ничего. Но когда вы используете "подобную архитектуру" для C++/D, вы получите интерпретатор Erlang на C++/D. В рамках языка добиться тех же успехов не выйдет.
Подробнее.
Основа для зелёных потоков есть и там и там — в C++ stackful coroutine, в D — fiber. Нужна инфраструктура в виде библиотек/фреймворков. Но это всё-таки нельзя назвать интерпретатором.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ikemefula, Вы писали:
I>>>>Проблема с ФП в том, что циклические ссылки это норма. Это поначалу просто убивает мозг. EP>>>Покажи пример циклической ссылки при использовании полностью immutable структур, и eager evaluation. I>>А при чем здесь "полностью immutable" ? Функциональщина это отделение сайдэффектов в отдельную коробочку, а не когда всё абсолютно иммутабельное. Если всё абсолютно иммутабельное, то надо как то обеспечить бесконечную память.
EP>Например есть иммутабельная структура данных типа rope — где там взяться циклам?
У меня ощущение, что ты давно перестал читать Извини, я не могу сделать это за тебя.
I>>C UFP всё в порядке — передача лямбды наверх не разрушает связь с экземпляром и здесь не надо ничего автоматизировать, всё и так работает автоматически.
EP>Это демагогия, с тем же успехом можно сказать что [&] решает UFP — сама ссылка-то жива, это просто объект уже уничтожен. Толку-то от мёртвого ресурса?
Никакого, но с UFP всё в порядке.
I>>Если ты про управление ресурсами, а не UFP, то можешь заметить, я пишу о том, что ни там, ни там нет автоматического управления. В обоих случаях ручное управление, только вызов освобождения в одном случае делается явно, в другом неявно. То есть, разница только в местах, где ты раскладываешь подсказки компилятору что бы он вовремя вызвал нужный метод как ::close, .Dispose или delete .
EP>В случае C++ — достаточно указать что использовать при захвате, в остальных N местах компилятор либо сам всё расставит, либо выдаст error.
Не надо никаких N мест
EP>В C# — нужно расставлять во всех N местах подсказки руками, причём происходит транзитивное заражение, таких мест много, и далеко не ко всем есть доступ.
Хватает одного места.
EP>То есть разница существенная: O(1) vs O(N)
Покажи где ты собираешься O(N) получить, если отбросить случай намеренного дублирования кода.
I>>Автоматическое управление, это использование обычных классов, безо всяких оберток, врапперов, смартпоинтеров и тд и тд и тд, и рантайм сам освобождает ресурсы, примерно как GC обходится с памятью. Вот это автоматическое, а то о чем ты говоришь это варианты ручного.
EP>Да называй как хочешь. Только это "ручное" позволяет упростить код с O(N) до O(1)
У меня в коде нет никаких O(N)
I>>Как минимум придется руками обеспечивать разделяемое владение.
EP>"Руками" это добавить make_shared? Беда.
Не важно. С многопоточностью, асинхронщиной, паралеллизмом и тд и тд придется изобретать всевозможные схемы управления счетчиками ссылок.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Код с IO/ST как раз чистый, для того, чтоб он был таковым они и нужны. Чтоб сделать из них "нечистый" нужно воспользоваться каким-нибудь unsafePerformIO.
Он может стать чистым где-то далеко выше, при применение чего-то типа runSt для отрезания данной области от остального кода. А так это не нормальный код на хаскеле, а императивный монадный подъязык.
Ну так что, покажете как выглядит мутабельная ссылка в чистом хаскеле (а не императивном монадном подъязыке) или же признаем что такого просто нет в чистом ФП? )
K>Во-первых, не обходится. Во вторых, то что вы называете "оптимизированным копированием" в языках с решенной UFP и в C++ существенно отличаются.
Реализации различные, а результат один.
K>А если мы возвращаем пару или вовсе список замыканий?
Да без проблем. Какая разница сколько объектов перемещать? )
K>Доступность не гарантирует, тормозит в случае подсчета ссылок, циклы не поддерживает, заставляет постоянно выбирать "на ровном месте". Это все не проблемы разве?
Про циклы не понял о чём вообще речь.
Насчёт выбора и т.п... Ну C++ как бы не самый простой язык и вообще не очень ориентирован на новичков. Однако думаю что уж не Хаскелю что-то говорить на эту тему — в нём не меньше всяческих нюансов, просто они совсем из другой области.
K>Видим полностью рабочий код, который перечисленных выше недостатков не имеет.
Кстати, сам то код функции с ссылкой выглядит не так уж и страшно. Только вот это уже не та функция (по сравнению с C++ аналогом) — в ней мы имеем дело уже не int'ом, а с некой другой сущностью, не имеющей его свойств (в отличие от int& в большинстве императивных языков). И вследствие этого, код использующий данную функцию будет уже выглядеть совсем адски.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Кроме того, есть всякие разные вычисления, где, казалось бы, нужен перформанс, перформанс, перформанс, о оказывается все не так просто I>>>http://www.adass.org/adass/proceedings/adass99/O3-02/ EP>>Ты читал что там написано? EP>>
EP>>Scripting languages have become a powerful tool for the construction of flexible scientific software because they provide scientists with an interpreted programming environment, can be easily interfaced with existing software written in C, C++, and Fortran, and can serve as a framework for modular software construction.
В таком контексте я и сам Python использую — библиотека на C++ вызывается из Python'а, в котором только всякий обвес. C++ API можно автоматически warp'ать через SWIG. I>И что тебя смущает ?
Привёл ссылку где рассказывается как Python может вызывать C/C++/Fortran библиотеки. Что сказать-то хотел?
I>Посмотри какие либы используются для научных вычислений. Там довольно часто код пишется дольше чем работает.
Какой-нибудь FEM (которых только в РФ штуки 4 из известных) — требует много вычислительных ресурсов.
Причём аппетит приходит во время еды — более мелкая сетка, разные сочетания нагрузок, нелинейные материалы, динамика, mesh optimization, progressive collapse analysis и т.д и т.п. При добавлении какого-либо нового свойства — время расчёта увеличивается на порядок, а то и несколько.
I>>>корректное взаимодействие и тд и тд. EP>>Какой взаимодействие? Где? Сделай те же акторы или csp, и будет тебе корректное взаимодействие I>И в итоге, все суммировав, получится в лучшем случае как-бэ-функциональный-дсл,
Да нет никакого DSL — просто библиотека, в худшем случае — framework.
I>>>Абсолютно чистого ФП в природе пока что нет, так что всё в порядке. EP>>Что ты конкретно имеешь ввиду? unsafePerformIO, или что-то более фундаментальное? I>Разумеется. Такие методы нарушают чистоту хаскеля, так что, по честному, его нельзя назвать чистым
unsafePerformIO можно запретить, вся связь с внешним миром, в том числе с библиотеками, будет идти строго через монаду IO — получится действительно чистое ФП. Разница для разработчика будет минимальной.
Так вот, мой тезис в том, что такое чистое ФП — плохо мэппится существующее железо, а не в том что элементы ФП не нужны.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Так и решается: функции вида Monad<A> F(B b) лифтятся до Monad<A> F(Monad<B> b) при помощи bind, а функции вида A G(B b) лифтятся до Monad<A> G(Monad<B>) в два приёма: сначала строится функция Monad<A> G'(B b) при помощи unit, а уже потом bind.
Не забываем, что задачка у нас: "добавить optional в старый код, вообще не меняя его". Т.е. разговор вообще то был не о том как делать собственно преобразование (это думаю всем давно очевидно), а как его автоматически добавить в код.
P.S. Кстати, bind осуществляет не лифтинг (создание новой функции), а непосредственно применяет функцию к монаде. Хотя это на суть дела не влияет.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Ничего. Но когда вы используете "подобную архитектуру" для C++/D, вы получите интерпретатор Erlang на C++/D. В рамках языка добиться тех же успехов не выйдет. Мы как-то уже обсуждали эту тему; оказалось, что написать "Эрланг.Net" невозможно — не тот рантайм.
А что здесь подразумевается под "подобной архитектурой"? Модель акторов или же вообще весь Эрланг с его прологоподобным синтаксисом, хитрой распределённой средой исполнения и ещё кучей всяких нюансов? Если первое, то это уже давно без проблем делается соответствующими библиотеками. Ну а если второе, то действительно получится что-то вроде написания интерпретатора Erlang'а и такое нафиг не нужно.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Например есть иммутабельная структура данных типа rope — где там взяться циклам? I>У меня ощущение, что ты давно перестал читать Извини, я не могу сделать это за тебя.
На вопрос ответь.
I>>>C UFP всё в порядке — передача лямбды наверх не разрушает связь с экземпляром и здесь не надо ничего автоматизировать, всё и так работает автоматически. EP>>Это демагогия, с тем же успехом можно сказать что [&] решает UFP — сама ссылка-то жива, это просто объект уже уничтожен. Толку-то от мёртвого ресурса? I>Никакого, но с UFP всё в порядке.
Отличный подход. "С UFP всё в порядке, поэтому исходную задачу решать не будем"
EP>>То есть разница существенная: O(1) vs O(N) I>Покажи где ты собираешься O(N) получить, если отбросить случай намеренного дублирования кода.
Было:
class Foo
{
// ...
};
Foo используется в N местах (включая транзитивные зависимости), в том числе у клиентов, к коду которых доступа нет.
Стало:
class Foo
{
Resource deficit;
// ...
};
Удачной O(N) охоты на IDisposable
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Например есть иммутабельная структура данных типа rope — где там взяться циклам? I>>У меня ощущение, что ты давно перестал читать Извини, я не могу сделать это за тебя.
EP>На вопрос ответь.
Отвечаю — "полностью immutable" к обсуждаемому вопросу никаким боком не относятся. То есть, вообще.
EP>>>Это демагогия, с тем же успехом можно сказать что [&] решает UFP — сама ссылка-то жива, это просто объект уже уничтожен. Толку-то от мёртвого ресурса? I>>Никакого, но с UFP всё в порядке.
EP>Отличный подход. "С UFP всё в порядке, поэтому исходную задачу решать не будем"
Скажи пожалуйста, а бросание исключения из лямбды тоже UFP нарушает ?
I>>Покажи где ты собираешься O(N) получить, если отбросить случай намеренного дублирования кода.
EP>Было: EP>
EP>class Foo
EP>{
EP> // ...
EP>};
EP>
Foo используется в N местах (включая транзитивные зависимости), в том числе у клиентов, к коду которых доступа нет.
То есть, под O(N) ты имеешь ввиду аггрегирование, которое я уже упоминал.
Вероятно, у тебя есть чудесный способ узнать что ресурс корректно захватывается, освобождается и разрушается во всех N случаях ? Покажи этот чудесный способ.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>И что тебя смущает ?
EP>Привёл ссылку где рассказывается как Python может вызывать C/C++/Fortran библиотеки. Что сказать-то хотел?
Спасибо, капитан, а я то думал, что Питон в 100% случаев именно так и работает, а оказывается, так оно и есть.
I>>Посмотри какие либы используются для научных вычислений. Там довольно часто код пишется дольше чем работает.
EP>Какой-нибудь FEM (которых только в РФ штуки 4 из известных) — требует много вычислительных ресурсов. EP>Причём аппетит приходит во время еды — более мелкая сетка, разные сочетания нагрузок, нелинейные материалы, динамика, mesh optimization, progressive collapse analysis и т.д и т.п. При добавлении какого-либо нового свойства — время расчёта увеличивается на порядок, а то и несколько.
Я немного не понимаю, для чего здесь С++. Это чисто математическая задача — накидать решение хоть в чем угодно, а потом сгенерировать тупой максимально быстрый код.
I>>И в итоге, все суммировав, получится в лучшем случае как-бэ-функциональный-дсл,
EP>Да нет никакого DSL — просто библиотека, в худшем случае — framework.
То есть, еще хуже, надо будет вникать во все детали реализации. C DSL хотя бы можно общий принцип из книги прочесть и налабать враз хоть сотню решений.
EP>unsafePerformIO можно запретить, вся связь с внешним миром, в том числе с библиотеками, будет идти строго через монаду IO — получится действительно чистое ФП. Разница для разработчика будет минимальной. EP>Так вот, мой тезис в том, что такое чистое ФП — плохо мэппится существующее железо, а не в том что элементы ФП не нужны.
Такое чистое ФП нужно там, где архитектура вычислителя другая. Если ты хочешь гонять код ровно в одном ядре, то конечно императивный язык здесь заруливается всех в минуса, я про то уже писал около десяти раз за последние полгода.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
[...] EP>>Соответственно понадобится boilerplate для их определения: Lazy<T>, LazyList<T>, каррированные cons, zipWith, etc. EP>>Пример выше запишется вот так: EP>>
Где * это композиция функций, а <ap> — это соответствующий named operator. K>Когда я говорил "попробуйте написать" — имелся в виду работающий код, а не псевдокод.
Так это и есть работающий код:
gentoo fibs # tail -n 6 main.cpp && clang++ main.cpp -std=c++1y -stdlib=libc++ && echo _____ && ./a.out
int main()
{
auto fibs = fix(cons(0) * cons(1) * (zipWith(sum) <ap> tail));
auto x = fibs <at> 101;
cout << x << endl;
}
_____
573147844013817084101
Вот только смысла так писать нет — итеративная версия будет и проще и быстрее.
Но если нужна действительно быстрая версия, то посыпание синтаксическим сахром ничем не поможет — нужно использовать подходящий алгоритм, типа ((1,1),(1,0))^n*(1,0).
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали: EP>Подробнее. EP>Основа для зелёных потоков есть и там и там — в C++ stackful coroutine, в D — fiber. Нужна инфраструктура в виде библиотек/фреймворков. Но это всё-таки нельзя назвать интерпретатором.
Насколько я помню, всё упиралось в модель памяти. Возможно, всё это обходимо в C++ и/или D.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Не забываем, что задачка у нас: "добавить optional в старый код, вообще не меняя его". Т.е. разговор вообще то был не о том как делать собственно преобразование (это думаю всем давно очевидно), а как его автоматически добавить в код.
Так и есть. Всё отличие "нового" кода от "старого" — это замена части аргументов с X на Monad<X>. А дальше начинаем замены.
Что смущает-то? Если брать "обычный" процесс разрешения имён из языка вроде C++, то всё работает почти как обычно. Вот мы видим обращение к somefunction(expression), где expression имеет статический тип Monad<X>. Если у нас в scope есть подходящая функция с таким именем, принимающая Monad<X>, то всё в порядке. Если нет — начинаем искать функцию с таким же именем, принимающую X. Если нашли — то смотрим на тип результата. Если он уже Monad<Y>, то заменяем somefunction(expression) на bind(somefunction)(expression). Если тип результата Y, то заменяем somefunction на bind(unit(somefunction))(expression).
После этого процесс вывода типов продолжается дальше как обычно.
Для многоаргументных функций всё это несколько осложняется, но в целом принцип точно такой же.
_>P.S. Кстати, bind осуществляет не лифтинг (создание новой функции), а непосредственно применяет функцию к монаде.
Странно. Мне казалось, что у неё сигнатура (в терминах C#) именно
Здравствуйте, alex_public, Вы писали: _>А что здесь подразумевается под "подобной архитектурой"? Модель акторов или же вообще весь Эрланг с его прологоподобным синтаксисом, хитрой распределённой средой исполнения и ещё кучей всяких нюансов? Если первое, то это уже давно без проблем делается соответствующими библиотеками. Ну а если второе, то действительно получится что-то вроде написания интерпретатора Erlang'а и такое нафиг не нужно.
Главное — его модель многозадачности, где помимо green threads есть передача владения, и в итоге получаем адскую скорость разбора пакетов, офигенные гарантии изоляции (т.е. поломанный актор не может ни попортить память других, ни отожрать 100% CPU), плюс горячую замену кода.
Сделать что-то отдалённо похожее — можно, но либо ценой перформанса, либо ценой надёжности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Исходные коды, из которых генерируется бинарный код, полностью типизированы. А то, что копилятор не обращает внимания на куски исходников, не используемые для генерации бинарного кода, никак не снижает уровень типизации.
Оппонент намекает на то, что разработка библиотеки на таком языке — адски трудное занятие. Отсутствие типизации означает, что компилятор откладывает проверку кода не просто до "генерации бинарного кода", а до "генерации бинарного кода, которая происходит очень далеко в пространстве-времени от написания шаблонного кода". Наш гипотетический монадно-ориентированный компилятор мог бы (и должен был бы) прямо во время компиляции монады, скажем, optional сказать нам "вы неправильно описали монаду — у вас функция bind имеет неверный тип аргумента. Ваш optional — это функтор". Или "ваши определения unit и bind нарушают требования к монаде".
И всё это — до того, как мы попробуем привинтить этот optional к конкретному типу.
_>Ну так это же опять не компиляция в исполняемый код (как и в том случае в Хаскелем при соответствующей оптимизации), а просто некое переформатирование исходников. )))
Речь не о переформатировании исходников, а об объёме анализа, проводимого во время этого переформатирования.
_>Что-то вы всё время придумываете некоторые мысли за меня и потом успешно с ними боретесь. ))) Я же чётко противопоставлял скорость обобщённого кода и раздельность компиляции, а не типизированность и раздельность компиляции.
Как мы знаем из практики, скорость обобщённого кода и раздельность компиляции — это четыре разных человека. То, что бинарный код генериков в C# появляется только на целевой машине — ну так весь дотнет такой, всё отложено до джита. Так что скорость обобщённого кода — точно такая же, как и у обычного. А компиляция исходников гарантирует отсутствие ошибок в коде генерика.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я немного не понимаю, для чего здесь С++. Это чисто математическая задача — накидать решение хоть в чем угодно, а потом сгенерировать тупой максимально быстрый код.
Всё зависит от масштабов. Во многих случаях делают именно так, как ты описал. И для этого у учёных есть любимейший инструмент под названием Mathematica. Он позволяет с помощью символьных вычислений получить что-то типа конечной формулы, а потом автоматом сгенерировать из неё рабочий C код. Именно за эту возможностью многие отдают деньги за лицензию на Mathematica. Естественно профессиональный программист на C++ без проблем сделает код оптимальнее, чем Mathematica, но не приставишь же такого к каждому учёному. Конечно некоторые учёные могут ещё фортране что-то накидать, но там чаще всего мрак выходит.
Однако решение выше подходит для какого-нибудь учёного, считающего свою задачку на обычном лабораторном сервере. А если речь заходит об огромных кластерах или вообще суперкомпьютерах, то цена вопроса уже существенно возрастает. И тогда между учёными и компьютером всё же ставится команда программистов, которые чаще всего работают на C/C++.
Ну а питончик обычно вообще для других целей используют. Например для обработки данных и т.п. И в силу простоты языка, учёные тут частенько справляются своими силами.
I>Такое чистое ФП нужно там, где архитектура вычислителя другая. Если ты хочешь гонять код ровно в одном ядре, то конечно императивный язык здесь заруливается всех в минуса, я про то уже писал около десяти раз за последние полгода.
И на многих ядрах всё тоже самое. ) Причём не только в быстродействие, но и в удобстве. Вот например, знаешь ли ты более краткое средство перевода однопоточного кода вычисления некого цикла в многопоточный, чем openmp? ) А это по сути основной сценарий для использования многоядерных процессоров в числодробилках...
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Так и есть. Всё отличие "нового" кода от "старого" — это замена части аргументов с X на Monad<X>. А дальше начинаем замены. S>Что смущает-то? Если брать "обычный" процесс разрешения имён из языка вроде C++, то всё работает почти как обычно. Вот мы видим обращение к somefunction(expression), где expression имеет статический тип Monad<X>. Если у нас в scope есть подходящая функция с таким именем, принимающая Monad<X>, то всё в порядке. Если нет — начинаем искать функцию с таким же именем, принимающую X. Если нашли — то смотрим на тип результата. Если он уже Monad<Y>, то заменяем somefunction(expression) на bind(somefunction)(expression). Если тип результата Y, то заменяем somefunction на bind(unit(somefunction))(expression). S>После этого процесс вывода типов продолжается дальше как обычно. S>Для многоаргументных функций всё это несколько осложняется, но в целом принцип точно такой же.
Ну так а в каком языке подобное возможно? ) И если предположим возможно, то благодаря каким-то особым свойствам языка или благодаря особым свойствам монад? )
S>Странно. Мне казалось, что у неё сигнатура (в терминах C#) именно S>
Нет, bind возвращает Monad<B> и именно поэтому можно писать код вида monad>>=func1>>=func2>>=func3. И кстати как раз заменой подобного и является do сахар в Хаскеле, ну разве что он позволяет ещё вставить другие вызовы между элементами цепочки.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Главное — его модель многозадачности, где помимо green threads есть передача владения, и в итоге получаем адскую скорость разбора пакетов, офигенные гарантии изоляции (т.е. поломанный актор не может ни попортить память других, ни отожрать 100% CPU), плюс горячую замену кода. S>Сделать что-то отдалённо похожее — можно, но либо ценой перформанса, либо ценой надёжности.
Без проблем это всё делается на C++. Например вот http://www.theron-library.com/index.php?t=page&p=tour1 интересное решение. Ну т.е. конечно небольшая разница есть. В том смысле, что т.к. C++ позволяет иметь самый низкий уровень доступа, то при желание можно без проблем обмануть библиотеку и сломать модель. Но это если специально стараться (в Эрланге такое даже при этом не выйдет), а если следовать правилам библиотечки, то получается абсолютно такой же быстродействующий и надёжный код.
А вообще, модель акторов это такая простая вещь, что даже не обязательно использовать какие-то готовые библиотеки. Например, если нам не нужны всякие там планировщики и распределённые системы, то подобный код легко пишется просто в лоб, без введения специальных сущностей. Я частенько работаю даже с обычными std::thread в таком стиле.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Оппонент намекает на то, что разработка библиотеки на таком языке — адски трудное занятие. Отсутствие типизации означает, что компилятор откладывает проверку кода не просто до "генерации бинарного кода", а до "генерации бинарного кода, которая происходит очень далеко в пространстве-времени от написания шаблонного кода". Наш гипотетический монадно-ориентированный компилятор мог бы (и должен был бы) прямо во время компиляции монады, скажем, optional сказать нам "вы неправильно описали монаду — у вас функция bind имеет неверный тип аргумента. Ваш optional — это функтор". Или "ваши определения unit и bind нарушают требования к монаде". S>И всё это — до того, как мы попробуем привинтить этот optional к конкретному типу.
Так фокус в том, что многие шаблонные библиотеки C++ не компилируются вообще. Т.е. они поставляются только в виде набора заголовочных файлов и для них компилятор вообще никогда не запускается и даже теоретические не может быть запущен. Ну т.е. понятно, что авторы в реальности работают в какой-то своей тестовой программкой (и кстати в ней естественно есть инстанцирование, так что компилятор отрабатывает все ошибки в шаблоне на полную), но в саму библиотеку она не входит.
А так, весьма точное описание проблемы. Только вот называть её отсутствием типизации как-то глупо. Всё же код, используемый для компиляции, является жёстко типизированным. А здесь у нас просто проблема "отсутствия компиляции". Т.е. я нигде не отрицал существование вышеописанной сложности, но к типизации это отношения не имеет.
Кстати, на мой взгляд интересное решение для данной сложности может лежать не в области компилятора, а в области IDE. Что-то типа:
template<typename T> Test<T, typename enable_if<is_base_of<Parent, T>::value>::type>{
T t;
Test()
{
t.//и тут автодополнение выдаёт члены класса Parent
}
};
можно без проблем реализовать средствами IDE. Правда пока C++ IDE не до этого, им бы пока просто Boost распарсить конца. )))
S>Как мы знаем из практики, скорость обобщённого кода и раздельность компиляции — это четыре разных человека. То, что бинарный код генериков в C# появляется только на целевой машине — ну так весь дотнет такой, всё отложено до джита. Так что скорость обобщённого кода — точно такая же, как и у обычного. А компиляция исходников гарантирует отсутствие ошибок в коде генерика.
В C++ тоже скорость обобщённого кода и обычного одинаковы (и при этом больше C#) и точно также гарантировано отсутствие подобных ошибок в исполняемом файле. Единственное отличие/ограничение варианта C++ в том, что в нём невозможно скомпилировать обобщённый код сам по себе. Т.е. нет раздельной компиляции шаблонов и использующего их кода.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Такое чистое ФП нужно там, где архитектура вычислителя другая. Если ты хочешь гонять код ровно в одном ядре, то конечно императивный язык здесь заруливается всех в минуса, я про то уже писал около десяти раз за последние полгода.
_>И на многих ядрах всё тоже самое.
Нет, на нескольких ядрах уже слишком много издержек из за синхронизации. Дальше я скипнул — ты ведь не занимаешь суперкомпьютерами, правильно ?
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>Главное — его модель многозадачности, где помимо green threads есть передача владения, и в итоге получаем адскую скорость разбора пакетов, офигенные гарантии изоляции (т.е. поломанный актор не может ни попортить память других, ни отожрать 100% CPU), плюс горячую замену кода. S>>Сделать что-то отдалённо похожее — можно, но либо ценой перформанса, либо ценой надёжности.
_>Без проблем это всё делается на C++.
Если Адъ и Израиль это без проблем, то всё в порядке, можно согласиться. Щас вот закомые пилят решение для виртуализации на С++. Это такой трэш, не передать словамаи.
Единственный раз я видел "без проблем" это когда в команде сиплюсников не было ни одного разраба меньше 10 лет опыта. Я, правда, к тому времени решил отказаться от С++ насовсем, ибо таких команд всего пару штук в моем городе.
Да и вообще таких команд очень мало, их тупо не хватит на все проекты. Поэтому совершенно неинтересно читать, что там есть для С++.
И вот очень интересно читать, что есть для джавы, дотнета, питона, джаваскрипта, ибо таких разработчиков искать не нужно.
То есть, просто сиплюсника можно найти быстро. Сиплюсника который свободно владеет бустом и хотя бы многопоточностью, уже много сложнее. А сиплюсника который умеет и многопоточность, и распределнные вычисления, и асинхронное программирование и при этом успел прокачать и stl и буст, и кучу других либ надо искать днём с огнём.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, просто сиплюсника можно найти быстро. Сиплюсника который свободно владеет бустом и хотя бы многопоточностью, уже много сложнее. А сиплюсника который умеет и многопоточность, и распределнные вычисления, и асинхронное программирование и при этом успел прокачать и stl и буст, и кучу других либ надо искать днём с огнём.
К слову, аналогичного джависта, питонщика, дотнетчика искать относительно просто, естественно вместо stl и буста будут другие либы.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нет, на нескольких ядрах уже слишком много издержек из за синхронизации. Дальше я скипнул — ты ведь не занимаешь суперкомпьютерами, правильно ?
По бизнесу не занимаюсь. Но не плохо знаком с этой темой, т.к. их эксплуатируют в основном учёные для разных числодробилок, а у меня там много контактов. Так вот, в этой области решение mpi+openmp полностью накрывает весь спектр проблем связанных с распараллеливанием и в общем то это почти как негласный стандарт. Ну точнее так было до появления GPU — под них пришлось переделывать код руками на низком уровне, что было мучением в общем то. Поэтому недавнее появление Intel Xeon Phi прошло просто на ура — можно снова работать на относительно высоком уровне. )
Насчёт синхронизации... Ну покажи мне как ты предлагаешь распараллелить обработку массива на несколько ядер. Т.е. берём массив 1000000 элементов и надо допустим изменить каждый его элемент, возведя его в квадрат. Код для одного ядра что-то типа for(int i=0; i<size; i++) x[i]=x[i]*x[i]; С помощью openmp мы можем это распараллелить на все ядра процессора одной простейшей директивой. А как предлагаешь сделать ты и чтобы без всякой синхронизации? )
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Если Адъ и Израиль это без проблем, то всё в порядке, можно согласиться. Щас вот закомые пилят решение для виртуализации на С++. Это такой трэш, не передать словамаи.
С интересом посмотрю на решение этой задачи на другом языке...
I>Единственный раз я видел "без проблем" это когда в команде сиплюсников не было ни одного разраба меньше 10 лет опыта. Я, правда, к тому времени решил отказаться от С++ насовсем, ибо таких команд всего пару штук в моем городе.
I>Да и вообще таких команд очень мало, их тупо не хватит на все проекты. Поэтому совершенно неинтересно читать, что там есть для С++. I>И вот очень интересно читать, что есть для джавы, дотнета, питона, джаваскрипта, ибо таких разработчиков искать не нужно.
С этим не поспоришь. )
I>То есть, просто сиплюсника можно найти быстро. Сиплюсника который свободно владеет бустом и хотя бы многопоточностью, уже много сложнее. А сиплюсника который умеет и многопоточность, и распределнные вычисления, и асинхронное программирование и при этом успел прокачать и stl и буст, и кучу других либ надо искать днём с огнём.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Насчёт синхронизации... Ну покажи мне как ты предлагаешь распараллелить обработку массива на несколько ядер. Т.е. берём массив 1000000 элементов и надо допустим изменить каждый его элемент, возведя его в квадрат. Код для одного ядра что-то типа for(int i=0; i<size; i++) x[i]=x[i]*x[i]; С помощью openmp мы можем это распараллелить на все ядра процессора одной простейшей директивой. А как предлагаешь сделать ты и чтобы без всякой синхронизации? )
... а в киеве дядька. Ты всё еще продолжаешь насиловать фон Неймановскую архитектуру, а я говорю о принципиально иной архитектуре.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>... а в киеве дядька. Ты всё еще продолжаешь насиловать фон Неймановскую архитектуру, а я говорю о принципиально иной архитектуре.
Что за иная архитектура?
И откуда оно возьмётся в задачах числодробилок, если вот тот мой пример полностью соответствует реальной задаче учёных (массив — это некая физическая величина, заданная на решётке)?
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так а в каком языке подобное возможно? ) Подобное возможно в С#, в виде Lifted Operators для Nullable.
_>И если предположим возможно, то благодаря каким-то особым свойствам языка или благодаря особым свойствам монад? )
Благодаря особым свойствам монад. Монада определяется не только сигнатурой операций, но их семантикой (см. тж. монадные законы). Поэтому гипотетический компилятор будет иметь право сделать такие замены автоматически.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Без проблем это всё делается на C++. Например вот http://www.theron-library.com/index.php?t=page&p=tour1 интересное решение. Ну т.е. конечно небольшая разница есть. В том смысле, что т.к. C++ позволяет иметь самый низкий уровень доступа, то при желание можно без проблем обмануть библиотеку и сломать модель. Но это если специально стараться (в Эрланге такое даже при этом не выйдет), а если следовать правилам библиотечки, то получается абсолютно такой же быстродействующий и надёжный код.
К сожалению, нет никакого способа убедиться в том, что некоторый код "следует правилам библиотечки". Специально стараться никуда не нужно — я не представляю себе способа написать минимально безопасную библиотеку на С++. Потому что в языке нет никакого способа запретить штуки типа char*, которые могут указывать буквально куда угодно.
_>А вообще, модель акторов это такая простая вещь, что даже не обязательно использовать какие-то готовые библиотеки. Например, если нам не нужны всякие там планировщики и распределённые системы, то подобный код легко пишется просто в лоб, без введения специальных сущностей. Я частенько работаю даже с обычными std::thread в таком стиле.
Дело не в модели акторов, а в том, чтобы иметь гарантии. На всякий случай напомню, что безо всякой распределёнщины С++-ный проект для эриксоновского свитча так и не взлетел. Несмотря на то, что там не самые тупые девелоперы писали, уж наверное могли "легко написать просто в лоб". А потом пришёл Эрланг, и внезапно оказалось, что всё можно написать не только языком на форуме, и оно даже работает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так фокус в том, что многие шаблонные библиотеки C++ не компилируются вообще. Т.е. они поставляются только в виде набора заголовочных файлов и для них компилятор вообще никогда не запускается и даже теоретические не может быть запущен. Ну т.е. понятно, что авторы в реальности работают в какой-то своей тестовой программкой (и кстати в ней естественно есть инстанцирование, так что компилятор отрабатывает все ошибки в шаблоне на полную), но в саму библиотеку она не входит.
Вы так пишете, как будто это хорошо. Это, по факту, означает, что компилятор никак не помогает авторам таких библиотек.
Насчёт "отрабатывает все ошибки в шаблоне на полную" — это вы хорошо пошутили, я оценил.
Если взять среднего девелопера, то он сходу не сможет написать тестовую программу для, скажем, optional<T>. Вы вот, к примеру, не смогли.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Встроенной ленивости и ленивых списков естественно нет. Их нет не потому что C++ не поддерживает ФП K>Ну да, логичнее было бы сказать, что C++ не поддерживает ФП потому, что их (в числе прочего, более важного) там нет.
1. Нет встроенных ленивых списков, но они реализуются библиотечно То есть их нет, точно также как нет и встроенных в язык хэштаблиц — хотя std::unodered_map элементарно реализуется средствами самого языка.
2. Какого "прочего, более важного" нет?
EP>>а потому что используются более эффективные техники (писать ФП ради самого ФП — нет смысла. есть смысл применять ФП там, где необходимы его полезные свойства). K>Ну вот пусть программист решит, где применение ФП себя оправдывает, а где нет. В этом и заключается основная разница между высокоуровневым языком и низкоуровневым.
Разница между высокоуровневым языком и низкоуровневым это наличие ФП?
K>Высокоуровневый язык предоставляет инструментарий для написания высокоуровневого кода, который обычно небесплатен даже в случае его неиспользования,
"обычно небесплатен" — в том то и дело, что он никому не обязан быть "платным".
K>Если вы утверждаете, что поддержка ФП в языке есть, то аргументы вроде "писать ФП ради самого ФП — нет смысла" и "вместо ФП можно использовать более эффективные техники" невалидные. Они пришлись бы к месту, если бы вы доказывали его ненужность, но доказанная ненужность ФП опять таки не означает доказанного наличия ФП там, где его нет.
Я говорю что использовать ФП ВЕЗДЕ нет смысла, так как в ряде случаев есть более эффективные и зачастую более понятные техники. Использование ФП там где оно добавляет тормозов на ровном месте, затрудняет понимание и не даёт никаких преимуществ — это и есть "писать ФП ради самого ФП".
Каким образом вы решили что аргумент "писать ФП ради самого ФП — нет смысла" применим только при доказательстве ненужности всего ФП — для меня остаётся загадкой
Re[29]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Нет, я о том, что этот "идиоматичный" пример тормозит даже со специальным runtime'ом. Например на ровном месте вводятся межпоточная синхронизации и медленные списки. K>Тормозит по сравнению с чем?
Тормозит по сравнению с простейшей итеративной версией, которую можно объяснить даже ребёнку.
K>Вот когда предоставите для сравнения control-structure для связывания комбинаторов с комбинаторами с аналогичной функциональностью (поддержка раннего завершения, циклов, автомемоизации, потокобезопасность и т.д.) тогда и сравним.
Зачем всё это при вычислении простейших задач типа чисел Фибоначчи?
K>Сразу говорю, что заявляемая ненужность комбинирования комбинаторов равноценной заменой для такого средства не является.
А зачем замена? Ваш пример с числами Фибоначчи с точностью до минимальных синтаксических различий (скобки вместо $, * вместо . , <ap> вместо <*> и т.п.) переписывается на C++:
Здравствуйте, alex_public, Вы писали:
I>>... а в киеве дядька. Ты всё еще продолжаешь насиловать фон Неймановскую архитектуру, а я говорю о принципиально иной архитектуре.
_>Что за иная архитектура?
Управление от потока данных.
_>И откуда оно возьмётся в задачах числодробилок, если вот тот мой пример полностью соответствует реальной задаче учёных (массив — это некая физическая величина, заданная на решётке)?
Не пойму логики. Из существования задачи решаемой через массивом как то следует невозможность использования другой архитектуры ?
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Если Адъ и Израиль это без проблем, то всё в порядке, можно согласиться. Щас вот закомые пилят решение для виртуализации на С++. Это такой трэш, не передать словамаи.
_>С интересом посмотрю на решение этой задачи на другом языке...
Я знаю два случая, где почти аналогичные проекты пилятся один на джаве, второй на дотнете
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Конечно не интересно. У вас же вся аргументация о том, что плюсолямбды UFP не решают строится так: K>1) Да у вас самих ничего не решается! Уже на этом этапе не понятно, как (не)поддержка UFP в плюсах зависит от того, что где-то там негров линчуют, ну да ладно. K>2) Обосновывается неподдержка закрыванием файла с использованием средства, которое как раз для этого и предназначено (решение проблемы prompt finalization). Полностью игнорируется то, что без использования этого средства (using, брекеты и т.д.) доступность файла гарантируется, примерно как и доступность объекта, но несколько слабее. По независимым от ГЦ причинам. Например потому, что у объекта нет метода "освободить память", а метод "закрыть файл" наоборот есть, как и у его плюсового аналога. Т.е. гарантия доступности точно не хуже плюсовой. K>3) Подразумевается, но не говориться (и даже явно отрицается), что претензия к prompt finalization. Действительно, такой гарантии нет ни для освобождения памяти, ни для закрытия файла. Первое считается приемлемым, а для второго есть другие средства (using, брекеты, регионы etc.), которые не поддерживают UFP (потому что гарантия на доступность не сочетается с гарантией на неотложное освобождение).
1. Я вам привёл уже несколько вариантов решения UFP в C++, в том числе GC. О чём тут ещё спорить?
2. Дефолтное средство управление ресурсами, RAII, работает и для памяти и для ресурсов в отличии от GC.
3. Вариант решения UFP с ресурсами (называйте как хотите — UFP не UFP, но то что проблема подобная это факт) в языках (с позиции которых был наезд "даже Upward Funarg Problem не решена") продемонстрирован не был. Запрет — это не решение.
K>При этом пример, который предлагается повторить, демонстрирует систему, которая не гарантирует ни доступность, ни неотложенную финализацию. Первое потому, что UFP не решена. Второе потому, что возвращая откуда-то замыкание, вы делегируете ответственность за время жизни "пользователю" функции, который может продлевать время ее жизни неограниченно. Естественно при разработке систем дающих гарантии на prompt finalization с такой лазейкой будут наоборот бороться.
Это касается не только возвращения ресурсов в замыканиях, а вообще в любых объектах, что я является нормальной практикой. Если же требуется запретить передвижение, то делают non-copyable&non-movable.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>Это демагогия, с тем же успехом можно сказать что [&] решает UFP — сама ссылка-то жива, это просто объект уже уничтожен. Толку-то от мёртвого ресурса? I>>>Никакого, но с UFP всё в порядке. EP>>Отличный подход. "С UFP всё в порядке, поэтому исходную задачу решать не будем" I>Скажи пожалуйста, а бросание исключения из лямбды тоже UFP нарушает ?
С чего бы? Ресурс-то уничтожится когда уничтожится само замыкание
I>>>Покажи где ты собираешься O(N) получить, если отбросить случай намеренного дублирования кода. EP>>Было: EP>>
EP>>class Foo
EP>>{
EP>> // ...
EP>>};
EP>>
Foo используется в N местах (включая транзитивные зависимости), в том числе у клиентов, к коду которых доступа нет. EP>>Стало: EP>>
Удачной O(N) охоты на IDisposable I>То есть, под O(N) ты имеешь ввиду аггрегирование, которое я уже упоминал.
Ты также упоминал "Не надо никаких N мест". Покажи как в примере выше у тебя не будет никаких N мест.
I>Вероятно, у тебя есть чудесный способ узнать что ресурс корректно захватывается, освобождается и разрушается во всех N случаях ? Покажи этот чудесный способ.
А при чём тут это? "плохие" вещи доступны во всех обсуждаемых здесь языках.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>И что тебя смущает ? EP>>Привёл ссылку где рассказывается как Python может вызывать C/C++/Fortran библиотеки. Что сказать-то хотел? I>Спасибо, капитан, а я то думал, что Питон в 100% случаев именно так и работает, а оказывается, так оно и есть.
Ээ. Так это ты привёл эту ссылку. Зачем?
I>>>Посмотри какие либы используются для научных вычислений. Там довольно часто код пишется дольше чем работает. EP>>Какой-нибудь FEM (которых только в РФ штуки 4 из известных) — требует много вычислительных ресурсов. EP>>Причём аппетит приходит во время еды — более мелкая сетка, разные сочетания нагрузок, нелинейные материалы, динамика, mesh optimization, progressive collapse analysis и т.д и т.п. При добавлении какого-либо нового свойства — время расчёта увеличивается на порядок, а то и несколько. I>Я немного не понимаю, для чего здесь С++. Это чисто математическая задача — накидать решение хоть в чем угодно, а потом сгенерировать тупой максимально быстрый код.
Покажи такой генератор.
EP>>unsafePerformIO можно запретить, вся связь с внешним миром, в том числе с библиотеками, будет идти строго через монаду IO — получится действительно чистое ФП. Разница для разработчика будет минимальной. EP>>Так вот, мой тезис в том, что такое чистое ФП — плохо мэппится существующее железо, а не в том что элементы ФП не нужны. I>Такое чистое ФП нужно там, где архитектура вычислителя другая.
Так я и говорю, что оно не для фон-Неймановских машин. С чем ты споришь?
I>Если ты хочешь гонять код ровно в одном ядре, то конечно императивный язык здесь заруливается всех в минуса, я про то уже писал около десяти раз за последние полгода.
Он заруливает даже тогда, когда нужно гонять код на многих ядрах/машинах. Да, в диспетчере могут быть полезны элементы ФП (типа примитивных map+reduce), но от того что код работает на нескольких машинах, сами машины не перестали быть фон-Неймановскими, а весь код не стал внезапно чистым ФП.
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Подобное возможно в С#, в виде Lifted Operators для Nullable.
Бррр, ну вроде бы уже несколько раз обсудили, что подобное мы не рассматриваем. Т.е. вот если бы в C# был механизм реализовать подобное для любой монады, тогда да, это было бы по теме...
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>К сожалению, нет никакого способа убедиться в том, что некоторый код "следует правилам библиотечки". Специально стараться никуда не нужно — я не представляю себе способа написать минимально безопасную библиотеку на С++. Потому что в языке нет никакого способа запретить штуки типа char*, которые могут указывать буквально куда угодно.
Запретить нельзя. Но никто и не заставляет использовать такое в своём коде. Т.е. да, работая на C++, надо понимать что ты делаешь. В отличие от языков специально заточенных под слабых программистов, которые ограничивают их. Но если ты понимаешь как как правильно себя ограничивать, то дальше C++ будет контролировать корректность всего сам.
S>Дело не в модели акторов, а в том, чтобы иметь гарантии. На всякий случай напомню, что безо всякой распределёнщины С++-ный проект для эриксоновского свитча так и не взлетел. Несмотря на то, что там не самые тупые девелоперы писали, уж наверное могли "легко написать просто в лоб". А потом пришёл Эрланг, и внезапно оказалось, что всё можно написать не только языком на форуме, и оно даже работает.
Вообще то, насколько я помню, они потом отказались от всего этого и вернулись к обычному классическому коду, написанному другой компанией. Именно благодаря этому Эрланг и попал в open source.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>Без проблем это всё делается на C++. Например вот http://www.theron-library.com/index.php?t=page&p=tour1 интересное решение. Ну т.е. конечно небольшая разница есть. В том смысле, что т.к. C++ позволяет иметь самый низкий уровень доступа, то при желание можно без проблем обмануть библиотеку и сломать модель. Но это если специально стараться (в Эрланге такое даже при этом не выйдет), а если следовать правилам библиотечки, то получается абсолютно такой же быстродействующий и надёжный код. S>К сожалению, нет никакого способа убедиться в том, что некоторый код "следует правилам библиотечки". Специально стараться никуда не нужно — я не представляю себе способа написать минимально безопасную библиотеку на С++. Потому что в языке нет никакого способа запретить штуки типа char*, которые могут указывать буквально куда угодно.
В языке нет, но при необходимости можно сделать внешний верификатор который запретит "плохие" конструкции в тех или иных модулях. То есть это скорее инфраструктурный вопрос.
Другой вопрос насколько это необходимо. В том же Node.js можно точно также отстрелить себе ногу. Да и вообще, как только у нас есть while или аналог — то "можно делать плохие вещи".
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Вы так пишете, как будто это хорошо. Это, по факту, означает, что компилятор никак не помогает авторам таких библиотек.
Это цена за уникальные возможности. ) На мой взгляд незначительная, т.к. мы всегда можем добавить к библиотеке тестовую программку (не в смысле классических полноценных тестов, а просто один обычный сценарий использования) и получить от компилятора полный отчёт о всех проблемах типизации.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Отличный подход. "С UFP всё в порядке, поэтому исходную задачу решать не будем" I>>Скажи пожалуйста, а бросание исключения из лямбды тоже UFP нарушает ?
EP>С чего бы? Ресурс-то уничтожится когда уничтожится само замыкание
Ресурс
I>>То есть, под O(N) ты имеешь ввиду аггрегирование, которое я уже упоминал.
EP>Ты также упоминал "Не надо никаких N мест". Покажи как в примере выше у тебя не будет никаких N мест.
Я пока не вижу никакого внятного кода, есть код добавления одного мембера. Надо полагать я должен додумать весь недостающий код ,что бы угадать твои мысли ?
I>>Вероятно, у тебя есть чудесный способ узнать что ресурс корректно захватывается, освобождается и разрушается во всех N случаях ? Покажи этот чудесный способ.
EP>А при чём тут это? "плохие" вещи доступны во всех обсуждаемых здесь языках.
Код покажи для начала, а не огрызок.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Управление от потока данных.
И как это реализуется в случае числодробилок? )
I>Не пойму логики. Из существования задачи решаемой через массивом как то следует невозможность использования другой архитектуры ?
Ну как бы она не решается через массив, а по сути ставится через массив. Т.е. это изначально из самой задачи (физики, математики) идёт. Соответственно, если ты захочешь применять что-то другое (я кстати пока так и не понял что), то это будет уже не естественный способ, а какая-то эмуляция.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Спасибо, капитан, а я то думал, что Питон в 100% случаев именно так и работает, а оказывается, так оно и есть.
EP>Ээ. Так это ты привёл эту ссылку. Зачем?
Что бы ты убедился, что такие проекты пишутся в т.ч. на питоне. Только самые проблемные вещи оптимизируются через нативный код.
EP>Покажи такой генератор.
Все нормальные математические тулы умеют такое.
EP>Он заруливает даже тогда, когда нужно гонять код на многих ядрах/машинах. Да, в диспетчере могут быть полезны элементы ФП (типа примитивных map+reduce), но от того что код работает на нескольких машинах, сами машины не перестали быть фон-Неймановскими, а весь код не стал внезапно чистым ФП.
Если одно ядро это фон-Неймановская архитектура, то вовсе не значит, что и вся система будет подходить под эту архитектуру.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Управление от потока данных.
_>И как это реализуется в случае числодробилок? )
Если я скажу, что в таком процессоре нет счетчика текущей инструкции, типа регистра IP, ты сильно удивишься ?
_>Ну как бы она не решается через массив, а по сути ставится через массив.
То есть, ты хочешь что бы я искал какие то варианты в твоем половинчатом решении ?
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>Подобное возможно в С#, в виде Lifted Operators для Nullable. _>Бррр, ну вроде бы уже несколько раз обсудили, что подобное мы не рассматриваем. Т.е. вот если бы в C# был механизм реализовать подобное для любой монады, тогда да, это было бы по теме...
Насколько я понял, эти Lifted Operators для Nullable тоже не являются аналогом монады Maybe, так как не останавливают вычисления. Это скорее аппликативный функтор Maybe, чем монада — то есть толку от него мало.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Если я скажу, что в таком процессоре нет счетчика текущей инструкции, типа регистра IP, ты сильно удивишься ?
Так ты всё это время писал про процессоры с другой архитектурой? Так бы и сказал сразу... Тогда конечно много чего можно, но только вот это не относится к нашей текущей реальности... )
I>То есть, ты хочешь что бы я искал какие то варианты в твоем половинчатом решении ?
Причём тут какое-то моё решение? Это методика численных вычислений в науке вообще. Или ты хочешь и это как-то переделать? )
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Насколько я понял, эти Lifted Operators для Nullable тоже не являются аналогом монады Maybe, так как не останавливают вычисления. Это скорее аппликативный функтор Maybe, чем монада — то есть толку от него мало.
Ну и кстати говоря оно даже не формальная монада, т.к. там реально у Nullable нет какой-то спец. функции, которая вызывается в этих местах с передачей ей оператора. А там всё делает сам компилятор по месту, так что это больше всего напоминает просто перегрузку всех операторов для данного типа.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>Отличный подход. "С UFP всё в порядке, поэтому исходную задачу решать не будем" I>>>Скажи пожалуйста, а бросание исключения из лямбды тоже UFP нарушает ? EP>>С чего бы? Ресурс-то уничтожится когда уничтожится само замыкание I>Ресурс
?
I>>>То есть, под O(N) ты имеешь ввиду аггрегирование, которое я уже упоминал. EP>>Ты также упоминал "Не надо никаких N мест". Покажи как в примере выше у тебя не будет никаких N мест. I>Я пока не вижу никакого внятного кода, есть код добавления одного мембера. Надо полагать я должен додумать весь недостающий код ,что бы угадать твои мысли ?
Код чего? Как класс Foo может использоваться в разных местах? Хотя бы:
class Bar
{
Foo x;
// ...
};
class Baz
{
Bar x;
// ...
};
// ...
{
Baz x;
// ...
}
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Спасибо, капитан, а я то думал, что Питон в 100% случаев именно так и работает, а оказывается, так оно и есть. EP>>Ээ. Так это ты привёл эту ссылку. Зачем? I>Что бы ты убедился, что такие проекты пишутся в т.ч. на питоне.
Так я и сам подобные вещи иногда пишу, причём именно на Python
То есть вот это:
ты сказал только для того, чтобы показать что Python может вызывать быструю библиотеку на C/C++/Fortran? Круто
EP>>Покажи такой генератор. I>Все нормальные математические тулы умеют такое.
И доступ к памяти, нарезку по кэшам, кластеризацию, векторизацию, comiple-time полиморфизм, распределение по потокам, за-оптимизируют? Чудеса!
Пример покажи.
EP>>Он заруливает даже тогда, когда нужно гонять код на многих ядрах/машинах. Да, в диспетчере могут быть полезны элементы ФП (типа примитивных map+reduce), но от того что код работает на нескольких машинах, сами машины не перестали быть фон-Неймановскими, а весь код не стал внезапно чистым ФП. I>Если одно ядро это фон-Неймановская архитектура, то вовсе не значит, что и вся система будет подходить под эту архитектуру.
Дальше-то что? Чистый ФП код внезапно станет оптимальным для каждого из ядер?
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>ты сказал только для того, чтобы показать что Python может вызывать быструю библиотеку на C/C++/Fortran? Круто
Питон всегда вызывает нативный код, в 100% случаях. После этого можешь выдать объяснение почему же многие классы приложений уже перестали писать на С++, хотя, казалось бы, этот С++ даст вагон перформанса.
В частности это справедливо для WoT и Eve. Нет там никакой специфики, всё можно на С++ оформить.
Но вот известно, что плюсовые аналоги тупо не взлетели.
EP>И доступ к памяти, нарезку по кэшам, кластеризацию, векторизацию, comiple-time полиморфизм, распределение по потокам, за-оптимизируют? Чудеса! EP>Пример покажи.
Пример самый простой — плюсовый код не взлетел, зато взлетел Эрланг, с чего собтсвенно и началась история Эрланга.
EP>Дальше-то что? Чистый ФП код внезапно станет оптимальным для каждого из ядер?
Объясняю еще раз — эффективность работы одного ядра очень слабо коррелирует с эффективностью всей распределенной сети.
Если отбросить случаи когда задача легко дробится на сколь угодно большое количесво параллельных кусочков, то для С++ пространства не так и много.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Я пока не вижу никакого внятного кода, есть код добавления одного мембера. Надо полагать я должен додумать весь недостающий код ,что бы угадать твои мысли ?
EP>Код чего? Как класс Foo может использоваться в разных местах? Хотя бы: EP>
EP>class Bar
...
EP>
Я не вижу в твоём коде никакого использования ресурсов, даже косвенного. Покажи внятный код или будем считать, что это настолько сложный случай, что тебе не под силу.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Запретить нельзя. Но никто и не заставляет использовать такое в своём коде. Т.е. да, работая на C++, надо понимать что ты делаешь. В отличие от языков специально заточенных под слабых программистов, которые ограничивают их. Но если ты понимаешь как как правильно себя ограничивать, то дальше C++ будет контролировать корректность всего сам.
Если я понимаю, как правильно себя ограничивать, то мне незачем контроль со стороны компилятора. А если я рассеян и/или необучен особенностям конкретной библиотеки, то С++ спокойно даст мне выстрелить себе в ногу.
_>Вообще то, насколько я помню, они потом отказались от всего этого и вернулись к обычному классическому коду, написанному другой компанией. Именно благодаря этому Эрланг и попал в open source.
Вот про это я уже не в курсе. Можно пруфлинк?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Это цена за уникальные возможности. ) На мой взгляд незначительная, т.к. мы всегда можем добавить к библиотеке тестовую программку (не в смысле классических полноценных тестов, а просто один обычный сценарий использования) и получить от компилятора полный отчёт о всех проблемах типизации.
Что-то мне подсказывает, что нет, не получим мы от компилятора "полный отчёт о всех проблемах типизации". Точнее, что "тестовая программка", которую надо добавить к библиотеке, запросто окажется по размеру больше самой библиотеки — если мы хотим проверить все аспекты типизации.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В языке нет, но при необходимости можно сделать внешний верификатор который запретит "плохие" конструкции в тех или иных модулях. То есть это скорее инфраструктурный вопрос.
Вы всеръёз сейчас предлагаете воспроизвести весь фронт-енд компилятора С++ во внешнем верификаторе, и называете это "инфраструктурным вопросом"? А что тогда останавливает вас от банального внесения логики этого "верификатора" прямо в язык?
EP>Другой вопрос насколько это необходимо. В том же Node.js можно точно также отстрелить себе ногу. Да и вообще, как только у нас есть while или аналог — то "можно делать плохие вещи".
Лично я никогда не позиционировал Node.js как панацею надёжности. И далеко не всякий аналог while даёт нам возможность "делать плохие вещи".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Если я понимаю, как правильно себя ограничивать, то мне незачем контроль со стороны компилятора.
Очень даже есть зачем. Не стоит путать ошибочный общий стиль и какие-то мелкие местные огрехи — их компилятор с удовольствием выявит.
S>А если я рассеян и/или необучен особенностям конкретной библиотеки, то С++ спокойно даст мне выстрелить себе в ногу.
Вот как раз то, что по рассеянности делается, компилятор будет хорошо отлавливать. Ну а с применением плохого стиля (например типа использования вышеупомянутого char* вместо string) и последующими ошибками из-за него, компилятор действительно ничего не может сделать.
Вообще говоря, C++ сейчас по сути включает в себя и весьма безопасное подмножество и весьма опасное. Причём в отличие от C# они не разделяются каким-то ключевым словом, собственно нет даже чёткой границы по набору конструкций языка. Но любой C++ профессионал прекрасно осознаёт это разделение и не будет использовать опасные вещи без критической необходимости.
S>Вот про это я уже не в курсе. Можно пруфлинк?
Например здесь http://www.erlang-factory.com/upload/presentations/416/MikeWilliams.pdf есть хорошее описание всей истории и кстати частично самого языка. ) И там видно, что вопреки мифам, Erlang разрабатывался как замена некого хитрого внутреннего языка (PLEX), а не C++. Им удалось реализовать один проект (с 1996 по 1998), который получился весьма не плохим. Но при этом всё равно в 1998-ом Erlang был запрещён к использованию в Ericsson — там решили сосредоточиться на работе с индустриальными языками и кажется как раз с C++. )))
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Что-то мне подсказывает, что нет, не получим мы от компилятора "полный отчёт о всех проблемах типизации". Точнее, что "тестовая программка", которую надо добавить к библиотеке, запросто окажется по размеру больше самой библиотеки — если мы хотим проверить все аспекты типизации.
Неправильно подсказывает. ) Автор шаблона прекрасно знает под какие типы он создаётся. Соответственно реализуем в тестовой программке один новый тип с минимальным набором требуемых от него свойств. И дальше просто инстанцируем наш шаблон с ним и всё. Если код собирается, то значит будет корректно работать со всеми соответствующими типами — можно приступать уже к функциональному тестированию (как для не обобщённого кода). А если не собирается, то компилятор подробно укажет, что мы не правильно написали в нашем шаблоне.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
EP>>В языке нет, но при необходимости можно сделать внешний верификатор который запретит "плохие" конструкции в тех или иных модулях. То есть это скорее инфраструктурный вопрос. S>Вы всеръёз сейчас предлагаете воспроизвести весь фронт-енд компилятора С++ во внешнем верификаторе, и называете это "инфраструктурным вопросом"?
Воспроизводить фронт-енд необязательно — есть готовые, типа Clang. У него есть достаточно простое API для нахождения тех или иных конструкций: AST Matcher. Например:
#include"clang/ASTMatchers/ASTMatchers.h"#include"clang/ASTMatchers/ASTMatchFinder.h"using namespace clang;
using namespace clang::ast_matchers;
StatementMatcher LoopMatcher =
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
hasInitializer(integerLiteral(equals(0)))))))).bind("forLoop");
class LoopPrinter : public MatchFinder::MatchCallback {
public :
virtual void run(const MatchFinder::MatchResult &Result) {
if (const ForStmt *FS = Result.Nodes.getNodeAs<clang::ForStmt>("forLoop"))
FS->dump();
}
};
int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
LoopPrinter Printer;
MatchFinder Finder;
Finder.addMatcher(LoopMatcher, &Printer);
return Tool.run(newFrontendActionFactory(&Finder));
}
S>А что тогда останавливает вас от банального внесения логики этого "верификатора" прямо в язык?
1. Добавление верификатора поломает backward compatability.
2. Для разных целей нужны разные средства — кому-то нужен один верификатор, кому-то другой.
EP>>Другой вопрос насколько это необходимо. В том же Node.js можно точно также отстрелить себе ногу. Да и вообще, как только у нас есть while или аналог — то "можно делать плохие вещи". S>Лично я никогда не позиционировал Node.js как панацею надёжности.
Ну да — так там её просто нет, но тем не менее это не мешает его использовать.
S>И далеко не всякий аналог while даёт нам возможность "делать плохие вещи".
Если нет возможности сделать вечный цикл — то это не аналог while.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Запретить нельзя. Но никто и не заставляет использовать такое в своём коде. Т.е. да, работая на C++, надо понимать что ты делаешь. В отличие от языков специально заточенных под слабых программистов, которые ограничивают их. Но если ты понимаешь как как правильно себя ограничивать, то дальше C++ будет контролировать корректность всего сам.
То есть, ты хочешь делегировать компилятору контроль всего подряд ? Зачем же тогда понимать что ты делаешь ? И зачем тебе такой контролёр, если ты сам понимаешь, как надо себя контролировать ?
По моему ты боишься сказать простую вещь — С++ ничего не контролирует, то есть, вообще. У тебя полностью ручной контроль и компиялтор сводит к минимуму твои трудозатраты. Правда этот минимум кактой то странный — что бы внятно работать с ресурсами, надо нагородить вагон шаблонов.
Ну или взять такое чудовщие как Boost и несколько лет осваивать его. Итого, если у С++ разработчика менее 5 лет опыта и заявлено свободное владение stl и boost, то гарантировано никаких других скилов не будет, можно даже не искать.
Если ты не согласен, то почему ты не пишешь на ассемблере ? Вот в ём точно надо понимать что ты делаешь, надо понимать как правильно себя ограничивать и тд и тд.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>А если я рассеян и/или необучен особенностям конкретной библиотеки, то С++ спокойно даст мне выстрелить себе в ногу.
_>Вот как раз то, что по рассеянности делается, компилятор будет хорошо отлавливать. Ну а с применением плохого стиля (например типа использования вышеупомянутого char* вместо string) и последующими ошибками из-за него, компилятор действительно ничего не может сделать.
Практика показывает, что хороший стиль вырабатывается годами. По моему разумению, стиль, соглашения всех сортов люди начинают понимать где то после 10 лет опыта. Проблема в том, что к этим 10 года подавляющее большинство уходит в менеджмент, собственный бизнес или вообще в другую область.
_>Вообще говоря, C++ сейчас по сути включает в себя и весьма безопасное подмножество и весьма опасное. Причём в отличие от C# они не разделяются каким-то ключевым словом, собственно нет даже чёткой границы по набору конструкций языка. Но любой C++ профессионал прекрасно осознаёт это разделение и не будет использовать опасные вещи без критической необходимости.
Тоже самое можно и про ассемблер сказать — любой профессионал на ассемблере глупостей не делает.
Ну вот скажем, у меня бывало так — набираю код на асме около недели, эдакий жосцкий кодинг 8 часов в день и 5 дней подряд, в конце недели запускаю, и все не только компилируется, но и работает без крешей и подвисаний.
Личный рекорд — один месяц такого кодинга без промежуточных компиляний и тд и тд. При чем софтина запускалась в прошивке одной железяки для телефонных станций.
Вопрос — ты можешь повторить такое на С++ ?
_>Например здесь http://www.erlang-factory.com/upload/presentations/416/MikeWilliams.pdf есть хорошее описание всей истории и кстати частично самого языка. ) И там видно, что вопреки мифам, Erlang разрабатывался как замена некого хитрого внутреннего языка (PLEX), а не C++. Им удалось реализовать один проект (с 1996 по 1998), который получился весьма не плохим. Но при этом всё равно в 1998-ом Erlang был запрещён к использованию в Ericsson — там решили сосредоточиться на работе с индустриальными языками и кажется как раз с C++. )))
"– Frightened of using little known programming language"
То есть, политическое решение, никакого отношения к качеству софта не имело.
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>Что-то мне подсказывает, что нет, не получим мы от компилятора "полный отчёт о всех проблемах типизации". Точнее, что "тестовая программка", которую надо добавить к библиотеке, запросто окажется по размеру больше самой библиотеки — если мы хотим проверить все аспекты типизации.
_>Неправильно подсказывает. ) Автор шаблона прекрасно знает под какие типы он создаётся. Соответственно реализуем в тестовой программке один новый тип с минимальным набором требуемых от него свойств. И дальше просто инстанцируем наш шаблон с ним и всё. Если код собирается, то значит будет корректно работать со всеми соответствующими типами — можно приступать уже к функциональному тестированию (как для не обобщённого кода). А если не собирается, то компилятор подробно укажет, что мы не правильно написали в нашем шаблоне.
А как мне узнать, как правильно писать свой тип, что бы правильно заюзать вон тот шаблон ? Опаньки ! С учетом того, что мета-информация динамически типизирована, это превращается в небольшой квест.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>В языке нет, но при необходимости можно сделать внешний верификатор который запретит "плохие" конструкции в тех или иных модулях. То есть это скорее инфраструктурный вопрос. S>>Вы всеръёз сейчас предлагаете воспроизвести весь фронт-енд компилятора С++ во внешнем верификаторе, и называете это "инфраструктурным вопросом"?
EP>Воспроизводить фронт-енд необязательно — есть готовые, типа Clang. У него есть достаточно простое API для нахождения тех или иных конструкций: AST Matcher.
Это какая то плохая реализация паттерн-матчинга в виде библиотеки.
Такое ощущение, что в этой либе сэмулировали Лисп на С
Здравствуйте, Ikemefula, Вы писали:
I>Практика показывает, что хороший стиль вырабатывается годами. По моему разумению, стиль, соглашения всех сортов люди начинают понимать где то после 10 лет опыта. Проблема в том, что к этим 10 года подавляющее большинство уходит в менеджмент, собственный бизнес или вообще в другую область.
Достаточно лидера проекта с правильным стилем, а остальное можно обеспечить с помощью административных стилевых гайдов. Вот тот же Гугл так делает и ещё даже выкладывает свои варианты для публичного использования.
I>Ну вот скажем, у меня бывало так — набираю код на асме около недели, эдакий жосцкий кодинг 8 часов в день и 5 дней подряд, в конце недели запускаю, и все не только компилируется, но и работает без крешей и подвисаний. I>Личный рекорд — один месяц такого кодинга без промежуточных компиляний и тд и тд. При чем софтина запускалась в прошивке одной железяки для телефонных станций.
Сильно. Правда не очень пойму смысл кодинга без компиляции. )
I>Вопрос — ты можешь повторить такое на С++ ?
Не пробовал такого. )))
I>"– Frightened of using little known programming language"
I>То есть, политическое решение, никакого отношения к качеству софта не имело.
Только благодаря этому Эрланг и стал open source, так что его фанаты должны быть благодарны этому решению. )))
И это скорее не политическое решение, а экономическое и возможно вполне оправданное... )
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А как мне узнать, как правильно писать свой тип, что бы правильно заюзать вон тот шаблон ? Опаньки ! С учетом того, что мета-информация динамически типизирована, это превращается в небольшой квест.
Ты про использование уже готовой библиотеки? А тут то в чём проблема? Подставляешь свой тип в шаблон и если скомпилировалось, то значит всё будет работать. А если нет, то компилятор обязательно укажет, определения какой операции не хватает у твоего типа.
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Никакого монадического кода там не было, если конечно не считать тривиальную монаду.
там не Identity, а Continuation монада (наскольк вообще можно говоритьо монадах в бестиповом языке).
EP>Там не обработка пустого значения — а возвращение (причём возвращать пустое значение не обязательно). Это просто void. Я добавил if чтобы продемонстрировать что это именно монада, а не АФ.
Да про if-то понятно, дело в (). Ну, представьте, что это на типизированном языке написано — какой у нее возвращаемый тип?
EP>Подробнее. В примере Scheme — никакой ленивости нет, но раннее завершение у maybe — есть.
Я на этот вопрос отвечаю прямо в посте на который вы отвечаете.
EP>Приведите тогда пример немонадического кода на Scheme.
Затрудняюсь. Я вообще не составил для себя твердого представления, что можно считать (не)монадическим кодом в бестиповых языках. (В принципе, о монадах в языках без * -> * кайндов мы говорим, может и тут что-то можно придумать).
EP>Ленивость позволяет не вычислять ненужное в тех случаях, когда функция/алгоритм описаны с ненужными вычислениями.
Ну, вроде бы причина понятна, когда мы комбинируем функции, то часто описываем как раз такой вот код с ненужными вычислениями. И пока мы вычисляем что-то лишнее по сравнению с сфьюженой вручную версией — подход "комбинирование комбинаторов" всегда будет ущербным по сравнению с подходом "пишем рекурсивную лапшу". А это полноценному ФП сильно не способствует.
EP>Какое-то засилье ненужных вычислений в ФП, из-за которого ленивость необходима как пища, продемонстрировано не было.
Довольно странно сейчас спрашивать подтверждение тому, что вы сами же и заметили и разговор о чем начали здесь
foldl (+) 0 a (обсуждаемый выше) для [Maybe a] будет неэффективным
EP>Более того, судя по Q&A на stackoverflow, когда нужна скорость — от этой ленивости бегут, точно также как и от GC.
Это, мягко говоря, сильное упрощение проблемы. Во многих случаях как раз ленивость и GC скорость и обеспечивают. Особенно это касается именно высокоуровневого и идиоматичного кода.
EP>Непрактичность ленивости? Комбинирование обязательно влечёт за собой ленивость?
С.м. выше начиная с "Ну, вроде бы причина понятна, когда мы комбинируем функции, то часто..."
EP>Мы же вроде обсуждали монадический код?
Вы же сами перешли на тему обеспечения производительности "комбинаторного" кода. Но темы, конечно, пересекающиеся.
EP>С этим я не спорю. Я просто показал, как в языках с call/cc обычный код легко превращается в монадичный.
Это скорее демонстрация того, что монада Cont[inuation] может служить функциональной заменой для многих монад.
Проблема превращения "обычного" кода в монадический, вообще принципиально сложная. Без указания мест где нужны >>= это не сделать. Вашем коде они вручную помечены. Вот сделать из монадического обычный гораздо проще — для этого Identity монады достаточно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Воспроизводить фронт-енд необязательно — есть готовые, типа Clang. У него есть достаточно простое API для нахождения тех или иных конструкций: AST Matcher. I>Это какая то плохая реализация паттерн-матчинга в виде библиотеки.
Своё дело она выполняет отлично — позволяет находить нужные куски AST, и трансформировать их (в обсуждаемом контексте трансформация не нужна).
Причём качество "понимания" C++ у неё на высоте — это же Clang, один из лучших компиляторов C++.
I>Такое ощущение, что в этой либе сэмулировали Лисп на С I>
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Опять 25. Почему они не работающие? Они работают даже для ресурсов в отличии от.
Потом, что доступность не гарантируют. И для дефицитных ресурсов доступность — это как раз то, чем можно пожертвовать ради закрытия по завершению использования.
EP>На C++ есть всякие DSL библиотеки, позволяющие писать высокоуровневый, который отлично мэппятся в железо. Например Eigen может во время компиляции выбрать оптимальный путь вычисления матричного выражения, и автоматически векторизовать.
Это пример куда лучше, но, тем не менее, числодробление не особенно высокоуровнево.
EP>Опять-таки высокоуровневый != огромное penalty.
Это, конечно, верно. Однако подход высокоуровневого языка заключается в том, чтоб дать широкий набор инструментов, в том числе и таких, где penalty неизбежно, однако постараться минимизировать это "огромное penalty". Ну а подход "вот тут мы можем как-то обойтись без огромного penalty, значит это у нас будет — вот это — нет." — это подход низкоуровневого языка.
EP>В большинстве кода не то что shared_ptr нет, а даже unique_ptr.
В большинстве низкоуровневого кода — да, в большинстве идиоматического ФП-кода — нет.
EP>Где вычисляется то что ненужно?
В примере "монадизации" на D, например.
EP>Выводы на основе ложных утверждений. Далеко не все абстракции дорогие.
Но многие абстракции, востребованные для написания ФП кода как раз дорогие.
K>>Поэтому никакого высокоуровневого кода и нет — есть только продвинутый интерфейс для двигания указателей. А поддержка высокоуровневых инструментов ограничивается заявлениями о их ненужности. EP>См. Eigen.
Смотрим. То, что не использовано для написания Eigen — не нужно?
EP>Да — это именно то решение, которое вы описали для UFP с ресурсами: "ненужно, поэтому запретить".
EP>1. Какую abstraction penalty вносит указатель сам по себе?
Указатель — это абстракция "плоская память произвольного доступа", если мы не "проделаем в ней дыру" и не станем учитывать иерархию памяти и прочее, от чего она нас вроде бы должна абстрагировать — мы будем биться об стену памяти, например. Вот такая вот penalty.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Встроенная абстракция языка, которая как вы говорите является "пищей ФП" и которая судя по всему используется повсеместно, даже в hello world, вводит меж-поточную синхронизацию (относительная цена которой с каждым годом только возрастает) — это и называется "на ровном месте".
Ну так ленивость предоставляет возможность изменять по месту. Причем в многопоточном случае дешевле (в чистом языке) о чем в статье и написано. Если вы будете переписывать хвост списка, как это обычно делается в строгих ФЯ, то тормозов из-за межпоточной синхронизации будет больше.
EP>Нужна ли такая абстракция или нет, приемлема ли такое penalty или нет — естественно зависит от прикладной области.
Все-таки необходимость таких вещей слабо связана с предметной областью. Предметная область для таких средств — написание хорошо взаимодействующих друг с другом библиотек. Но допустим, что это так. И что нам делать, если язык ленивость нормально не поддерживает? Избегать эту прикладную область?
EP>Я предполагаю что лучшего решения нет — мутабельные данные (модификация/чтение для которых может пересекаться) требуют синхронизации by-design, поэтому их и нужно избегать.
И вы сможете без них обходиться?
EP>Решение аналогичных задач (но через другую функциональность) в других языках достигается куда более дешёвыми средствами.
Дешевыми в смысле производительности получившегося кода — да. В смысле труда программиста — нет. Аналогичные задачи в низкоуровневых языках решаются ручным слиянием функций, вместо их комбинирования.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
K>>Непонятно, в каком смысле это аналогично C++ если там нет даже второго крайнего положения, не говоря уже о промежуточных, а есть только одно.
EP>Второе крайнее положение есть — type-erasure, но оно достигается специальным кодом, а не компилятором. EP>Например можно сделать так: EP>
Оба варианта работают с "callable" типа int(double), без всякого наследоавния. Но в первом случае код шаблона должен быть виден в месте использования (хотя конкретные специализации можно компилировать отдельно), а во втором — раздельная компиляция.
Речь идет о разных вариантах компиляции одного и того же кода. А тут код отличается.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Никакого монадического кода там не было, если конечно не считать тривиальную монаду. K>там не Identity, а Continuation монада (наскольк вообще можно говоритьо монадах в бестиповом языке).
Где тут continuation:
(define (user_func get Mx My)
(define x '())
(define y '())
(set! x (get Mx))
(if (less x 1000)
(begin
(set! y (get My))
(* x y))
'()))
?
EP>>Там не обработка пустого значения — а возвращение (причём возвращать пустое значение не обязательно). Это просто void. Я добавил if чтобы продемонстрировать что это именно монада, а не АФ. K>Да про if-то понятно, дело в (). Ну, представьте, что это на типизированном языке написано — какой у нее возвращаемый тип?
Зависит от идиом языка, возможно какой-нибудь null/nil/nullptr/void/etc, под всё можно подстроить оборачивающий код.
Но, это пустое значение не является необходимостью. В большинстве кода не будет никакого пустого значения.
EP>>Приведите тогда пример немонадического кода на Scheme. K>Затрудняюсь. Я вообще не составил для себя твердого представления, что можно считать (не)монадическим кодом в бестиповых языках.
В Scheme ведь строгая типизация.
EP>>Какое-то засилье ненужных вычислений в ФП, из-за которого ленивость необходима как пища, продемонстрировано не было. K>Довольно странно сейчас спрашивать подтверждение тому, что вы сами же и заметили и разговор о чем начали K>здесь
foldl (+) 0 a (обсуждаемый выше) для [Maybe a] будет неэффективным
Мы же говорим про монадизацию существующего кода?
1. Так а чем ленивость помогает в случае с foldl [Maybe a]?
2. Как ленивость поможет монодизировать foldl/foldr [list a] ?
EP>>Мы же вроде обсуждали монадический код? K>Вы же сами перешли на тему обеспечения производительности "комбинаторного" кода. Но темы, конечно, пересекающиеся.
Это другая тема. Да — call/cc это дорогая конструкция.
EP>>С этим я не спорю. Я просто показал, как в языках с call/cc обычный код легко превращается в монадичный. K>Это скорее демонстрация того, что монада Cont[inuation] может служить функциональной заменой для многих монад.
Для всех монад http://blog.sigfpe.com/2008/12/mother-of-all-monads.html
K>Проблема превращения "обычного" кода в монадический, вообще принципиально сложная. Без указания мест где нужны >>= это не сделать. Вашем коде они вручную помечены. Вот сделать из монадического обычный гораздо проще — для этого Identity монады достаточно.
Я же говорю: они помечены только из-за ограничений Scheme.
1. Но даже в Scheme — эти get/await могут быть где-то в глубине call-tree, а функции их вызывающие никак не поменяются.
2. Изменения минимальны — вместо x будет (get x). Нет никакого кардинального изменения кода как в Haskell в виде нарезания всего control-flow на замыкания.
3. В том же C++/D ничего помечать не нужно. Но там нет полноценного call/cc, а есть ограниченный.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Речь не про убогое ФП, а про чистый код. Да, я помню, что вы считаете код внутри монад равноправным обычному коду в Хаскеле. Но на мой взгляд это совсем не так. И не только на мой (могу привести цитаты из хороших книг по Хаскелю).
Еще раз. Если вам что-то не нравится (например IORef), это не значит, что этого нет. А вся ваша аргументация и тут и в ветке про UFP как раз и построена на том, что IORef прочего не существует.
На самом деле в ФП есть средства работы с мутабельностью никак принципам ФП не противоречащие.
_>Не, это не то совсем. Вот хорошая скрытая мутабельность реализуется например при превращение рекурсии в цикл.
Непонятно, почему ленивость как скрытая мутабельность — это не то, а превращение рекурсии в цикл, как скрытая мутабельность — то. Первое встречается гораздо чаще второго, и позволяет оптимизировать гораздо более широкий спектр рекурсивного кода.
K>>Конкретный пример — это код. K>>Я же говорю, оптимизации, которые устраняют промежуточные массивы, списки и т.д. в комбинации функций, каждая из которых по по отдельности копирует, а не меняет по месту существуют и вполне работают. Как и все оптимизации, работают они не всегда, но объем копирования существенно сокращают. Т.е. компилятор оптимизирующий код вида: K>>... K>>существует. Понятно, что без таких оптимизаций было бы затруднительно комбинировать комбинаторы более-менее безнаказанно.
_>Ну ок, пускай будет код. Мне интересно, в коде типа такого _>
Что-то подобное вполне можно оптимизировать так, чтоб память выделялась один раз. Правда, типичные подходы к дефорестации/фьюжену минимизируют проходы (плюс они ориентированы на оптимизацию конвееров, в которых типы на входе и выходе функций обычно отличаются), так что полученный код будет проверять наличие n функций для каждого элемента в течении одного прохода по выделенной памяти, а не ходить по этой памяти n раз. Впрочем, правила переписывания для того же GHC это библиотечный код, все эти оптимизации не захардкодили в компилятор, а написали авторы библиотек, с которыми они (оптимизации) и поставляются. Так что можно и преобразования нужные вам описать — никакой принципиальной проблемы тут нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Исходные коды, из которых генерируется бинарный код, полностью типизированы.
Ну так я же не утверждаю, что конкретный, специализированный код нетипизирован? Он, конечно, типизирован. Нетипизирован обобщенный.
_>А то, что копилятор не обращает внимания на куски исходников, не используемые для генерации бинарного кода, никак не снижает уровень типизации.
Т.е. отсутствие проверки типов для какого-то кода не снижает уровень типизации? Вообще-то снижает. В случае отсутствия проверки, снижает до нуля.
_>Ну так это же опять не компиляция в исполняемый код (как и в том случае в Хаскелем при соответствующей оптимизации), а просто некое переформатирование исходников. )))
Это вполне решает те проблемы, для решения которых раздельная компиляция и существует. ну и в случае линктайм кодогенерации, это может быть оптимизация, которая работает именно что с почти готовым исполняемым кодом, который слинкуется и заработает и без этой оптимизации.
_>Что-то вы всё время придумываете некоторые мысли за меня и потом успешно с ними боретесь. ))) Я же чётко противопоставлял скорость обобщённого кода и раздельность компиляции, а не типизированность и раздельность компиляции.
Вы начали обсуждать скорость обобщенного кода как оправдание и даже причину нетипизированности обобщенного кода. Хотя обобщенный код, который работает так же как и плюсовые шаблоны вполне можно типизировать.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Это цена за уникальные возможности.
И что это за не имеющие аналогов возможности? Тут рядом я давал ссылку на сравнение разных методов обобщенного программирования, которое показывает, что возможности вовсе не уникальны. Так что едва ли это можно рассматривать как цену уплаченную за какие-то уникальные возможности — оплачивается экономия умственных усилий разработчиков языка.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Он может стать чистым где-то далеко выше, при применение чего-то типа runSt для отрезания данной области от остального кода. А так это не нормальный код на хаскеле, а императивный монадный подъязык.
Он всегда является чистым. IO/ST как раз это и обеспечивают. Это нормальный код на хаскеле, который преимущественно из использования разнообразных "молнадных подъязыков" и состоит.
_>Реализации различные, а результат один.
Нет, не один.
K>>А если мы возвращаем пару или вовсе список замыканий? _>Да без проблем. Какая разница сколько объектов перемещать? )
Объект один. А ссылки на него во всех возвращаемых замыканиях. Какое тут может быть перемещение?
_>Про циклы не понял о чём вообще речь.
Циклические ссылки.
_>Насчёт выбора и т.п... Ну C++ как бы не самый простой язык и вообще не очень ориентирован на новичков. Однако думаю что уж не Хаскелю что-то говорить на эту тему — в нём не меньше всяческих нюансов, просто они совсем из другой области.
На хаскеле просто писать высокоуровневый код, а низкоуровневый — сложно. На плюсах легко писать низкоуровневый код, а высокоуровневый — сложно.
_>Кстати, сам то код функции с ссылкой выглядит не так уж и страшно. Только вот это уже не та функция (по сравнению с C++ аналогом) — в ней мы имеем дело уже не int'ом, а с некой другой сущностью, не имеющей его свойств (в отличие от int& в большинстве императивных языков). И вследствие этого, код использующий данную функцию будет уже выглядеть совсем адски.
Вот так всегда. Какой монадически-ужасный код вам не покажи — всякий раз оказывается, что ничего страшного в нем нет, но вот другой, пока еще не показанный — вот это ужас-ужас-ужас.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Так это и есть работающий код:
tail -n 6 main.cpp
Ядерный реактор условно не показан.
Все же можно посмотреть полный код, который можно скомпилировать и запустить?
EP>Вот только смысла так писать нет — итеративная версия будет и проще и быстрее. EP>Но если нужна действительно быстрая версия, то посыпание синтаксическим сахром ничем не поможет — нужно использовать подходящий алгоритм, типа ((1,1),(1,0))^n*(1,0).
У вас что, есть волшебный рецепт переписывания любого ФП-кода в "итеративный" или вообще "подходящий"? Понятно, что считать числа Фибоначчи именно таким способом бессмысленно. Это просто демонстрация применения ряда идиоматических приемов/языковых средств на минимальном примере.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>1. Нет встроенных ленивых списков, но они реализуются библиотечно То есть их нет, точно также как нет и встроенных в язык хэштаблиц — хотя std::unodered_map элементарно реализуется средствами самого языка.
Что за встроенные списки? В типе
data [a] = a : [a] | []
есть магические имена конструкторов, но никакими магическими свойствами, по сравнению с типом
data List a = a :> List a | Nil
он не обладает.
А без встроенной ленивости — как вы обеспечите оптимизации описанные в статье? Как вы автоматически будете строгость анализировать? Ну понятно как — написанием языка со встроенной ленивостью.
EP>2. Какого "прочего, более важного" нет?
Решенной UFP.
K>>Ну вот пусть программист решит, где применение ФП себя оправдывает, а где нет. В этом и заключается основная разница между высокоуровневым языком и низкоуровневым.
EP>Разница между высокоуровневым языком и низкоуровневым это наличие ФП? http://rsdn.ru/forum/images/anvaka/wacko.gif
ОК
Ну вот пусть программист решит, где применение высокоуровневых средств себя оправдывает, а где нет. В этом и заключается основная разница между высокоуровневым языком и низкоуровневым.
EP>"обычно небесплатен" — в том то и дело, что он никому не обязан быть "платным".
Как только придумаете небесплатные аналоги — так сразу и будет не обязан. А пока, в данной нам в ощущениях реальности эти средства вполне "платные".
EP>Я говорю что использовать ФП ВЕЗДЕ нет смысла, так как в ряде случаев есть более эффективные и зачастую более понятные техники.
Например прилежание и усидчивость.
EP>Использование ФП там где оно добавляет тормозов на ровном месте, затрудняет понимание и не даёт никаких преимуществ — это и есть "писать ФП ради самого ФП".
Есть смысл использовать ФП везде, где программист решил, что использовать есть смысл. А низкоуровневый коммунизм известен: в колбасе ленивости потребности нет.
EP>Каким образом вы решили что аргумент "писать ФП ради самого ФП — нет смысла" применим только при доказательстве ненужности всего ФП — для меня остаётся загадкой
Ну так ваше "писать ФП ради ФП нет смысла" — это же просто отговорка. Если что-то в плюсах поддерживается слабо — значит это ФП ради ФП — смысла не имеет. А если поддерживается — сразу имеет смысл.
Допустим, ленивость не нужна, гарантии доступности для захваченного в замыкания (а значит и лямбды) не нужны. А что тогда нужно? Вы список какой-нибудь можете составить — какие же ФП-средства нужны, в котором более 0 пунктов?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[30]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
K>>Тормозит по сравнению с чем? EP>Тормозит по сравнению с простейшей итеративной версией, которую можно объяснить даже ребёнку.
Ну я и говорю. Под поддержкой фп понимается "это все ненужно — можно же написать нетормозящую итеративную версию!".
K>>Вот когда предоставите для сравнения control-structure для связывания комбинаторов с комбинаторами с аналогичной функциональностью (поддержка раннего завершения, циклов, автомемоизации, потокобезопасность и т.д.) тогда и сравним.
EP>Зачем всё это при вычислении простейших задач типа чисел Фибоначчи?
Для более сложных задач. Впрочем подход обычный: поддержка ФП инструментария опять оказалась риторическим вопросом "зачем все это нужно?"
EP>А зачем замена? Ваш пример с числами Фибоначчи с точностью до минимальных синтаксических различий (скобки вместо $, * вместо . , <ap> вместо <*> и т.п.) переписывается на C++: EP>
Вопрос в том, какими средствами это достигается и какими свойствами обладает. Синтаксических претензий у меня, допустим, нет. Вот будет полный, компилирующийся и запускающийся пример — можно будет и обсудить.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>1. Я вам привёл уже несколько вариантов решения UFP в C++, в том числе GC. О чём тут ещё спорить?
Из которых ни одно решение кроме консервативного GC доступность не гарантирует, а консервативный GC не обладает приемлемыми с практической точки зрения свойствами.
EP>2. Дефолтное средство управление ресурсами, RAII, работает и для памяти и для ресурсов в отличии от GC.
В каком смысле "работает?". UFP не обеспечивает, а prompt finalization обеспечивает. Дефолтное управление с помощью GC наоборот UFP обеспечивает, а prompt finalization — нет. Я согласен, что для дефицитных ресурсов первое лучше, но для обычных языковых сущностей лучше второе.
EP>3. Вариант решения UFP с ресурсами (называйте как хотите — UFP не UFP, но то что проблема подобная это факт) в языках (с позиции которых был наезд "даже Upward Funarg Problem не решена") продемонстрирован не был. Запрет — это не решение.
Я же говорю, уберите скобки-using-и и будет UFP. Скобки нужны для prompt finalization.
EP>Это касается не только возвращения ресурсов в замыканиях, а вообще в любых объектах, что я является нормальной практикой.
Для объектов это нормальная практика, а для дефицитных ресурсов — ненормальная.
EP>Если же требуется запретить передвижение, то делают non-copyable&non-movable.
Вот это уже близкий аналог регионов-скобок.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Достаточно лидера проекта с правильным стилем, а остальное можно обеспечить с помощью административных стилевых гайдов. Вот тот же Гугл так делает и ещё даже выкладывает свои варианты для публичного использования.
Административные костыли никогда толком не работают. Гугл как раз нетипичный пример, ибо у них средний уровень контингента намного выше чем в среднем по больнице.
Административные костыли перестают работать, когда появляется активный разработчик, еще не очень опытный, но у которого хорошо получается работа. "А я вот так сделаю и это будет работать" — всё, административные костыли перестали работать.
Отсюда ясно, что для административных костылей надо подбирать команду по принципу — один толковый-ответсвенный и толпа послушных управляемых статистов.
К такой модели разработки отношусь очень скептически, ибо видел как такие команды делали только провальные, распильные проекты или мелочовку которая никому не интересна.
I>>Ну вот скажем, у меня бывало так — набираю код на асме около недели, эдакий жосцкий кодинг 8 часов в день и 5 дней подряд, в конце недели запускаю, и все не только компилируется, но и работает без крешей и подвисаний. I>>Личный рекорд — один месяц такого кодинга без промежуточных компиляний и тд и тд. При чем софтина запускалась в прошивке одной железяки для телефонных станций.
_>Сильно. Правда не очень пойму смысл кодинга без компиляции. )
Компиляция, вообще говоря, нужна только для того что бы отдать готовый результат, всё остальное это кривые инструменты или слабые мозги.
I>>Вопрос — ты можешь повторить такое на С++ ?
_>Не пробовал такого. )))
А ты попробуй. Вот там будет очень интересно послушать про самоограничение, стили и соглашения. Получилось — значит язык позволяет то о чем ты говоришь. Не получилось — стало быть ты говоришь про некоторый идеал который для тебя недостижим, и пудозреваю, для большинства разработчиков так же недостижим.
Я например точно понимаю эту разницу, потому как давно утратил способности писать код неделями без ошибок.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>А как мне узнать, как правильно писать свой тип, что бы правильно заюзать вон тот шаблон ? Опаньки ! С учетом того, что мета-информация динамически типизирована, это превращается в небольшой квест.
_>Ты про использование уже готовой библиотеки? А тут то в чём проблема? Подставляешь свой тип в шаблон и если скомпилировалось, то значит всё будет работать.
Если скомпилировалось, то для С++ это значит что только скомпилировалось, а будет ли работать — большой вопрос. Вот для Хаскеля — если скомпилировалось, то с много большей вероятностью будет работать. Вот это и есть типизация.
>А если нет, то компилятор обязательно укажет, определения какой операции не хватает у твоего типа.
Годится, расскажи, как написать код, скажем, статического анализатора ну например на Clang(рядом пример взял), который скажет что bind и unit (другой пример рядом) реализованы неправильно, монадные законы, типы и всё такое.
Программа, разумеется, компилируется.
Второй случай — препроцессор на том же Clang который заменит код эквивалентным, выбрасывая сколь угодно большое количество мусора. Программу так же компилируется.
Ты главное опиши словам, а то мне интересно, как такие фокусы можно делать если типизация шаблонов динамическая. Пудозреваю, если ты решишь эти две задачи, то, внезапно, этот же подход можно будет заюзать для джаваскрипта и питона и динамических языков вообще, да так что скорость работы сравняется с нативным кодом
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Еще раз. Если вам что-то не нравится (например IORef), это не значит, что этого нет. А вся ваша аргументация и тут и в ветке про UFP как раз и построена на том, что IORef прочего не существует. K>На самом деле в ФП есть средства работы с мутабельностью никак принципам ФП не противоречащие.
Так и не существует, вне монад.
Насчёт того, что мне не нравится... В Хаскеле это пожалуй только реализация IO/ST. Т.е. я конечно понимаю, что при данных условиях они не могли сделать по другому. Но можно же было не ставить такие условия, а сделать помягче. Например сделать чистоту не обязательной, а опциональной (как в D). Ленивость кстати при этом можно не убирать полностью — просто она будет работать только для соответствующих мест. Тогда внешний вид программы стал бы как на других функциональных языках, без монадного ужаса. Кстати, саму концепцию монад в Хаскеле как раз стоило бы оставить, как весьма удобную, но уже без IO/ST...
K>Непонятно, почему ленивость как скрытая мутабельность — это не то, а превращение рекурсии в цикл, как скрытая мутабельность — то. Первое встречается гораздо чаще второго, и позволяет оптимизировать гораздо более широкий спектр рекурсивного кода.
Ну так она же не всегда позволяет оптимизировать. )
K>Что-то подобное вполне можно оптимизировать так, чтоб память выделялась один раз. Правда, типичные подходы к дефорестации/фьюжену минимизируют проходы (плюс они ориентированы на оптимизацию конвееров, в которых типы на входе и выходе функций обычно отличаются), так что полученный код будет проверять наличие n функций для каждого элемента в течении одного прохода по выделенной памяти, а не ходить по этой памяти n раз. Впрочем, правила переписывания для того же GHC это библиотечный код, все эти оптимизации не захардкодили в компилятор, а написали авторы библиотек, с которыми они (оптимизации) и поставляются. Так что можно и преобразования нужные вам описать — никакой принципиальной проблемы тут нет.
Так можно всё же получить не некие общие рассуждения, а конкретные ответ:
1. сколько выделений памяти будет в указанном коде?
2. как будет выглядеть на haskell'e код, реализующий тоже самое, но с нулём выделений памяти (размещение исходных данных не считаем)?
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Т.е. отсутствие проверки типов для какого-то кода не снижает уровень типизации? Вообще-то снижает. В случае отсутствия проверки, снижает до нуля.
А то, что компилятор Хаскеля не проверяет исходники какой-нибудь библиотеки на диске, не используемой в данном проекте, случаем не снижает уровень типизации? С точки зрения вашей логики явно должно снижать... )))
Или наоборот. Возьмём шаблонную C++ библиотеку и раскидаем её по заголовочным файлам так, чтобы в каждом файле было ровно по одному шаблону. И соответственно тогда включим в проект, только используемые в нём, заголовочные файлы. После этих магических действий у нас по вашей логике проект резко стал полностью типизированным (т.к. в нём больше нет ни строчки без проверки типов компилятором)?
K>Вы начали обсуждать скорость обобщенного кода как оправдание и даже причину нетипизированности обобщенного кода. Хотя обобщенный код, который работает так же как и плюсовые шаблоны вполне можно типизировать.
Я физически не мог называть скорость обобщённого кода в C++ оправданием нетипизированности, хотя бы потому, что не раз говорил, что не считаю его нетипизированным. Так что ценой за сочетание мощи+скорости шаблонов в C++ является как раз отсутствие раздельной компиляции.
Собственно в Хаскеле всё тоже самое, разве что добавлена возможность получить медленный код с раздельной компиляций.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
>>А если нет, то компилятор обязательно укажет, определения какой операции не хватает у твоего типа. I>Годится, расскажи, как написать код, скажем, статического анализатора ну например на Clang(рядом пример взял), который скажет что bind и unit (другой пример рядом) реализованы неправильно, монадные законы, типы и всё такое.
AFAIK, монадические законы даже в Haskell не проверяются.
Всё остальное реализуется в языке, без внешнего анализатора — работает и перегрузка (то есть проверка того что передали) и проверка тела шаблона (те операции которые используются). Например смотри Boost.ConceptCheck.
Причём в C++11 с decltype SFINAE стал очень мощным (при таком decltype — концепции это практически синтаксический сахар).
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Он всегда является чистым. IO/ST как раз это и обеспечивают. Это нормальный код на хаскеле, который преимущественно из использования разнообразных "молнадных подъязыков" и состоит.
Чистый снаружи, но не сам по себе.
K>Объект один. А ссылки на него во всех возвращаемых замыканиях. Какое тут может быть перемещение?
Это имеется в виду что-то типа возвращения из функции нескольких разных лямбд, каждая из которых захватывает одну и ту же локальную переменную из нашей функции? Что-то вообще ни разу не попадался мне на практике такой вариант, хотя лямбды использую с удовольствием. Но в любом случае решение тут тоже очевидно — shared_ptr.
K>На хаскеле просто писать высокоуровневый код, а низкоуровневый — сложно. На плюсах легко писать низкоуровневый код, а высокоуровневый — сложно.
Интересная мысль. ) А вот скажем известный набор паттернов проектирования — это высокоуровневый или низкоуровневый код? )
K>Вот так всегда. Какой монадически-ужасный код вам не покажи — всякий раз оказывается, что ничего страшного в нем нет, но вот другой, пока еще не показанный — вот это ужас-ужас-ужас.
Так просто в данном случае весь "ужас ужас ужас" не в самой функции, а в коде её использования (который не был показан). В C++ то нет особой разницы в использование функции int f(int) и void f(int&), а в Хаскеле во втором случае появляется та самая жуть...
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Если скомпилировалось, то для С++ это значит что только скомпилировалось, а будет ли работать — большой вопрос. Вот для Хаскеля — если скомпилировалось, то с много большей вероятностью будет работать. Вот это и есть типизация.
Чего чего? ) Ну покажи мне где там разница... )))
I>Годится, расскажи, как написать код, скажем, статического анализатора ну например на Clang(рядом пример взял), который скажет что bind и unit (другой пример рядом) реализованы неправильно, монадные законы, типы и всё такое. I>Программа, разумеется, компилируется.
Она разумеется не компилируется, если хоть что-то не корректно. )
I>Второй случай — препроцессор на том же Clang который заменит код эквивалентным, выбрасывая сколь угодно большое количество мусора. Программу так же компилируется.
Это я вообще не понял о чём. )
I>Ты главное опиши словам, а то мне интересно, как такие фокусы можно делать если типизация шаблонов динамическая. Пудозреваю, если ты решишь эти две задачи, то, внезапно, этот же подход можно будет заюзать для джаваскрипта и питона и динамических языков вообще, да так что скорость работы сравняется с нативным кодом
Эээээ что? ) Шаблоны C++ работают исключительно во время компиляции. Так что если нам нужно что-то в рантайме, то надо брать уже не шаблоны, а другой инструмент.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Административные костыли никогда толком не работают. Гугл как раз нетипичный пример, ибо у них средний уровень контингента намного выше чем в среднем по больнице.
Ну так хороший пример для подражания же. Тем более что в небольшой компании этого гораздо проще достичь. )
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Если скомпилировалось, то для С++ это значит что только скомпилировалось, а будет ли работать — большой вопрос. Вот для Хаскеля — если скомпилировалось, то с много большей вероятностью будет работать. Вот это и есть типизация.
_>Чего чего? ) Ну покажи мне где там разница... )))
Это вобщем другими словами примерно следующее "высокоуровневый код писать легко". Но я так понял, ты и с этим будешь спорить ?
I>>Годится, расскажи, как написать код, скажем, статического анализатора ну например на Clang(рядом пример взял), который скажет что bind и unit (другой пример рядом) реализованы неправильно, монадные законы, типы и всё такое. I>>Программа, разумеется, компилируется.
_>Она разумеется не компилируется, если хоть что-то не корректно. )
То есть, ты утверждаешь, что компилятор сумеет отличить правильную с т.з. реализацию математики реализацию bind и неправильную ?
Я правильно тебя понял ?
I>>Второй случай — препроцессор на том же Clang который заменит код эквивалентным, выбрасывая сколь угодно большое количество мусора. Программу так же компилируется.
_>Это я вообще не понял о чём. )
Очень просто — анализируешь мета-код и генеришь эквивалентную замену. Например нашел мега-итераторы и ррррраз, заменил всё более толковым кодом.
I>>Ты главное опиши словам, а то мне интересно, как такие фокусы можно делать если типизация шаблонов динамическая. Пудозреваю, если ты решишь эти две задачи, то, внезапно, этот же подход можно будет заюзать для джаваскрипта и питона и динамических языков вообще, да так что скорость работы сравняется с нативным кодом
_>Эээээ что? ) Шаблоны C++ работают исключительно во время компиляции. Так что если нам нужно что-то в рантайме, то надо брать уже не шаблоны, а другой инструмент.
Шаблоны C++ работают исключительно во время компиляции и при этом они динамически типизированы.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Административные костыли никогда толком не работают. Гугл как раз нетипичный пример, ибо у них средний уровень контингента намного выше чем в среднем по больнице.
_>Ну так хороший пример для подражания же. Тем более что в небольшой компании этого гораздо проще достичь. )
А в комании из одного человека так и вовсе проблем никаких.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>На хаскеле просто писать высокоуровневый код, а низкоуровневый — сложно. На плюсах легко писать низкоуровневый код, а высокоуровневый — сложно.
_>Интересная мысль. ) А вот скажем известный набор паттернов проектирования — это высокоуровневый или низкоуровневый код? )
Если паттерны высокоуровневые, то код высокоуровневый. Если паттерны низкоуровневые, то код низкоуровневый.
K>>Вот так всегда. Какой монадически-ужасный код вам не покажи — всякий раз оказывается, что ничего страшного в нем нет, но вот другой, пока еще не показанный — вот это ужас-ужас-ужас.
_>Так просто в данном случае весь "ужас ужас ужас" не в самой функции, а в коде её использования (который не был показан). В C++ то нет особой разницы в использование функции int f(int) и void f(int&), а в Хаскеле во втором случае появляется та самая жуть...
Да покаж уже эти ужасы. Уже скоро месяц пугаешь ужасами, я за это время даже Хаскель немного выучить успел но никак ужасов не найду
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это вобщем другими словами примерно следующее "высокоуровневый код писать легко". Но я так понял, ты и с этим будешь спорить ?
А причём тут это? Ты писал про какие-то различия уровня типизации обобщённого кода на C++ и Haskell'е. Так вот, если мы говорим про некий C++ проект с шаблонами, компилируемый в исполняемый файл (а не шаблонную библиотеку, поставляемую в виде заголовочных файлов), то разницы с Хаскелем нет никакой, в принципе. А именно, компилятор и там и там чётко сообщит о всех некорректностях и просто не скомпилирует проект в случае наличия каких-то ошибок.
I>То есть, ты утверждаешь, что компилятор сумеет отличить правильную с т.з. реализацию математики реализацию bind и неправильную ? I>Я правильно тебя понял ?
Это никакой компилятор не сможет проверить, т.к. для этого надо смотреть не только на прототип функции bind (что компилятор может), но и на её реализацию.
I>Очень просто — анализируешь мета-код и генеришь эквивалентную замену. Например нашел мега-итераторы и ррррраз, заменил всё более толковым кодом.
Ты говоришь про статический анализатор/трансформер исходников что ли? %) Никогда не пользовался такими штуками. И причём он вообще к нашей дискуссии?
I>Шаблоны C++ работают исключительно во время компиляции и при этом они динамически типизированы.
Что-то я тебе вообще перестал понимать. Ты вообще о чём говоришь то? )))
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>На C++ есть всякие DSL библиотеки, позволяющие писать высокоуровневый, который отлично мэппятся в железо. Например Eigen может во время компиляции выбрать оптимальный путь вычисления матричного выражения, и автоматически векторизовать. K>Это пример куда лучше, но, тем не менее, числодробление не особенно высокоуровнево.
Над этим числодроблением можно точно также надстроить абстракции (бесплатные/дешёвые), более близкие к конкретной предметной области. Например Eigen+МКЭ.
EP>>Опять-таки высокоуровневый != огромное penalty. K>Это, конечно, верно. Однако подход высокоуровневого языка заключается в том, чтоб дать широкий набор инструментов, в том числе и таких, где penalty неизбежно, однако постараться минимизировать это "огромное penalty". Ну а подход "вот тут мы можем как-то обойтись без огромного penalty, значит это у нас будет — вот это — нет." — это подход низкоуровневого языка.
В C++ по-другому. Там не "то что дорого — запрещено", а "you don't pay for what you don't use".
За то что нужно платить — выключено по умолчанию, но это не означает что оно полностью запрещено.
EP>>В большинстве кода не то что shared_ptr нет, а даже unique_ptr. K>В большинстве низкоуровневого кода — да, в большинстве идиоматического ФП-кода — нет.
Например C#/Java — это какие по-вашему? Низкоуровневые?
EP>>Где вычисляется то что ненужно? K>В примере "монадизации" на D, например.
Это достаточно искусственный/специфичный пример. Там точно также как и в foldl происходят лишние вычисления.
EP>>Выводы на основе ложных утверждений. Далеко не все абстракции дорогие. K>Но многие абстракции, востребованные для написания ФП кода как раз дорогие.
А для чего востребован сам этот ФП код? ("этот" — о котором идёт речь, с дорогими абстракциями. (отдельные ФП элементы действительно имеют полезные свойства, необходимые при решении практических задач, и при этом бесплатны/дёшевы)).
K>>>Поэтому никакого высокоуровневого кода и нет — есть только продвинутый интерфейс для двигания указателей. А поддержка высокоуровневых инструментов ограничивается заявлениями о их ненужности. EP>>См. Eigen. K>Смотрим. То, что не использовано для написания Eigen — не нужно?
Нужно, но не везде и не всегда.
То есть весь вопрос в том, насколько часто у дорогих абстракций нет дешёвых альтернатив.
EP>>1. Какую abstraction penalty вносит указатель сам по себе? K>Указатель — это абстракция "плоская память произвольного доступа",
Память плоская только в пределах массива/структуры.
K>если мы не "проделаем в ней дыру" и не станем учитывать иерархию памяти и прочее, от чего она нас вроде бы должна абстрагировать — мы будем биться об стену памяти, например. Вот такая вот penalty.
Сам указатель не даёт никакого penalty. Он не отражает иерархичность, но не исключает её.
Если нужен быстрый код — нужно так или иначе учитывать GCD особенности целевых систем. Например для учёта иерархической организации памяти разрабатываются сache-oblivious алгоритмы.
Что и как можно встроить в понятие указатель для отражения иерархичности? Что это даст по сравнению с тем что есть сейчас?
(особенно нужно учесть, что C++ код работает на разном железе, включая восьми битные микроконтроллеры).
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Это вобщем другими словами примерно следующее "высокоуровневый код писать легко". Но я так понял, ты и с этим будешь спорить ?
_>А причём тут это? Ты писал про какие-то различия уровня типизации обобщённого кода на C++ и Haskell'е. Так вот, если мы говорим про некий C++ проект с шаблонами, компилируемый в исполняемый файл (а не шаблонную библиотеку, поставляемую в виде заголовочных файлов), то разницы с Хаскелем нет никакой, в принципе. А именно, компилятор и там и там чётко сообщит о всех некорректностях и просто не скомпилирует проект в случае наличия каких-то ошибок.
Мы говорим про библиотеку а не готовый исполняемый продукт.
Если ввели эти и другие мульки, то с хаскелем разница только в раздельной компиляции.
I>>То есть, ты утверждаешь, что компилятор сумеет отличить правильную с т.з. реализацию математики реализацию bind и неправильную ? I>>Я правильно тебя понял ?
_>Это никакой компилятор не сможет проверить, т.к. для этого надо смотреть не только на прототип функции bind (что компилятор может), но и на её реализацию.
Я про статистический анализатор, а не компилятор.
I>>Шаблоны C++ работают исключительно во время компиляции и при этом они динамически типизированы.
_>Что-то я тебе вообще перестал понимать. Ты вообще о чём говоришь то? )))
In C++, templates are not separately type checked. Instead, type checking is
performed after instantiation at each call site. Type checking of the call site can
only succeed when the input types satisfy the type requirements of the function
template body. Unfortunately, because of this, if a generic algorithm is invoked
with an improper type, complex, long, and potentially misleading error messages
may result.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
1. Указанная вещь без проблем работает ещё в древнем стандарте языка. Просто она в нём записывается с кучей синтаксического мусора (через enable_if), а предлагается сделать отдельную симпатичную запись. Т.е. по сути это практически синтаксический сахар, хотя и весьма сильный.
2. И старая реализация и указанное (вроде как это планируют в C++14), работают исключительно в процессе использования шаблона. Т.е. здесь опять же требуется инстанцирование, для включение контроля компилятором. Но лично я не вижу в этом никаких существенных ограничений.
3. Собственно говоря именно контроль типов в C++ шаблонах полноценно работает и без всяких концептов, просто выдаются слегка разные сообщения об ошибках ("Cont — это не Sortable тип" vs "у Cont не определён оператор >"), что совсем не принципиально. А реальная польза от концептов (сейчас для этого используют страшные выражения с enable_if) в возможности перегрузки шаблонов без указания конкретных типов. Это позволяет например определить общий алгоритм для InputIterator и более оптимальный для RandomIterator и т.п.
I>Я про статистический анализатор, а не компилятор.
Хы, ну я про это ничего не знаю. Не пользуюсь ими вообще. )))
I>
I>In C++, templates are not separately type checked. Instead, type checking is
I>performed after instantiation at each call site. Type checking of the call site can
I>only succeed when the input types satisfy the type requirements of the function
I>template body. Unfortunately, because of this, if a generic algorithm is invoked
I>with an improper type, complex, long, and potentially misleading error messages
I>may result.
Ну да, всё правильно. Я только не пойму к чему ты написал эти очевидные истины. )
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
.
I>Если ввели эти и другие мульки, то с хаскелем разница только в раздельной компиляции.
1. Это Concepts Lite. Как уже сказал alex_public, на тело шаблона они не накладывают ограничения (хотя первый вариант концепций C++0x ограничивал и тело шаблона). Тут подробнее.
2. Всё что дают Concepts Lite помимо сахара, по сравнению с тем что есть сейчас — это разбиение требований на атомы, и автоматическая перегрузка по тестам множеств (сейчас нужно играть с тэгами, enable_if/disable_if/etc).
3. У них есть shorthand-notation. Например, варианты кода выше:
Здравствуйте, alex_public, Вы писали:
I>>Если ввели эти и другие мульки, то с хаскелем разница только в раздельной компиляции.
_>1. Указанная вещь без проблем работает ещё в древнем стандарте языка. Просто она в нём записывается с кучей синтаксического мусора (через enable_if), а предлагается сделать отдельную симпатичную запись. Т.е. по сути это практически синтаксический сахар, хотя и весьма сильный.
enable_if это костыль
_>2. И старая реализация и указанное (вроде как это планируют в C++14), работают исключительно в процессе использования шаблона. Т.е. здесь опять же требуется инстанцирование, для включение контроля компилятором. Но лично я не вижу в этом никаких существенных ограничений.
Я куда ни смотрю, то у тебя в С++ всё шоколадно, хотя ты этим не пользуешься, но вот в другом языке только ужос-ужос-ужос.
_>3. Собственно говоря именно контроль типов в C++ шаблонах полноценно работает и без всяких концептов, просто выдаются слегка разные сообщения об ошибках ("Cont — это не Sortable тип" vs "у Cont не определён оператор >"), что совсем не принципиально. А реальная польза от концептов (сейчас для этого используют страшные выражения с enable_if) в возможности перегрузки шаблонов без указания конкретных типов. Это позволяет например определить общий алгоритм для InputIterator и более оптимальный для RandomIterator и т.п.
Вобщем то принципиально, а то многие ошибки с шаблонами по количеству текста превосходят любые самые худшие ожидания
I>>
I>>In C++, templates are not separately type checked. Instead, type checking is
I>>performed after instantiation at each call site. Type checking of the call site can
I>>only succeed when the input types satisfy the type requirements of the function
I>>template body. Unfortunately, because of this, if a generic algorithm is invoked
I>>with an improper type, complex, long, and potentially misleading error messages
I>>may result.
_>Ну да, всё правильно. Я только не пойму к чему ты написал эти очевидные истины. )
Ты же с этим несогласен
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>1. Добавление верификатора поломает backward compatability. EP>2. Для разных целей нужны разные средства — кому-то нужен один верификатор, кому-то другой.
Ок, это аргумент.
EP>Ну да — так там её просто нет, но тем не менее это не мешает его использовать.
Я пока скептически отношусь к Node.js. В своё время казалось, что тяжеловесные ОРМ — это ответ на все вопросы. А потом внезапно выяснилось, что они создают больше проблем, чем решают. Вот и Node.js — интересный эксперимент. Году к 2020 посмотрим, что из него имеет смысл вписывать в скрижали, а что окажется смешным заблуждением наивных пропонентов.
EP>Если нет возможности сделать вечный цикл — то это не аналог while.
А для чего вам вечный цикл?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>enable_if это костыль
Ну так свои задачи то выполняет и не плохо. Не зря же его в итоге в стандарт ввели. )
I>Я куда ни смотрю, то у тебя в С++ всё шоколадно, хотя ты этим не пользуешься, но вот в другом языке только ужос-ужос-ужос.
Не не не, ты забываешь про D — вот там действительно всё шоколадно. ))) Если бы для D сейчас был готовый Boost, wxWidgets и ещё несколько подобных библиотек, плюс мощная IDE (хотя это уже даже не обязательно) уровня Netbeans/Eclipse/VS, то C++ выкинул бы прямо сегодня. ))) Хотя нет, надо бы ещё компилятор D под ARM и микроконтроллеры (такое сейчас даже не намечается, хотя технически возможно), вот тогда точно можно выкидывать.
I>Вобщем то принципиально, а то многие ошибки с шаблонами по количеству текста превосходят любые самые худшие ожидания
Хы, это чуть ли не единственная здравая претензия к C++ шаблонам в этой темке. )))
I>Ты же с этим несогласен
Где это было? )
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну и кстати говоря оно даже не формальная монада, т.к. там реально у Nullable нет какой-то спец. функции, которая вызывается в этих местах с передачей ей оператора.
Конечно же не монада. Нормальная монада должна была не только операторы залифтить, но и любые функции от базового типа.
А там всё делает сам компилятор по месту, так что это больше всего напоминает просто перегрузку всех операторов для данного типа.
Ага. Просто монадный компилятор мог бы это делать автоматом для любых монад, а не только для встроенных в язык.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>вне монад.
Ну так что с того?
_>Но можно же было не ставить такие условия, а сделать помягче. Например сделать чистоту не обязательной, а опциональной (как в D). Ленивость кстати при этом можно не убирать полностью — просто она будет работать только для соответствующих мест. Тогда внешний вид программы стал бы как на других функциональных языках, без монадного ужаса.
Ну был бы еще один ФЯ-инвалид вроде SML/OCaml. Ведь любое ослабление контроля за эффектами придется разменять на удобства в коде и оптимизации. И это при том, что тему ужасности "монадных ужасов" раскрыть так и не удалось.
Лучше было бы, если бы контроль за эффектами в хаскеле можно было наоборот усилить, чтоб учитывать частичность/незавершаемость функций, это бы дало еще больше полезной информации и для анализатора строгости и для инлайнера, что позволило бы делать более агрессивные оптимизации и рассуждать о коде без всяких скидок на боттомы.
K>>Непонятно, почему ленивость как скрытая мутабельность — это не то, а превращение рекурсии в цикл, как скрытая мутабельность — то. Первое встречается гораздо чаще второго, и позволяет оптимизировать гораздо более широкий спектр рекурсивного кода.
_>Ну так она же не всегда позволяет оптимизировать.
Не всегда, но для полноценной поддержки рекурсии ленивость полезнее TCO именно за счет более широкого охвата. Хвостовая рекурсия по какой-то причине сильно раскручена во всяких вводных статьях по ФЯ, хотя сама по себе редко встречается (а те случаи, когда она переписывается именно в цикл — и того реже), переписывание в хвосторекурсивной форме часто уродует код (хвосторекурсивная лапша с аккумуляторами не сильно лучше циклов выглядит, ручная CPS-трансформация и того хуже), про всякие развороты списков задом наперед и лишнюю работу на ровном месте я и не говорю.
_>Так можно всё же получить не некие общие рассуждения, а конкретные ответ: _>1. сколько выделений памяти будет в указанном коде? _>2. как будет выглядеть на haskell'e код, реализующий тоже самое, но с нулём выделений памяти (размещение исходных данных не считаем)?
Конкретный ответ получить можно. Вот он:
import qualified Data.Vector.Generic as V
import qualified Data.Vector.Generic.Mutable as M
import Control.Monad
-- это у нас "фильтры", что-то делаем с массивом (разворачиваем, например)
f1' p = when p . M.reverse
f2' p = when p . M.reverse
-- эти функции из тех, что вы называете "в большой монаде", делаем из них
-- такие, которые вы считаете идиоматическими, т.е. копирующие:
f1 :: V.Vector v a => Bool -> v a -> v a
f1 p = V.modify $ f1' p
f2 :: V.Vector v a => Bool -> v a -> v a
f2 p = V.modify $ f2' p
-- комбинатор для производства таких функций из монадических устроен так:
-- modify f = new . New.modify f . clone
-- эта функция копирует (clone) переданный массив в свежеразмещенный
-- т.е. такой про который мы знаем, что ссылка на него есть только
-- в данной функции, а значит его можно "заморозить" в иммутабельный
-- без копирования (new).
-- Ну, теперь выстраиваем конвейер:
test1 p1 p2 = f1 p1 . f2 p2
-- без оптимизации тут два выделения памяти для массива.
-- но есть оптимизация. В библиотеке (в числе прочих) прописано правило
-- "clone/new [Vector]" forall p. clone (new p) = p
-- буквально означающее, что копировать свежеразмещенный массив не нужно
В результате, конвейер скомпилируется во что-то вроде этого (хаскель, восстановленный из core):
test1 p1 p2 v1 = runST $ do
let x1 = length v1
s <- new x1 -- первоначальное выделение памяти под мутабельный массив
copy v1 s -- копирование в него переданного иммутабельного массиваif p2
then
M.reverse s -- разворот in-placeif p1
then
M.reverse s
unsafeFreeze s -- "заморозка" без копирования.else
unsafeFreeze s
else if p1
then
M.reverse s
unsafeFreeze s
else unsafeFreeze s
Т.е. только размещение исходных данных, никаких ненужных копирований нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А то, что компилятор Хаскеля не проверяет исходники какой-нибудь библиотеки на диске, не используемой в данном проекте, случаем не снижает уровень типизации?
Снижало бы, если бы этот код не проверялся тайпчекером. Но он проверялся. Ведь обобщенный код на хаскеле проверяется для всех типов, а не для конкретных и только после специализации.
Утверждения о проверке только используемого кода на C++ просто некорректны. Обобщенный код, который используется в другом обобщенном коде не проверяется. Библиотеки в которых вообще код только обобщенный, т.е. в случае C++ непроверяемый — распространенное явление для языков с нормальным параметрическим полиморфизмом.
_>Я физически не мог называть скорость обобщённого кода в C++ оправданием нетипизированности, хотя бы потому, что не раз говорил, что не считаю его нетипизированным.
Вы действительно не называете их "нетипизированными", однако их отличие от всех прочих систем обобщенного программирования в аспекте типизации вроде как признаете, нет?
_>Так что ценой за сочетание мощи+скорости шаблонов в C++ является как раз отсутствие раздельной компиляции.
Это, в основном, соответствует действительности, вот только отсутствие раздельной компиляции и вообще генеративная природа параметризации никак не связана с типизированностью. Я же говорю, существует системы обобщенного программирования вроде SML-ных функторов (именно SML-ных, окамловых это не касается) и F#-ных инлайн-функций, которые точно так же меняют проблемы с раздельной компиляцией на производительность как и плюсовые шаблоны, но полностью типизированы.
_>Собственно в Хаскеле всё тоже самое, разве что добавлена возможность получить медленный код с раздельной компиляций.
Там добавлена возможность получать достаточно быстрый код с преимущественно раздельной компиляцией, что вовсе не то же самое, а полностью противоположно ситуации с C++ в котором никакого компромисса между раздельностью компиляции и производительностью построить нельзя.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Чистый снаружи, но не сам по себе.
Что это значит? Это можно как-то раскрыть?
_>Это имеется в виду что-то типа возвращения из функции нескольких разных лямбд, каждая из которых захватывает одну и ту же локальную переменную из нашей функции? Что-то вообще ни разу не попадался мне на практике такой вариант, хотя лямбды использую с удовольствием.
Потому, что в императивных языках с кое-какими функциональными фичами лямбды/замыкания используют совсем не так, как в ФЯ, где они основной инструмент. Это определяется в числе прочего и принципиально разным уровнем поддержки.
Контейнеры с функциями совершенно нормальный случай. См. аппликативные функторы, например.
_>Но в любом случае решение тут тоже очевидно — shared_ptr.
Еще раз: счетчики тормозят и не работают с циклическими ссылками, которые постоянно встречаются в ФП.
_>Интересная мысль. ) А вот скажем известный набор паттернов проектирования — это высокоуровневый или низкоуровневый код? )
Это низкоуровневый код. Если я правильно понял о чем идет речь конечно (о кодогенерации а-ля Александреску).
_>Так просто в данном случае весь "ужас ужас ужас" не в самой функции, а в коде её использования (который не был показан).
Ну так покажите. А то я опять какой-то "страшный" монадический код покажу и опять окажется, что весь ужас в еще непоказанном. Нету у меня чувства жуткого монадического кода — тут без эксперта по ужасам монад никак не получится.
_>В C++ то нет особой разницы в использование функции int f(int) и void f(int&), а в Хаскеле во втором случае появляется та самая жуть...
А в бестиповых языках, бывает, нет особой разницы между числом и строкой, можно их складывать, например. Вот это удобство!
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Над этим числодроблением можно точно также надстроить абстракции (бесплатные/дешёвые), более близкие к конкретной предметной области. Например Eigen+МКЭ.
Будто бы МКЭ какое-то особенное числодробление.
EP>В C++ по-другому. Там не "то что дорого — запрещено", а "you don't pay for what you don't use". EP>За то что нужно платить — выключено по умолчанию, но это не означает что оно полностью запрещено.
Проблема в том, что за множество высокоуровневых инструментов нужно платить даже при неиспользовании, т.е. когда они "выключены" — это им дорогу в низкоуровневые языки вроде C++ и закрывает.
K>>В большинстве низкоуровневого кода — да, в большинстве идиоматического ФП-кода — нет. EP>Например C#/Java — это какие по-вашему? Низкоуровневые?
Разговор был вообще-то про ФП, с натяжкой ФЯ можно разве что C# посчитать.
Уровень у них повыше, чем у C++. И что? Писать на C++ в стиле C# и Явы (особенно в современном, когда популярны иммутабельные "объекты" и т.д.) примерно настолько же затруднительно, насколько и в ФП стиле. Собственно, ООП нуждается в точном компактифицирующем кучу GC не меньше ФП.
EP>Это достаточно искусственный/специфичный пример.
На самом деле, когда мы программируем в ФП стиле, комбинируя функции — это достаточно типичный случай.
EP>А для чего востребован сам этот ФП код? ("этот" — о котором идёт речь, с дорогими абстракциями. (отдельные ФП элементы действительно имеют полезные свойства, необходимые при решении практических задач, и при этом бесплатны/дёшевы)).
Вы постоянно уводите тему с поддержки ФП в C++ на ненужность ФП. Я не считаю нужность ФП-инструментария чем-то несомненным и не подлежащим обсуждению и при других обстоятельствах с удоольствием бы об этом поговорил, но в данной ветке — это просто сведение дискуссии с рельсов. Если даже вы обоснуете ненужность какого-то ФП-средства — это не будет означать наличие его поддержки там, где его нет. Если вы доказываете, что ФП поддерживается, то на просьбу предъявить X вы должны показать как легко X использовать и как хорошо он оптимизируется, а рассуждать о ненужности X, наоборот, не должны. Т.е. никто этого запретить вам не может, но к теме разговора это отношения не имеет.
EP>Нужно, но не везде и не всегда.
Так можно сказать про что угодно. Проблема в том, что если нужно не везде — где-то все равно нужно, значит поддержка должна быть.
EP>То есть весь вопрос в том, насколько часто у дорогих абстракций нет дешёвых альтернатив.
Полноценных альтернатив у дорогих абстракций не бывает никогда — иначе они (дорогие абстракции) никогда не вышли бы из областей больного воображения в реальный мир. Альтернативы "для бедных" бывают. Насколько часто — зависит от того, насколько "бедным" согласен быть пользователь таких альтернатив.
EP>Память плоская только в пределах массива/структуры.
И где же у указателя эти "пределы"?
EP>Сам указатель не даёт никакого penalty. Он не отражает иерархичность, но не исключает её.
Это какая-то софистика. Если мы будем употреблять указатель как указатель — мы будем биться об стену памяти. Чтоб этого не делать, нужно учитывать то, от чего указатель нас абстрагирует, т.е. разрушить абстракцию. Такая абстракция как раз иерархичность и исключает (из рассмотрения), а рассмотрение иерархичности — исключает такую абстракцию.
EP>Если нужен быстрый код — нужно так или иначе учитывать GCD особенности целевых систем. Например для учёта иерархической организации памяти разрабатываются сache-oblivious алгоритмы. EP>Что и как можно встроить в понятие указатель для отражения иерархичности? Что это даст по сравнению с тем что есть сейчас?
сache-oblivious — это как раз подход к построению абстракций, которые иерархичность памяти учитывают, а вот от конкретных параметров компонент этой иерархии нас абстрагируют.
А вот абстракции "указатель" и "массив" порождают такие тормозные в условиях иерархичной памяти штуки как поиск делением пополам и быстрая сортировка.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Если нужен быстрый код — нужно так или иначе учитывать GCD особенности целевых систем. Например для учёта иерархической организации памяти разрабатываются сache-oblivious алгоритмы. EP>>Что и как можно встроить в понятие указатель для отражения иерархичности? Что это даст по сравнению с тем что есть сейчас? K>сache-oblivious — это как раз подход к построению абстракций, которые иерархичность памяти учитывают, а вот от конкретных параметров компонент этой иерархии нас абстрагируют.
Так я об этом и говорю — машину нужно учитывать. Указатель не исключает иерархичность.
K>А вот абстракции "указатель" и "массив" порождают такие тормозные в условиях иерархичной памяти штуки как поиск делением пополам и быстрая сортировка.
Если про бинарный поиск ещё можно поспорить (например при определённых параметрах иерархичности implicit B-tree будет лучше), но чем quicksort не угодила?
Я про quick sort Тони Хоара, а не про ту пародию которую с гордостью показывают хаскелисты. Quick sort это как раз пример сache-oblivious алгоритма.
И, например, std::sort Степанова в SGI STL использует quick_sort как базу (introsort — начинает с quick sort, если достигается threshold глубина то делает переход на heap sort, и в конце всё полируется insertion sort). Уж кто-кто, а Степанов умеет делать быстрые алгоритмы.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Нужна ли такая абстракция или нет, приемлема ли такое penalty или нет — естественно зависит от прикладной области. K>Все-таки необходимость таких вещей слабо связана с предметной областью. Предметная область для таких средств — написание хорошо взаимодействующих друг с другом библиотек. Но допустим, что это так. И что нам делать, если язык ленивость нормально не поддерживает? Избегать эту прикладную область?
То есть без ленивости трудно делать библиотеки хорошо взаимодействующие друг с другом?
EP>>Я предполагаю что лучшего решения нет — мутабельные данные (модификация/чтение для которых может пересекаться) требуют синхронизации by-design, поэтому их и нужно избегать. K>И вы сможете без них обходиться?
Обычно синхронизация для мутабельных данных реально требуется только по периметру модуля, а не по всей площади.
Если же вы говорите что ленивость это пища для ФП — то видимо должна использоваться повсеместно, так? И соответственно меж-поточная синхронизация разбрасывается по коду только ради самой дорогой абстракции, а не для решения прикладной задачи. Ничего хорошего в этом нет
Если же ленивость нужна только по периметру, то никакая это не пища ФП.
EP>>Решение аналогичных задач (но через другую функциональность) в других языках достигается куда более дешёвыми средствами. K>Дешевыми в смысле производительности получившегося кода — да. В смысле труда программиста — нет. Аналогичные задачи в низкоуровневых языках решаются ручным слиянием функций, вместо их комбинирования.
"Ручное слияние" это по сути дубликация структуры кода, так? Хотелось бы увидеть пример.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Второе крайнее положение есть — type-erasure, но оно достигается специальным кодом, а не компилятором. EP>>Например можно сделать так:
[...] EP>>Оба варианта работают с "callable" типа int(double), без всякого наследоавния. Но в первом случае код шаблона должен быть виден в месте использования (хотя конкретные специализации можно компилировать отдельно), а во втором — раздельная компиляция. K>Речь идет о разных вариантах компиляции одного и того же кода. А тут код отличается.
Так я же и говорю, что автоматизма нет — нужна специальная обвёртка с type-erasure над шаблонной версией. Это безусловно недостаток, я всего лишь показываю ручную альтернативу.
Кстати, вот тут говорится что при использовании нескольких уровней (4-6) type-class'ов в GHC начинаются runtime тормоза, так как компилятор не может это переварить.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Так это и есть работающий код: EP>>
EP>>tail -n 6 main.cpp
EP>>
K>Ядерный реактор условно не показан. K>Все же можно посмотреть полный код, который можно скомпилировать и запустить?
В коде то, что я описал ранее — Lazy<T>, LazyList<T>, каррированные функции и named operator'ы.
Код не показываю только потому, что я его не оптимизировал (нет ни времени, ни мотивации), а начинать сравнение скорости 100-строковой реализации vs optimized code мне бы не хотелось.
Нечто подобное есть в outdated библиотеке FC++.
EP>>Вот только смысла так писать нет — итеративная версия будет и проще и быстрее. EP>>Но если нужна действительно быстрая версия, то посыпание синтаксическим сахром ничем не поможет — нужно использовать подходящий алгоритм, типа ((1,1),(1,0))^n*(1,0). K>У вас что, есть волшебный рецепт переписывания любого ФП-кода в "итеративный" или вообще "подходящий"?
В том то и дело что нет. И даже нет волшебного рецепта переписывания "итеративного" кода в "подходящий"/"оптимальный".
K>Понятно, что считать числа Фибоначчи именно таким способом бессмысленно. Это просто демонстрация применения ряда идиоматических приемов/языковых средств на минимальном примере.
Именно об этом я и говорю. Нужно знать алгоритмы, нужно знать машину, нужно знать mapping между ними — и только тогда можно получить эффективный код.
Так уж получилось, что на современные машины ФП код мэппится плохо. Да что там машины, многие полезные и практичные алгоритмы плохо мэппятся на чистый ФП (без всяких хаков типа STArray), на ровном месте добавляется логарифмическое penalty к complexity.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>"обычно небесплатен" — в том то и дело, что он никому не обязан быть "платным". K>Как только придумаете небесплатные аналоги — так сразу и будет не обязан. А пока, в данной нам в ощущениях реальности эти средства вполне "платные".
Так есть ведь аналоги. Вместо создания списка, в котором косвенность на косвенности, аллокации и thunk'и — в ряде случаев достаточно обычного плоского массива.
K>>>Если вы утверждаете, что поддержка ФП в языке есть, то аргументы вроде "писать ФП ради самого ФП — нет смысла" и "вместо ФП можно использовать более эффективные техники" невалидные. Они пришлись бы к месту, если бы вы доказывали его ненужность, но доказанная ненужность ФП опять таки не означает доказанного наличия ФП там, где его нет. EP>>Я говорю что использовать ФП ВЕЗДЕ нет смысла, так как в ряде случаев есть более эффективные и зачастую более понятные техники. Использование ФП там где оно добавляет тормозов на ровном месте, затрудняет понимание и не даёт никаких преимуществ — это и есть "писать ФП ради самого ФП". EP>>Каким образом вы решили что аргумент "писать ФП ради самого ФП — нет смысла" применим только при доказательстве ненужности всего ФП — для меня остаётся загадкой K>Ну так ваше "писать ФП ради ФП нет смысла" — это же просто отговорка. Если что-то в плюсах поддерживается слабо — значит это ФП ради ФП — смысла не имеет. А если поддерживается — сразу имеет смысл.
Какая отговорка? Ленивые вычисления — реализуются, UFP — решена. И да, использовать эти средства везде — нет смысла. В тех местах где performance penalty допустима, и если эти средства действительно дают преимущества — то их нужно использовать.
Если же вся программа целиком будет состоять только из дорогих ФП элементов, то действительно лучше взять язык заточенный под это
K>Допустим, ленивость не нужна, гарантии доступности для захваченного в замыкания (а значит и лямбды) не нужны. А что тогда нужно? Вы список какой-нибудь можете составить — какие же ФП-средства нужны, в котором более 0 пунктов?
Нужны где? По всему коду? Например:
Чистые функции: действительно полезно и удобно, это должен быть default. Причём внутри они могут что-то мутировать, создавать, удалять — также как и State Monad. (если чистые не получаются — можно регулярные (результат зависит только от аргументов, но могут быть side-effect'ы)).
Функции высшего порядка и first-class functions: мощная и полезная вещь.
Referential transparency: см. STL.
Замыкания: удобны, особенно при захвате большого количества переменных.
И это всё бесплатно, или крайне дёшево (зависит от компилятора) — так как всё прекрасно inline'ится.
Где-то наверху в calltree, можно использовать какие-то дорогие штуки, но не нужно разбрасывать их по всему коду без необходимости.
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>>>Тормозит по сравнению с чем? EP>>Тормозит по сравнению с простейшей итеративной версией, которую можно объяснить даже ребёнку. K>Ну я и говорю. Под поддержкой фп понимается "это все ненужно — можно же написать нетормозящую итеративную версию!".
Я вам показал как поддерживается ФП. И да, для практических целей тормозящая реализация fibs на ленивых списках не нужна.
Но из этого никак не следует что "под поддержкой фп понимается это все ненужно"
K>>>Вот когда предоставите для сравнения control-structure для связывания комбинаторов с комбинаторами с аналогичной функциональностью (поддержка раннего завершения, циклов, автомемоизации, потокобезопасность и т.д.) тогда и сравним. EP>>Зачем всё это при вычислении простейших задач типа чисел Фибоначчи? K>Для более сложных задач. Впрочем подход обычный: поддержка ФП инструментария опять оказалась риторическим вопросом "зачем все это нужно?"
Для более сложных задач — возможно. Но вопрос был про простые задачи.
Было заявлено что fibs это идиоматический hello world, и ленивость это пища ФП. Если же для простейших задач ленивость вредна — то видимо это и не "пища ФП", ведь так?
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Конкретный ответ получить можно. Вот он: K>...
О, интересное решение, спасибо. Значит мы пишем наши функции всё же монадным способом, а потом пакуем их в копирующие обёртки, с расчётом на то, что оптимизация выкинет эти обёртки на месте стыка.
Т.е. автоматически (обычным красивым кодом) добиться быстродействия в Хаскеле нельзя, но если специально заняться этим вопросом, то руками можно много чего оптимизировать...
K>В результате, конвейер скомпилируется во что-то вроде этого (хаскель, восстановленный из core): K>... K>Т.е. только размещение исходных данных, никаких ненужных копирований нет.
Ну вообще то одно лишнее копирование всё же есть. Но я понимаю о чём вы — что при 10-и функция будет всё равно это же одно лишнее копирование, а не 10.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Снижало бы, если бы этот код не проверялся тайпчекером. Но он проверялся. Ведь обобщенный код на хаскеле проверяется для всех типов, а не для конкретных и только после специализации. K>Утверждения о проверке только используемого кода на C++ просто некорректны. Обобщенный код, который используется в другом обобщенном коде не проверяется. Библиотеки в которых вообще код только обобщенный, т.е. в случае C++ непроверяемый — распространенное явление для языков с нормальным параметрическим полиморфизмом.
Ещё раз, "использование кода" — это генерация из него исполняемого файла. Компилятор отвечает исключительно за это и благодаря статической типизации не позволяет проникнуть в исполняемый файл ни одной ошибке такого рода. Заниматься же помощью в написание исходников — это не дело компилятора! Этим может заниматься например IDE или ещё какие-то подобные инструменты.
K>Вы действительно не называете их "нетипизированными", однако их отличие от всех прочих систем обобщенного программирования в аспекте типизации вроде как признаете, нет?
Конечно, в C++ и D используется система, позволяющая самые широкие возможности. Ценой за это является отсутствие раздельной компиляции. Ну и ещё местами страшноватый синтаксис и сообщения об ошибках в случае C++.
K>Это, в основном, соответствует действительности, вот только отсутствие раздельной компиляции и вообще генеративная природа параметризации никак не связана с типизированностью. Я же говорю, существует системы обобщенного программирования вроде SML-ных функторов (именно SML-ных, окамловых это не касается) и F#-ных инлайн-функций, которые точно так же меняют проблемы с раздельной компиляцией на производительность как и плюсовые шаблоны, но полностью типизированы.
Это просто у вас такое понимание типизированности. ) При котором вы хотите чтобы компилятор выполнял не только свою прямую работу, но и служил чем-то типа статического анализатора кода.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Потому, что в императивных языках с кое-какими функциональными фичами лямбды/замыкания используют совсем не так, как в ФЯ, где они основной инструмент. Это определяется в числе прочего и принципиально разным уровнем поддержки. K>Контейнеры с функциями совершенно нормальный случай. См. аппликативные функторы, например.
Контейнеры с функциями как раз попадаются. А вот возврат из нашей функции сразу нескольких замыканий что-то не припомню на практике. Хотя естественно в теории возможно. )
K>Это низкоуровневый код. Если я правильно понял о чем идет речь конечно (о кодогенерации а-ля Александреску).
Причём тут метапрограммирование? ) Я про эти вещи говорил. Так они низкоуровневые значит? А что в вашем понимание является высокоуровневым кодом?
K>Ну так покажите. А то я опять какой-то "страшный" монадический код покажу и опять окажется, что весь ужас в еще непоказанном. Нету у меня чувства жуткого монадического кода — тут без эксперта по ужасам монад никак не получится.
Я писал это Ikemefula, который просто не в курсе какая жуть следует за использованием State int вместо int. Вы же прекрасно в курсе о чём речь, просто упорно считаете это нормальным. )))
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Причём тут метапрограммирование? ) Я про эти вещи говорил. Так они низкоуровневые значит? А что в вашем понимание является высокоуровневым кодом?
K>>Ну так покажите. А то я опять какой-то "страшный" монадический код покажу и опять окажется, что весь ужас в еще непоказанном. Нету у меня чувства жуткого монадического кода — тут без эксперта по ужасам монад никак не получится.
_>Я писал это Ikemefula, который просто не в курсе какая жуть следует за использованием State int вместо int. Вы же прекрасно в курсе о чём речь, просто упорно считаете это нормальным. )))
Цже пошел второй месяц обсуждения, а ты никак эту жуть не покажешь Не боись, я не пугливый, переживу
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>1. Я вам привёл уже несколько вариантов решения UFP в C++, в том числе GC. О чём тут ещё спорить? K>Из которых ни одно решение кроме консервативного GC доступность не гарантирует,
Копирование, перемещение и refcounting тоже гарантирует доступность.
K>а консервативный GC не обладает приемлемыми с практической точки зрения свойствами.
Есть точные GC — но они менее автоматизированные чем консервативные. При использовании точных нужно заменять T* на gc_ptr<T>, etc.
EP>>3. Вариант решения UFP с ресурсами (называйте как хотите — UFP не UFP, но то что проблема подобная это факт) в языках (с позиции которых был наезд "даже Upward Funarg Problem не решена") продемонстрирован не был. Запрет — это не решение. K>Я же говорю, уберите скобки-using-и и будет UFP. Скобки нужны для prompt finalization.
Даже если не требовать prompt finalization, получается что нет никакого UFP-автоматизма — нельзя просто захватить какую-то переменную, нужно ещё и cкобки убирать, которые могут быть выше замыкания несколькими уровнями (что и было в исходном примере).
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Цже пошел второй месяц обсуждения, а ты никак эту жуть не покажешь Не боись, я не пугливый, переживу
Ну вообще то там была речь про IO (где всё ещё хуже), а не ST... Хотя разница не особо принципиальна. Просто ST во-первых можно не особо много использовать, а во-вторых есть средства для локализации ужаса. В случае же IO в обычном приложение всё наоборот.
Если есть желание вникнуть, то мне очень понравился один учебник (и это при том, что сам язык не понравился). Одновременно и с хорошим языком и очень подробный (если весь прочитать). Сейчас поищу ссылки на соответствующие разделы...
Значит вот теория про ST с примерами. После прочтения этого, должно стать очевидным, что неконстантная ссылка в Хаскеле — это что-то из области ада (в сравнение с другими языками). А пример qsort'а там вообще просто на загляденье... )))
А вот хорошее описание того, как автор пытается бороться с тем, во что вырождается Хаскель при столкновение с реальностью (интенсивным взаимодействием с внешним миром). Здесь уже больше про IO. Кстати, замечу, что автор тоже отделяет страшный монадный код от классического (который в реальности наверное только в учебниках и бывает) и называет его "псевдо-Haskell".
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Над этим числодроблением можно точно также надстроить абстракции (бесплатные/дешёвые), более близкие к конкретной предметной области. Например Eigen+МКЭ. K>Будто бы МКЭ какое-то особенное числодробление.
Внутри обычное числодробление, которым занимается Eigen. А снаружи — МКЭ-DSL, который генерирует матрицы элементов для перемалывания.
То есть над одним DSL — Eigen, надстраивается другой — МКЭ. Уровень абстракции повышается, а runtime penalty минимальный, если вообще присутсвует.
K>>>В большинстве низкоуровневого кода — да, в большинстве идиоматического ФП-кода — нет. EP>>Например C#/Java — это какие по-вашему? Низкоуровневые? K>Разговор был вообще-то про ФП, с натяжкой ФЯ можно разве что C# посчитать.
Вы постоянно пытаетесь противопоставить "ФП" и "низкоуровневый код". Как-будто только ФП это высокий уровень. Поэтому я и спросил про C#/Java.
EP>>То есть весь вопрос в том, насколько часто у дорогих абстракций нет дешёвых альтернатив. K>Полноценных альтернатив у дорогих абстракций не бывает никогда — иначе они (дорогие абстракции) никогда не вышли бы из областей больного воображения в реальный мир.
Конкретный пример — runtime reflection. В большинстве случаев достаточно compile-time reflection.
У runtime reflection огромный overhead, а у compile-time — нулевой.
EP>>Память плоская только в пределах массива/структуры. K>И где же у указателя эти "пределы"?
В ISO C++.
За этими пределами — here be dragons, в виде undefined behaviour.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
EP>>>>Другой вопрос насколько это необходимо. В том же Node.js можно точно также отстрелить себе ногу. S>>>Лично я никогда не позиционировал Node.js как панацею надёжности. EP>>Ну да — так там её просто нет, но тем не менее это не мешает его использовать. S>Я пока скептически отношусь к Node.js. В своё время казалось, что тяжеловесные ОРМ — это ответ на все вопросы. А потом внезапно выяснилось, что они создают больше проблем, чем решают. Вот и Node.js — интересный эксперимент. Году к 2020 посмотрим, что из него имеет смысл вписывать в скрижали, а что окажется смешным заблуждением наивных пропонентов.
ИМХО, Node.js зацепился только за счёт инфраструктуры и рекламы ("buzzwordish"). Ничего особенного там нет, тем более для надёжности. Поначалу даже не предлагалось никакого решения для распутывания лапши callback'ов.
EP>>Если нет возможности сделать вечный цикл — то это не аналог while. S>А для чего вам вечный цикл?
Для полноты по Тьюрингу.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Значит вот теория про ST с примерами. После прочтения этого, должно стать очевидным, что неконстантная ссылка в Хаскеле — это что-то из области ада (в сравнение с другими языками). А пример qsort'а там вообще просто на загляденье... )))
Quick Sort там, кстати, далёк от оригинального — вместо bidirectional partition Тони Хоара, используется forward partition Нико Ломуто.
Например разница в том, что для массива эквивалентных элементов bidirectional вариант даёт Θ(N*log(N)), а forward — Θ(N^2).
Если же делать bidirectional partition — то код там будет ещё красивее
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Значит мы пишем наши функции всё же монадным способом, а потом пакуем их в копирующие обёртки, с расчётом на то, что оптимизация выкинет эти обёртки на месте стыка.
Это просто потому, что затребованное вами поведение (с многочисленными проходами по одному мутабельному массиву) воспроизводится оптимизациями, описанными в пакете vector для монадического кода. Нелифтнутый код, с иммутабельными массивами оптимизируется так, как я показал выше — там в типичном конвейере будут разные типы промежуточных значений между "стадиями", а значит в общем случае писать в один массив много раз не получится — нужно соединять n проходов в один и тогда уже писать. Поскольку оптимизации это или правила перезаписи в библиотеке или обычный код (в случае плагинов) — реализовать можно разные преобразования и разными способами. Это просто демонстрация того, что компиляторы, оптимизирующие ФП-код, реально существуют, что собственно и требовалось.
_>Т.е. автоматически (обычным красивым кодом) добиться быстродействия в Хаскеле нельзя, но если специально заняться этим вопросом, то руками можно много чего оптимизировать...
Где тут ручная оптимизация и где некрасивый код? Вручную ничего не оптимизировано — наоборот — все автоматически.
_>Ну вообще то одно лишнее копирование всё же есть. Но я понимаю о чём вы — что при 10-и функция будет всё равно это же одно лишнее копирование, а не 10.
Это "лишнее копирование" уйдет точно также как и остальные, когда функция из примера сфъюзится с первоначальным источником массива. Т.е. если вы в хаскельный код даете указатель, то именно этот указатель такая функция и будет двигать и писать в память, на которую он указывает.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Утверждения о проверке только используемого кода на C++ просто некорректны. Обобщенный код, который используется в другом обобщенном коде не проверяется. Библиотеки в которых вообще код только обобщенный, т.е. в случае C++ непроверяемый — распространенное явление для языков с нормальным параметрическим полиморфизмом.
_>Ещё раз, "использование кода" — это генерация из него исполняемого файла.
Нет, "использование кода" — это использование обобщенного кода для написания другого обобщенного кода.
_>Компилятор отвечает исключительно за это и благодаря статической типизации не позволяет проникнуть в исполняемый файл ни одной ошибке такого рода. Заниматься же помощью в написание исходников — это не дело компилятора! Этим может заниматься например IDE или ещё какие-то подобные инструменты.
Непонятно, откуда взялось такое ограничение. Во всех языках с обобщенным программированием (кроме C++ и клонов) именно компилятор является легковесным верификатором кода, в том числе и обобщенного. Если плюсовой компилятор не может этого делать — это проблема именно плюсового компилятора и его пользователей, а не какое-то общее правило для всех компиляторов.
_>Конечно, в C++ и D используется система, позволяющая самые широкие возможности. Ценой за это является отсутствие раздельной компиляции. Ну и ещё местами страшноватый синтаксис и сообщения об ошибках в случае C++.
Трейдофф между раздельной компиляцией и производительностью получаемого кода понятен и уже обсужден — проблема же в том, что обобщенный код не проверяется, хотя никаких препятствий для этого нет (если, конечно, проектировать средства обобщенного программирования типизированными с самого начала — потом без нарушения обратной совместимости добавить ее уже затруднительно) — никакого компромисса между производительностью и типизированностью не нужно, наоборот, от типизированности для производительности одна польза (по крайней мере, пока у нас завтипов нет).
_>Это просто у вас такое понимание типизированности. ) При котором вы хотите чтобы компилятор выполнял не только свою прямую работу, но и служил чем-то типа статического анализатора кода.
Служить статическим анализатором кода — прямая работа компиляторов всех типизированных языков. Компилировать без статического анализа не в рантайме вообще довольно затруднительно, да и мы же вроде не трассирующие JIT-компиляторы бестиповых языков тут обсуждаем?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Где тут ручная оптимизация и где некрасивый код? Вручную ничего не оптимизировано — наоборот — все автоматически.
Мы перешли от обычного задания функций (как было в моём примере, который, как я понимаю, не оптимальный совсем) на монадное. И плюс нам надо конструировать дополнительные обёртки вокруг наших функций, наоборот устраняющие монадность. Это и есть ручная оптимизация.
K>Это "лишнее копирование" уйдет точно также как и остальные, когда функция из примера сфъюзится с первоначальным источником массива. Т.е. если вы в хаскельный код даете указатель, то именно этот указатель такая функция и будет двигать и писать в память, на которую он указывает.
Что-то мне это не очевидно. Я пока понял, что оно оптимизируется только при условие, что в нашу тестовую функцию передаётся результат вызова "new".
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
_>>Ещё раз, "использование кода" — это генерация из него исполняемого файла. K>Нет, "использование кода" — это использование обобщенного кода для написания другого обобщенного кода.
Это уже использование кода человеком, а не компилятором.
K>Непонятно, откуда взялось такое ограничение. Во всех языках с обобщенным программированием (кроме C++ и клонов) именно компилятор является легковесным верификатором кода, в том числе и обобщенного. Если плюсовой компилятор не может этого делать — это проблема именно плюсового компилятора и его пользователей, а не какое-то общее правило для всех компиляторов.
Почему ограничение? ) Если вам хочется включить в свой компилятор какую-то дополнительную функциональность (вот тот же clang ещё много чего умеет, кроме просто компиляции), то никто этого не запрещает. Только не надо тогда называть эту дополнительную возможность типизацией и как следствие считать её обязательной.
K>Трейдофф между раздельной компиляцией и производительностью получаемого кода понятен и уже обсужден — проблема же в том, что обобщенный код не проверяется, хотя никаких препятствий для этого нет (если, конечно, проектировать средства обобщенного программирования типизированными с самого начала — потом без нарушения обратной совместимости добавить ее уже затруднительно) — никакого компромисса между производительностью и типизированностью не нужно, наоборот, от типизированности для производительности одна польза (по крайней мере, пока у нас завтипов нет).
Если мы говорим про C++, то там обобщённый код полностью проверяется, но только на момент использования. На мой взгляд этого более чем достаточно для уверенности в корректности созданного ПО.
K>Служить статическим анализатором кода — прямая работа компиляторов всех типизированных языков. Компилировать без статического анализа не в рантайме вообще довольно затруднительно, да и мы же вроде не трассирующие JIT-компиляторы бестиповых языков тут обсуждаем?
Да, для кода используемого для генерации исполняемого кода. А не для кода, просто лежащего где-то на диске.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Значит вот теория про ST с примерами. После прочтения этого, должно стать очевидным, что неконстантная ссылка в Хаскеле — это что-то из области ада (в сравнение с другими языками).
Перевожу для тех кто читает твои сообщения — "ужос, ужос, ужос" включая "чтото из области ада" есть просто многолетняя привычка к плюсам и основаные на ней эмоции.
>А пример qsort'а там вообще просто на загляденье... )))
Ужос — синтаксис не как в С++
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Перевожу для тех кто читает твои сообщения — "ужос, ужос, ужос" включая "чтото из области ада" есть просто многолетняя привычка к плюсам и основаные на ней эмоции.
Я вообще то много какие языки использую и ещё большее количество знаю. Но нигде, кроме указанного случая, не требуется подобный дикий код для использования банальной ссылки.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Перевожу для тех кто читает твои сообщения — "ужос, ужос, ужос" включая "чтото из области ада" есть просто многолетняя привычка к плюсам и основаные на ней эмоции.
_>Я вообще то много какие языки использую и ещё большее количество знаю. Но нигде, кроме указанного случая, не требуется подобный дикий код для использования банальной ссылки.
Я не вижу там никакого дикого кода, процитируй его сюда пожалуйста
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>ИМХО, Node.js зацепился только за счёт инфраструктуры и рекламы ("buzzwordish"). Ничего особенного там нет, тем более для надёжности. Поначалу даже не предлагалось никакого решения для распутывания лапши callback'ов.
+1.
S>>А для чего вам вечный цикл? EP>Для полноты по Тьюрингу.
А для чего вам полнота по Тьюрингу?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>ИМХО, Node.js зацепился только за счёт инфраструктуры и рекламы ("buzzwordish"). Ничего особенного там нет, тем более для надёжности. Поначалу даже не предлагалось никакого решения для распутывания лапши callback'ов.
В ноде очень простой и понятный апи, нормальная модульная система и функции. От джаваскрипта достается песочница. Все вместе это дает довольно простую и дешовую асинхронщину.
В ноде и не нужно ничего для распутывания колбеков. Это задача языка или модулей. Сейчас всё не хуже, чем в питоне
Cкажем, вот такой пример один к одному перегоняется в джаваскрипт
Здравствуйте, Sinclair, Вы писали:
S>а функции вида A G(B b) лифтятся до Monad<A> G(Monad<B>) в два приёма: сначала строится функция Monad<A> G'(B b) при помощи unit, а уже потом bind.
Это называется fmap.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Контейнеры с функциями как раз попадаются. А вот возврат из нашей функции сразу нескольких замыканий что-то не припомню на практике.
И откуда у вас эти контейнеры с функциями берутся, если вы их не из функций возвращаете?
_>Причём тут метапрограммирование? ) Я про эти вещи говорил.
А причем тут уровни кода тогда? Если речь не о воплощении шаблонов проектирования с помощью каких-то инструментов метапрограммирования.
_>Так они низкоуровневые значит? А что в вашем понимание является высокоуровневым кодом?
Я тут писал по соседству, что высокоуровневый код — это такой код, о строительных блоках которого можно рассуждать как о математических объектах (о функциях как о функциях, например) и извлекать из этого какую-то пользу.
_>Я писал это Ikemefula, который просто не в курсе какая жуть следует за использованием State int вместо int. Вы же прекрасно в курсе о чём речь, просто упорно считаете это нормальным. )))
Ну так покажите всем, как это ненормально. Слева все хорошо, справа "ужас-ужас-ужас". Но вы же упорно не хотите этого делать. И понятно почему, потому что рядом с императивным кодом на большинстве языков монадический код смотрится совсем не страшно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Где тут ручная оптимизация и где некрасивый код? Вручную ничего не оптимизировано — наоборот — все автоматически.
_>Мы перешли от обычного задания функций (как было в моём примере, который, как я понимаю, не оптимальный совсем) на монадное.
Я же объяснил, что это потому, что запрашиваемое вами конкретное поведение (с n-проходов) реально существующая библиотека обеспечивает при оптимизации "монадного" кода, а для остального другое поведение (хотя устранение промежуточных значений тоже происходит и такие преобразования я тоже продемонстрировал). Мы вроде начали с принципиальной возможности таких оптимизаций в реально существующем компиляторе, а теперь оказывается что пока я не напишу библиотеку с какими-то конкретными перламутровыми пуговицами это не засчитывается. Причем, когда я ее напишу, то окажется, что пуговицы опять недостаточно перламутровые и т.д.
_>И плюс нам надо конструировать дополнительные обёртки вокруг наших функций, наоборот устраняющие монадность. Это и есть ручная оптимизация.
Вообще-то это ручная пессимизация в чистом виде. Я вручную создаю лишние копирования, которые компилятор устраняет.
Как раз для того, чтоб это (устранение их компилятором) продемонстрировать.
_>Что-то мне это не очевидно. Я пока понял, что оно оптимизируется только при условие, что в нашу тестовую функцию передаётся результат вызова "new".
И в чем проблема? Почему бы первоначальному источнику не передавать результат обернутый в New?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Нет, "использование кода" — это использование обобщенного кода для написания другого обобщенного кода. _>Это уже использование кода человеком, а не компилятором.
И что? У вас получается замкнутый круг — ненужность проверки кода компилятором вы обосновываете тем, что компилятор код не проверяет. Хотя должен проверять и в большинстве языков проверяет.
_>Почему ограничение? )
Потому, что ограничивает написание обобщенного кода, лишая программиста легковесной верификации написанного им кода, которую обычно компилятор и обеспечивает.
_>Только не надо тогда называть эту дополнительную возможность типизацией и как следствие считать её обязательной.
Не нужно из конкретного дизайнерского просчета авторов C++ выводить какие-то космические правила.
Эта возможность и называется типизацией, и "дополнительной" в типизированном языке не является.
_>Если мы говорим про C++, то там обобщённый код полностью проверяется, но только на момент использования.
Что означает "не проверяется", если воспользоваться общепонятным смыслом слова "используется", а не специальным узким значением только для того и придуманным, чтоб выставить баг фичей.
_>На мой взгляд этого более чем достаточно для уверенности в корректности созданного ПО.
Никогда не было недостатка программистов, которые считают, что проверка типов не нужна.
_>Да, для кода используемого для генерации исполняемого кода. А не для кода, просто лежащего где-то на диске.
Имеет значение как раз то, что вы называете "использование программистом" и соответствующие удобства для программиста, предоставляемые компилятором.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Указатель не исключает иерархичность.
Указатель как абстракция — исключает. Для того, чтоб иерархичность учитывать, такую абстракцию нужно либо "продырявить", чтоб учитывать то, от чего она нас абстрагирует или расширить.
EP>Я про quick sort Тони Хоара, а не про ту пародию которую с гордостью показывают хаскелисты.
Ну пошло-поехало. Что за хаскелисты это с гордостью показывают? (Это не какая-то "пародия на quick sort" кстати, а просто tree sort).
EP>Quick sort это как раз пример сache-oblivious алгоритма.
С каких пор? сache-oblivious сортировка это какие-нибудь разновидности merge-sort вроде funnel sort, например.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>То есть без ленивости трудно делать библиотеки хорошо взаимодействующие друг с другом?
Да, именно так. Это основное обоснование для поддержки ленивости.
Это легковесный способ организовать передачу от компонента B информации в компонент A о том, что именно от компонента A требуется. Т.е. компонент A не делает все что может, а только то, что требуется компоненту B про который A вообще говоря ничего не знает.
EP>Обычно синхронизация для мутабельных данных реально требуется только по периметру модуля, а не по всей площади.
Вообще не понимаю ничего. Какие-то площади и периметры модулей.
EP>Если же вы говорите что ленивость это пища для ФП — то видимо должна использоваться повсеместно, так?
Должна использоваться там, где она нужна. Но для этого придется платить в любом случае.
EP>И соответственно меж-поточная синхронизация разбрасывается по коду только ради самой дорогой абстракции, а не для решения прикладной задачи. Ничего хорошего в этом нет
Это типичный подход для высокоуровневого языка. К примеру, полноценные лямбды требуют нормальный ГЦ, а значит и write barrier при модификации ссылок. Полноценный параметрический полиморфизм и параметризуемые модули требуют боксинг всего (либо рантайм кодогенерацию), за которые тоже приходится платить во многих местах.
EP>"Ручное слияние" это по сути дубликация структуры кода, так? Хотелось бы увидеть пример.
Чем плох пример, с упоминания которого вами же вся эта линия разговора и пошла? Вы уже придумали "аналогичное решение", которое сопоставимо с ленивостью по удобству? Так не стесняйтесь — предъявляйте.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Я про quick sort Тони Хоара, а не про ту пародию которую с гордостью показывают хаскелисты. K>Ну пошло-поехало. Что за хаскелисты это с гордостью показывают?
K>(Это не какая-то "пародия на quick sort" кстати, а просто tree sort).
Это никакой не Tree Sort, это именно пародия на quick sort.
EP>>Quick sort это как раз пример сache-oblivious алгоритма. K>С каких пор? сache-oblivious сортировка это какие-нибудь разновидности merge-sort вроде funnel sort, например.
Quick Sort делит массив на две части (вырезая середину), и продолжает рекурсивно в каждой из частей. Начиная с определённой глубины текущий Range полностью поместится в L3, ещё глубже — L2, потом в L1 и так далее. http://en.wikipedia.org/wiki/Cache-oblivious_algorithm
Most cache-oblivious algorithms rely on a divide-and-conquer approach. They reduce the problem, so that it eventually fits in cache no matter how small the cache is, and end the recursion at some small size determined by the function-call overhead and similar cache-unrelated optimizations, and then use some cache-efficient access pattern to merge the results of these small, solved problems.
А второй фазы ("merge the results") у quick sort нету.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В коде то, что я описал ранее — Lazy<T>, LazyList<T>, каррированные функции и named operator'ы.
Да это понятно.
EP>Код не показываю только потому, что я его не оптимизировал (нет ни времени, ни мотивации), а начинать сравнение скорости 100-строковой реализации vs optimized code мне бы не хотелось.
Так в этом и проблема. В низкоуровневом языке писать высокоуровневый код на практике невозможно. Нет ни времени, ни мотивации. Да и работать с приемлемой скоростью он все равно не будет.
EP>>>Вот только смысла так писать нет — итеративная версия будет и проще и быстрее.
Проще точно не будет. Да и с какой стати итеративная реализация бесконечного списка чисел Фибоначчи будет заметно быстрее?
EP>В том то и дело что нет. И даже нет волшебного рецепта переписывания "итеративного" кода в "подходящий"/"оптимальный".
Ну так о чем речь тогда? Вы отвергаете целый подход к написанию программ как ненужный, потому что какую-то одну программу можете переписать иначе, и получить от этого какой-то выигрыш. Это слабый аргумент. Да и неуместный потому, что (напоминаю в очередной раз) обсуждается не полезность подхода, а инструментальная поддержка подхода.
EP>Именно об этом я и говорю. Нужно знать алгоритмы, нужно знать машину, нужно знать mapping между ними — и только тогда можно получить эффективный код.
А еще можно всего этого не знать и получить код, работающий с приемлемой скоростью в 80% случаев. На что языки высокого уровня, в основном, и ориентированы.
EP>Так уж получилось, что на современные машины ФП код мэппится плохо.
И что? Значит, что отсутствие поддержки ФП засчитывается как хорошая поддержка? Нет? К чему вы опять про это вспомнили тогда?
EP>Да что там машины, многие полезные и практичные алгоритмы плохо мэппятся на чистый ФП (без всяких хаков типа STArray), на ровном месте добавляется логарифмическое penalty к complexity.
Ну конечно, сначала придумываете какой-то специально-ущербный чистый ФП, а потом с ним боретесь. Обосновать, что STArray является хаком сможете? О какой "логарифмическое penalty к complexity" речь идет вообще непонятно. Какой смысл сравнивать структуры данных с несопоставимой функциональностью? Вы без ФП сможете версионность поддерживать с меньшим penalty что ли?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Так есть ведь аналоги. Вместо создания списка, в котором косвенность на косвенности, аллокации и thunk'и — в ряде случаев достаточно обычного плоского массива.
Это на аналог не тянет. Ленивый список это, в первую очередь, не data, а control-structure. Я еще понимаю, какой-нибудь лисповый loop-комбайн или континуации рассматривать как аналоги, но плоский массив — это не смешно даже.
Напоминаю еще раз постановку вопроса:
Вот когда предоставите для сравнения control-structure для связывания комбинаторов с комбинаторами с аналогичной функциональностью (поддержка раннего завершения, циклов, автомемоизации, потокобезопасность и т.д.) тогда и сравним.
EP>Ленивые вычисления — реализуются, UFP — решена. И да, использовать эти средства везде — нет смысла. В тех местах где performance penalty допустима, и если эти средства действительно дают преимущества — то их нужно использовать.
Ну так performance penalty за вашу "поддержку" (тормозная ленивость, счетчики ссылок с утечками из-за циклических ссылок и т.д.) гораздо выше, чем в высокоуровневом языке. Т.е. performance penalty у вас получается неприемлема практически везде, использовать никто и нигде не будет (ну, кроме как для споров на форуме). Если это и понимается, когда декларируется, что поддержка есть — все понятно.
EP>Если же вся программа целиком будет состоять только из дорогих ФП элементов, то действительно лучше взять язык заточенный под это EP>Нужны где? По всему коду?
Не обязательно вся программа — достаточно заметных масштабов использования.
EP>Функции высшего порядка и first-class functions: мощная и полезная вещь.
В моем минимум списке, собственно, только этот пункт и есть, и даже тут у C++ все плохо из-за того что UFP не решено.
EP>Referential transparency: см. STL.
И где там Referential transparency? Или тут опять какой-то местечковый термин?
EP>Замыкания: удобны, особенно при захвате большого количества переменных.
Это подразумевается в пункте про первоклассные функции.
EP>И это всё бесплатно, или крайне дёшево (зависит от компилятора) — так как всё прекрасно inline'ится.
Нет, это все не бесплатно. Первоклассность функций требует ГЦ, поддержку карринга от рантайма, ленивость (опять таки с поддержкой от рантайма и компилятора) для того, чтоб можно было нормально комбинировать функции.
Если еще и поддержку рекурсии добавить, к ленивости, которая уже затребована, прибавится стек в куче, а для полиморфной рекурсии — боксинг всего.
Т.е. никаких чудес, за функции платим по полной программе, как приходится платить в ФЯ (за большую часть перечисленного).
Какое-то подобие нормальной поддержки первоклассных функций реализуется относительно дешево, чем бледнее подобие — тем дешевле — тут все достаточно интуитивно.
EP>Где-то наверху в calltree, можно использовать какие-то дорогие штуки, но не нужно разбрасывать их по всему коду без необходимости.
Это как раз подход низкоуровневых языков, который я рассматривал в сравнении с высокоуровневыми. Логика такая:
1) Дорогие штуки используем тогда, когда стоимость не имеет значение.
2) Раз стоимость значения не имеет — ничего для поддержки не делаем. Пусть работает медленно — какая разница?
3) Ставим галочку — все поддерживается, проблема решена!
4) Язык распадается на два подмножества "фортран" для написания кода, который имеет значение и "скрипт" для клеевого кода и споров на форумах.
5) На самом деле, мест где стоимость совсем не имеет значения довольно мало, такой код пишется редко, "Высокоуровневый" код либо с самого начала не пишется, либо пишется под переписывание в дальнейшем. Мотивация писать "высокоуровневый" код слабая, это напрасная трата времени — все равно же переписывать в идиоматическом для данного языка стиле придется.
6) "Высокоуровневый" код пишется только на форумах, чтоб доказывать полноценность языка. Но какая разница? Для галочки-то все есть.
Высокоуровневый язык должен поддерживать дорогие фичи настолько хорошо, чтоб ими действительно можно было пользоваться и делать настолько быстрыми, насколько это возможно. В этом и отличие.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И откуда у вас эти контейнеры с функциями берутся, если вы их не из функций возвращаете?
Ну так это же не ФЯ с его ограничениями на иммутабельность — мы можем создавать что угодно, не только возвращая значения из функций. )
K>А причем тут уровни кода тогда? Если речь не о воплощении шаблонов проектирования с помощью каких-то инструментов метапрограммирования.
Шаблоны проектирования прекрасно реализуются и без всякого МП, так что оно собственно тут ни при чём. Так вот, возвращаясь к шаблонам проектирования... Это разве на ваш взгляд не абстракции достаточно высокого уровня?
K>Я тут писал по соседству, что высокоуровневый код — это такой код, о строительных блоках которого можно рассуждать как о математических объектах (о функциях как о функциях, например) и извлекать из этого какую-то пользу.
Интересное определение, но я не очень понял один нюанс. Правильно ли я понимаю, что мы таким определением очень сильно сужаем область даже теоретической возможности написания высокоуровневого кода?) Т.е. что этот термин (в таком определение) становится применим только к небольшой области ПО. Или же, если здесь не подразумевается подобного сужения (т.е. считаем что любую задачку можно решить высокоурвневым кодом), то хотелось бы увидеть примеры подобных математических объектов. Вот например возьмём такое общеизвестное простейшее приложение как "Блокнот". Из каких математических объектов он будет состоять, если мы его реализуем по высокоуровневому? )
K>Ну так покажите всем, как это ненормально. Слева все хорошо, справа "ужас-ужас-ужас". Но вы же упорно не хотите этого делать. И понятно почему, потому что рядом с императивным кодом на большинстве языков монадический код смотрится совсем не страшно.
Нуну)
Возьмём например такой простейший код, работающий через константные ссылки:
prepare :: Array Int Int -> Array Int Int
prepare а = а//[(1, а!1*а!1)]
test :: Array Int Int -> Int
test а = let r=prepare а
in sum $ elems r
main = print $ test $ listArray (0, length l -1) l
where l= [1, 2, 3]
Он конечно не оптимальный, но для массивов в 3 элемента без разницы. Его прямым аналогом на C++ будет что-то вроде:
auto prepare(const vector<int>& a)
{
vector<int> r=a;
r[1]=r[1]*r[1];
return r;
}
auto test(const vector<int>& a)
{
auto r=prepare(a);
return accumulate(r.cbegin(), r.cend(), 0);
}
int main(){cout<<test({1, 2, 3});}
Как видно, он является практически точной копией. Разве что копирования массива в C++ задаётся явно, а создание массива реализовано удобнее. Но это всё мелочи, а семантически код одинаков.
А теперь предположим, что нам захотелось переделать это под неконстантные ссылки. Кстати, вполне реальная задачка, если у нас массив не из 3-ёх элементов, а из 3*10^9. На C++ это станет выглядеть так:
void prepare(vector<int>& a){a[1]=a[1]*a[1];}
auto test(vector<int>&& a)
{
prepare(a);
return accumulate(a.cbegin(), a.cend(), 0);
}
int main(){cout<<test({1, 2, 3});}
Видно, что код практически не изменился по своей структуре, а стал только проще — просто стёрли лишнее.
Ну и теперь полюбуемся, как будет выглядеть что-то подобное на Хаскеле:
prepare :: STArray s Int Int -> ST s ()
prepare a = do
x <- readArray a 1
writeArray a 1 (x*x)
test :: STArray s Int Int -> ST s Int
test a = do
prepare a
l <- getElems a
return $ sum l
main = print $ runST $ do
let l=[1, 2, 3]
a <- newListArray (0, length l -1) l :: ST s (STArray s Int Int)
test a
И это ещё в лучше случае, если getElems в реальности создаёт ссылку, а не выделяет память (я просто не в курсе таких тонкостей). А если getElems выделяет память, то её использовать нельзя и придётся ещё самим писать новую версию sum, которая умеет работать с типом STArray s Int Int.
Но даже если забыть про этот момент, то в целом видно, что изначальный хаскельный код при переходе к монадному (который необходим для существования неконстантных ссылок) изменился до неузнаваемости. Причём код не просто полностью изменился, а стал заметно страшнее — смысловая часть в нём погребена под кучей монадного синтаксического мусора.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
K>>Я тут писал по соседству, что высокоуровневый код — это такой код, о строительных блоках которого можно рассуждать как о математических объектах (о функциях как о функциях, например) и извлекать из этого какую-то пользу. _>Интересное определение, но я не очень понял один нюанс. Правильно ли я понимаю, что мы таким определением очень сильно сужаем область даже теоретической возможности написания высокоуровневого кода?) Т.е. что этот термин (в таком определение) становится применим только к небольшой области ПО. Или же, если здесь не подразумевается подобного сужения (т.е. считаем что любую задачку можно решить высокоурвневым кодом), то хотелось бы увидеть примеры подобных математических объектов. Вот например возьмём такое общеизвестное простейшее приложение как "Блокнот". Из каких математических объектов он будет состоять, если мы его реализуем по высокоуровневому? )
Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу.
Даже об инструкциях императивного языка можно рассуждать как о математических объектах. Например так, как делал Tony Hoare — Hoare Triple.
Или так как делает Александр Степанов. Например в STL — в ISO вполне математически описаны концепции с аксиомами. Или в его Elements of Programming — вводятся определения концепций, аксиомы, из которых выводятся леммы и теоремы, на основе которых строятся эффективные алгоритмы для современных машин.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Я же объяснил, что это потому, что запрашиваемое вами конкретное поведение (с n-проходов) реально существующая библиотека обеспечивает при оптимизации "монадного" кода, а для остального другое поведение (хотя устранение промежуточных значений тоже происходит и такие преобразования я тоже продемонстрировал). Мы вроде начали с принципиальной возможности таких оптимизаций в реально существующем компиляторе, а теперь оказывается что пока я не напишу библиотеку с какими-то конкретными перламутровыми пуговицами это не засчитывается. Причем, когда я ее напишу, то окажется, что пуговицы опять недостаточно перламутровые и т.д.
Что-то я не понял, что вы тут хотели сказать. Что описываемую задачку можно решить без монадного кода? ) Если можно, то тогда с удовольствием посмотрю на это... Если же нельзя, то тогда в чём претензии к моим комментариям? )
K>Вообще-то это ручная пессимизация в чистом виде. Я вручную создаю лишние копирования, которые компилятор устраняет. K>Как раз для того, чтоб это (устранение их компилятором) продемонстрировать.
А что, без этих "лишних копирований" можно обойтись что ли? ) Как мы без них получим нормальные (не монадные) хаскельные функции? )
K>И в чем проблема? Почему бы первоначальному источнику не передавать результат обернутый в New?
Ну так мало ли откуда там идёт тот внешний буфер — далеко не факт, что он прямой результат new. А если делать дополнительную обёртку, то всё равно получим то самое копирование.
Кстати, в реальности (изначальная задачка то из вполне реальной области была) там это выглядит так: первичный буфер предоставляет ОС, вызывая наш код 30 раз в секунду и передавая нам при этом указатель. Так вот на C++ естественно без проблем делается такая обработка вообще без выделения памяти — и внутри обработки одного кадра (про что и был код выше) и между кадрами. А как тут у Хаскеля дела? )
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>На мой взгляд этого более чем достаточно для уверенности в корректности созданного ПО. K>Никогда не было недостатка программистов, которые считают, что проверка типов не нужна.
Утомил меня этот наш бестолковый спор о терминах. Вы пытаетесь цепляться за придуманные вами же определения и не обращаете внимания на смысл вообще.
Предлагаю простейшее разрешение вопроса. Раз вы считаете, что шаблоны C++ нетипизированные, то тогда просто приведите ровно один любой пример, в котором из-за этой нетипизированности будет создаваться некорректно работающее ПО. Ну и естественно Хаскель (как пример вроде как типизированного) для того же случая не должен позволять создать некорректное ПО.
Если покажете такой пример, то я признаю что ошибался и что в C++ шаблоны нетипизированные. Ну а если нет, то значит что вы всё время тут говорили ерунду.
P.S. Для динамических языков (того же питона например) я легко могу показать подобные примеры.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В ноде очень простой и понятный апи, нормальная модульная система и функции. От джаваскрипта достается песочница. Все вместе это дает довольно простую и дешовую асинхронщину.
Ты вот всё время акцентируешь на этом внимание... В то время как в реальности действительная польза от асинхронного кода есть только на крайне узком спектре задач. Обычно что-то вроде сервера, обрабатывающего тысячи одновременных запросов. А в большинстве обычных задач, классический синхронный код является не менее эффективным (а в случае числа потоков около числа ядер процессора, скорее даже более эффективным). При этом являясь более удобным и лаконичным. Кстати, это видно даже по твоему любимому await из C# — вся его основная "крутизна" заключена в том, что он создаёт видимость синхронного кода, являясь при этом асинхронным. Т.е. уже даже из этого очевидно какой код удобнее в реальности.
Так что твой частый аргумент про "простую и дешовую асинхронщину" весьма сомнителен в большинстве случаев. Хотя если говорить именно про node.js, то на нём как раз частенько пытаются делать приложения из той узкой области, где асинхронный код может быть реально полезен... )
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В ноде очень простой и понятный апи, нормальная модульная система и функции. От джаваскрипта достается песочница. Все вместе это дает довольно простую и дешовую асинхронщину.
_>Ты вот всё время акцентируешь на этом внимание... В то время как в реальности действительная польза от асинхронного кода есть только на крайне узком спектре задач. Обычно что-то вроде сервера, обрабатывающего тысячи одновременных запросов.
Под это определение подойдут практически все серверные решения
>А в большинстве обычных задач, классический синхронный код является не менее эффективным (а в случае числа потоков около числа ядер процессора, скорее даже более эффективным).
Все гораздо проще — есть задачи, где больше вычислений. Есть задачи, где больше IO. Node.js нужен для второго случая. Это и ежу ясно — Джаваскрипт медленее С++ и даже шарпа с джавой. Асинхронщина в задачах где больше всего IO есть не потому что Node, а потому что IO.
_>Так что твой частый аргумент про "простую и дешовую асинхронщину" весьма сомнителен в большинстве случаев.
Я про все случаи и не говорил, это под твое определение подходят все случаи серверных решений.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
То есть, в кратце, тебя смущают не страхи в Хаскеле, которых ты не смог показать, а всего-то
1 если писать на XXX, как на YYY, то получается многословный код.
2 изменение состояния на функциональном языке дает многословный код
Хаскель не С++ — ужос !
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу.
Теоретически. Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется.
Отсюда ясно, что уровень языка нужно определять через количеством умозаключений, которые надо нагородить, что бы решать задачи абстрагируюясь от аппаратных и прочих особенностей.
Например, рассуждая скажем о строительных блоках в виде ассемблерных команд, до решения типичной задачи как правило мало кто доходит а для сложных задач решения вообще никогда не бывает.
Скажем, что бы написать быструю сортировку на ассемблере, надо очень, очень долго думать.
На С++ думать надо меньше, но все равно очень много относителя Хаскеля.
А вот Хаскель будет лидер из трех этих примеров, без шансов. (Тут кто нибудь из плюсовиков почти наверняка не согласится)
Т.е. высокоуровневый, это такой который легко позволяет оперировать абстракциями, а не конкретными особенностями аппаратной платформы. Очевидно, это никак не связано с быстродействием.
Если привязаться к железу и поменять условие, например управлять микроконтром обращаясь к нему через его порты, то, внезапно, всех порвёт ассемблер, а на других языках такая задача не решается, потому что в порты они писать не умеют, им понадобится помощь собтсвенно этого самого ассемблера.
А если смапить порты на память, то, внезапно, всех порвёт С++, который умеет легко менять состояние.
Очевидно, из этого не следует, что Ассемблер или С++ иногда становятся высокоуровневыми языками. Это значит, что они легко используются в конкретных случаях, а ассемблер будет самым быстродейственным, т.к. быстродействие там где ближе всего к железу.
Теоретически, компиляторы С++ создают код, который невозможно написать таким же быстрым но руками на ассемблере. Парадокс в том, что любую такую программу можно ускорить парочкой локальных финтов на ассемблере.
Это следует из того, что
1. компилятр пишут люди
2. компилятор всего лишь слепок текущих представлений, а не кладезь абсолютной истины
Пример — можно легко устранить лишние вызовы функций заменив их на переходы. Или инлайнить виртуальные вызовы, про которые ни у компилятора ни у линкера нет полноты сведений для принятия решения.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Предлагаю простейшее разрешение вопроса. Раз вы считаете, что шаблоны C++ нетипизированные, то тогда просто приведите ровно один любой пример, в котором из-за этой нетипизированности будет создаваться некорректно работающее ПО.
Это некорректное сравнение. Динамика означает, что всякие проверки переносятся на момент вызова или не выполняются вообще. Корректно ли будет ПО дело десятое. Где у нас вызов шаблонов С++ ? Правильно, при конкретном использовании.
Скажем, в джаваскрипте можно вообще написать мусор, но софт будет абсолютно корректно работать. Из этого, представь, не следует, что джаваскрипт вдруг стал статически типизированым.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу. I>Теоретически.
Я привёл конкретные примеры.
I>Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется.
Вот выше был пример Fibonacci numbers через fix — ты сможешь объяснить его ребёнку? Зато обычная итеративная версия и проще и быстрее.
I>Отсюда ясно, что уровень языка нужно определять через количеством умозаключений, которые надо нагородить, что бы решать задачи абстрагируюясь от аппаратных и прочих особенностей. I>Например, рассуждая скажем о строительных блоках в виде ассемблерных команд, до решения типичной задачи как правило мало кто доходит а для сложных задач решения вообще никогда не бывает.
Неверно. Из ассемблерных команд делают блоки побольше, которые собирают ещё более в крупные блоки и т.п.
И это так везде, даже в ФП — из маленьких блоков собирают побольше и т.п.
And then in the beginning of 1976 I had my first revelation: the ideas of the Structured Programming had nothing to do with the language. One could write beautiful code even in assembly. And if I could, I must. (After all I reached the top of the technical ladder and had to either aspire to something unattainable or go into management.) I decided that I will use my new insight while doing my next project: implementing an assembler. Specifically I decided to use the following principles:
...
The result of my experiment was quite astonishing. The code did not contain serious bugs. There were typos: I had to change AND to OR, etc. But I did not need patches. And over 95% of the code was in general functions! I felt quite proud. There remained a problem that I could not yet precisely figure out what it meant that a function was general. As a matter of fact, it is possible to summarize my research over the next 30 years as an attempt to clarify this very point.
I>Скажем, что бы написать быструю сортировку на ассемблере, надо очень, очень долго думать. I>На С++ думать надо меньше, но все равно очень много относителя Хаскеля. I>А вот Хаскель будет лидер из трех этих примеров, без шансов. (Тут кто нибудь из плюсовиков почти наверняка не согласится)
Конечно не согласится — то убожество которое гордо демонстрируют Хаскелисты это не Quick Sort.
Адекватные Хаскилсты даже явно говорят, что это не Quick Sort Тони Хоара, например Erik Meijer (28:25).
Если же пытаться сделать нормальный Quick Sort на Haskell — то получается крайне убого и на порядок сложнее (alex_public выше приводил ссылку, и то — там до нормального quick sort с bidirectional partition ещё далеко).
Зато если делать на C++ как в Haskell (то есть медленно и не Quick Sort) — то код получится очень похожим, только смысла в этом нет.
I>Т.е. высокоуровневый, это такой который легко позволяет оперировать абстракциями, а не конкретными особенностями аппаратной платформы.
Конкретные модели абстракций на чём будешь реализовывать?
I>Очевидно, из этого не следует, что Ассемблер или С++ иногда становятся высокоуровневыми языками.
Очевидно, что из этого не следует и обратное. То есть не следует ни то, ни другое — к чему вообще тогда пример?
I>Пример — можно легко устранить лишние вызовы функций заменив их на переходы. Или инлайнить виртуальные вызовы, про которые ни у компилятора ни у линкера нет полноты сведений для принятия решения.
Если во время написания кода ты знаешь что есть возможность инлайнинга, то ты сможешь заинлайнить даже на C# — для этого ассемблер не нужен.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, в кратце, тебя смущают не страхи в Хаскеле, которых ты не смог показать, а всего-то I>1 если писать на XXX, как на YYY, то получается многословный код.
При такой логике и брейнфак легко становится идеальным языком... )
I>2 изменение состояния на функциональном языке дает многословный код
А вот и нет. Если мы глянем на тот же Ocaml и многие другие ФЯ, то там подобной ереси нет.
I>Хаскель не С++ — ужос !
Вообще то там было скорее показано, что "монадный хаскель" — это не хаскель. Хотя в сравнение "монадный хаскель" vs. C++ расклад оказался даже ещё хуже.
А вот против классического красивого Хаскеля никто ничего и не говорил. Ну за исключением того, что подобных Хаскель можно увидеть только в академических примерах, а во всех реальных приложениях почти весь код занимают гигантские монады.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Под это определение подойдут практически все серверные решения
_>Совсем нет. И тот факт, что Apache занимает большую часть рынка, как раз это и подтверждает.
Все. Любой сервер предполагает тысячи одновременно приходящих запросов. Ну разве кроме самопального, для hello world
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Теоретически. Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется. I>Отсюда ясно, что уровень языка нужно определять через количеством умозаключений, которые надо нагородить, что бы решать задачи абстрагируюясь от аппаратных и прочих особенностей.
Сомнительно. Вот допустим мы возьмём некую узкую предметную область (и кстати совсем не завязанную на железо или быстродействие) и ассемблер. Напишем на нём мощный фреймворк (да, это будет нам дорого стоить) под нашу предметную область. А вот теперь посмотрим на работу пользователя нашего фреймворка! Думаю она будет очень высокоуровневая, хотя он и будет вроде как работать на ассемблере...
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это некорректное сравнение. Динамика означает, что всякие проверки переносятся на момент вызова или не выполняются вообще. Корректно ли будет ПО дело десятое. Где у нас вызов шаблонов С++ ? Правильно, при конкретном использовании.
Что значит "корректность ПО дело десятое", если вообще смысл всех этих типизаций как раз в гарантиях отсутствия определённого класса ошибок? ) Если нам наплевать на корректность, то вообще не нужна никакая типизация в языке.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу. I>>Теоретически.
EP>Я привёл конкретные примеры.
Если ты не заметил, я их и не оспариваю, более того, я с ними абсолютно согласен.
I>>Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется.
EP>Вот выше был пример Fibonacci numbers через fix — ты сможешь объяснить его ребёнку? Зато обычная итеративная версия и проще и быстрее.
Для кого проще ? Ты внятно ответь сначала и расскажи, что ты под простотой-сложностью понимаешь.
Если человек не знаком с программированием, то приседания с переприсваиванием ему чужды. А вот функциональная запись это именно то, чем он занимался в школе. Формулы он умеет писать с 4го класса, с 9го он знает что такое производная, с 10го — интеграл.
Вот на такой базе ему можно объяснить очень многое. А вот твои переприсваивания совершенно не ясно как объяснить, потому что это принципиально другая область — организация вычислений, а не сами вычисления. То есть, делегирование вычислений кому то другому, а не сами вычисления.
А вот если минимально научить его программированию, то, внезапно, станет наоборот — проще понять итерационную версию, потому что он руками сможет проделать ту работу, которую делает процессор.
I>>Отсюда ясно, что уровень языка нужно определять через количеством умозаключений, которые надо нагородить, что бы решать задачи абстрагируюясь от аппаратных и прочих особенностей. I>>Например, рассуждая скажем о строительных блоках в виде ассемблерных команд, до решения типичной задачи как правило мало кто доходит а для сложных задач решения вообще никогда не бывает.
EP>Неверно. Из ассемблерных команд делают блоки побольше, которые собирают ещё более в крупные блоки и т.п.
Это теория. А практика говорит о том, что на ассемблере адски сложно писать и еще сложнее читать код. Отсюда понятно, что в основной массе ассемблерный код это небольшие функции, бутстрапы и тд. Есть конечно исключения, но в основном неоправданое применение, из любви к искусству.
Объяснение простое — нет в ассеблере возможности оперировать только высокоуровневыми блоками. Ассемблер тебя жостко ограничивает — придется продираться черз конструкции типа "локальная переменная", "параметр". В итоге внимание тупо распыляется.
Даже больше — любой язык не дает возможности использовать только высокоуровневые конструкции. Отсюда синтаксический шум/мусор и проблемы с читабельностью кода.
Собтсвенно возможности наименьших блоков уже неплохо характеризуют уровень языка.
EP>И это так везде, даже в ФП — из маленьких блоков собирают побольше и т.п.
1 Высота вот этой иерархии "блоков" на ассемблере несравнимо выше чем в любом высокоуровневом языки.
2 Количество такого мусора в реальной программе превосходит любые ожидания
В ФП тебе не надо конструировать блок "локальная переменная" или "передать параметр" или даже "функция"
I>>На С++ думать надо меньше, но все равно очень много относителя Хаскеля. I>>А вот Хаскель будет лидер из трех этих примеров, без шансов. (Тут кто нибудь из плюсовиков почти наверняка не согласится)
EP>Конечно не согласится — то убожество которое гордо демонстрируют Хаскелисты это не Quick Sort. EP>Адекватные Хаскилсты даже явно говорят, что это не Quick Sort Тони Хоара, например
Квик сорт это уже давно не конкретный алгоритм, а семейство алгоритмов. Если для тебя это принципиально, то рассмотрим общий случай сортировки. Тебе, вероятно, известен алгоритм сортировки на Си в одну строчку ?
I>>Т.е. высокоуровневый, это такой который легко позволяет оперировать абстракциями, а не конкретными особенностями аппаратной платформы.
EP>Конкретные модели абстракций на чём будешь реализовывать?
Ни на чем, меня интересует только факт решения, он и показывает уровень языка. Свойства решения, как быстродействие, это уже конкретная реализация. Про это я написал отдельно.
I>>Очевидно, из этого не следует, что Ассемблер или С++ иногда становятся высокоуровневыми языками.
EP>Очевидно, что из этого не следует и обратное. То есть не следует ни то, ни другое — к чему вообще тогда пример?
Еще раз — язык нужен для людей. Процессору он не нужен. Представь себе эдакого Всемогутора, который может любую задачу любой сложности решить за 0 времени.
Вопрос — на кой ляд ему какой то язык ? Он прямо в машинных кодах за 0 времени навернёт решение любой сложности.
Отсюда очевидно, что уровень языка относится к особенностям психики человека, и я показал, что нужно отталкиваться от количества тех самых блоков про которые ты сказал.
Скажем, что бы писать на асме как в ФП или как в С++, надо нагородить не одну тысячу паттернов и очень четко знать и представлять свойства каждого из них. То есть, уже трудозатраты, как минимум по заучиванию всех таких вещей — не один год надо потратить, что бы писать на асме без ошибок.
Паттерны нужно не только записвать, но и распознавать. То есть, всё гораздо интереснее, ведь программы больше читают, чем пишут.
В итоге ассемблер это вагон трудозатрат на ровно месте в ЯВУ это достается почти что даром.
I>>Пример — можно легко устранить лишние вызовы функций заменив их на переходы. Или инлайнить виртуальные вызовы, про которые ни у компилятора ни у линкера нет полноты сведений для принятия решения.
EP>Если во время написания кода ты знаешь что есть возможность инлайнинга, то ты сможешь заинлайнить даже на C# — для этого ассемблер не нужен.
Если непонятно, я сказал, что на ассемблере можно локально создать код лучший, чем может выдать компилятор. При чем любой, сколь угодно умный компилятор. Переписывание программы на Си никак не говорит о разнице в быстродейтсвии генеренного кода и кода на асме. Если ты хочешь сравнить быстродействие генеренного кода от самого умного компилятора и кода на асме, то надо сравнивать генереный код и рукописный. Сгенерировали, улучшили на асме локально — профит. Не получилось улучшить — асм сосёт. Но ведь улучшить то всегда можно ? Опаньки.
Теперь фокус — генеренным кодом будет улучшать код на асме. Для этого нужно написать небольшой кусочек кода на асме используя фичи который в компилере еще не заимплементили. Опаньки, а улучшить то нельзя.
Следовательно генереный код сливает рукописному.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Это некорректное сравнение. Динамика означает, что всякие проверки переносятся на момент вызова или не выполняются вообще. Корректно ли будет ПО дело десятое. Где у нас вызов шаблонов С++ ? Правильно, при конкретном использовании.
_>Что значит "корректность ПО дело десятое", если вообще смысл всех этих типизаций как раз в гарантиях отсутствия определённого класса ошибок? ) Если нам наплевать на корректность, то вообще не нужна никакая типизация в языке.
Ну тогда тебе остаётся признать, что Джаваскрипт это статически типизированый язык
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Сомнительно. Вот допустим мы возьмём некую узкую предметную область (и кстати совсем не завязанную на железо или быстродействие) и ассемблер. Напишем на нём мощный фреймворк (да, это будет нам дорого стоить) под нашу предметную область. А вот теперь посмотрим на работу пользователя нашего фреймворка! Думаю она будет очень высокоуровневая, хотя он и будет вроде как работать на ассемблере...
А что значит "мощный" ? Определи этот термин.
Чтобы доказать, что это не будет высокоуровневая работа, необходимо и достаточно показать, что
1 в таком фремворке есть нечто, от чего можно избавить без потери эффективности, продуктивности и тд и тд, это необходимо
2 отсутствует нечто, чего дает эффективность, продуктивность и тд и тд. — необходимо
3 показать, что существует нечто, что даст и эффективность и продуктивность при избавлении от п.1 — необходимо и достаточно
Итого
От примитивов типа "паттерн передать аргумент", "паттерн почистить стек" , "паттерн возвращаемое значение" ты никуда не уйдёшь.
Если врапнуть этот фремворк в С++, т.е. всего то описать экспорт функций и структур данных, то, внезапно, пользователю не надо будет думать о том, кто чистит стек, как передавать аргументы и по какому смещению находится возвращаемое значение.
На том же С++ пользователь сможет взять любой из интсрументов, например обобщенное программирование, и сделать такую композицию, которую на ассемблере надо отлаживать дольше, чем пишется сам фремворк.
Опаньки !
1 работа пользователя фремворка оказалась не такой уж высокоуровневой
2 есть инструмент который повыше уровнем
Как то так
P.S. Писать на ассемблере и не завязываться на железо это сильно. Регистры, стек, флаги, порты — куда это все девать ?
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>То есть, в кратце, тебя смущают не страхи в Хаскеле, которых ты не смог показать, а всего-то I>>1 если писать на XXX, как на YYY, то получается многословный код.
_>При такой логике и брейнфак легко становится идеальным языком... )
Нет, не становится.
I>>2 изменение состояния на функциональном языке дает многословный код
_>А вот и нет. Если мы глянем на тот же Ocaml и многие другие ФЯ, то там подобной ереси нет.
Конкретно такой может и нет, но есть другая. И вообще, все эти ФЯ по сравнению с Хаскелем сильно вряд ли ФЯ Так, гибриды.
I>>Хаскель не С++ — ужос !
_>Вообще то там было скорее показано, что "монадный хаскель" — это не хаскель. Хотя в сравнение "монадный хаскель" vs. C++ расклад оказался даже ещё хуже.
Если уж сравнивать монадный хаскель с С++, то надо обязательно посмотреть на ко-монады.
_>А вот против классического красивого Хаскеля никто ничего и не говорил. Ну за исключением того, что подобных Хаскель можно увидеть только в академических примерах, а во всех реальных приложениях почти весь код занимают гигантские монады.
Я полистал книгу по Yesod и с тобой не согласен.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется. EP>>Вот выше был пример Fibonacci numbers через fix — ты сможешь объяснить его ребёнку? Зато обычная итеративная версия и проще и быстрее. I>Для кого проще ? Ты внятно ответь сначала и расскажи, что ты под простотой-сложностью понимаешь. I>Если человек не знаком с программированием, то приседания с переприсваиванием ему чужды. А вот функциональная запись это именно то, чем он занимался в школе. Формулы он умеет писать с 4го класса, с 9го он знает что такое производная, с 10го — интеграл. I>Вот на такой базе ему можно объяснить очень многое. А вот твои переприсваивания совершенно не ясно как объяснить, потому что это принципиально другая область — организация вычислений, а не сами вычисления. То есть, делегирование вычислений кому то другому, а не сами вычисления.
Проще для всех — есть тысячи примеров императивщины, как в школе, так и в повседневной жизни:
Детский конструктор с пошаговой инструкцией как собрать конкретную модель. Да хоть то же оригами.
Карточные игры, или например пасьянсы — сплошное мутирование с императивщиной. Кстати, я когда в 12 лет изучал сортировку (императивную!) — для наглядности использовал карты.
Работа с бытовой техникой.
Кухонные рецепты.
Я помню как в первом классе мы рисовали различные фигуры: поставим точку в определённую точку, а дальше учитель говорит (императивно!) куда и сколько клеток прочертить.
Алгоритмы описанные в книге Liber Abaci Леонарда Пизанского (aka Фибоначчи) учат в первых классах: сложение, умножение и т.п.
Начала Евклида — книга по которой учат геометрию почти 2300 лет. В дословном переводе первые три постулата отличаются от того, как нас учат в школе "через две точки можно провести прямую ...". Например перевод Sir Thomas Heath:
Let the following be postulated:
1. To draw a straight line from any point to any point.
2. To produce a finite straight line continuously in a straight line.
3. To describe a circle with any centre and distance.
Это же процедуры в чистом виде, которые изменяют глобальное состояние. Далее, на основе этих процедур строятся более крупные:
Proposition 1.
On a given finite straight line to construct an equilateral triangle.
Лабораторные работы по физике, химии и т.п.
Вот, кстати, наглядная сортировка с мутированием. Попробуй изобрази функциональный аналог с cons'ами.
I>А вот если минимально научить его программированию, то, внезапно, станет наоборот — проще понять итерационную версию, потому что он руками сможет проделать ту работу, которую делает процессор.
Люди с самого детства взаимодействуют с миром императивно, мутируя какие-либо состояния, выполняя последовательности действий — это более естественно чем ФП. Вот хотя бы попробуй описать рыбалку.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Вот на такой базе ему можно объяснить очень многое. А вот твои переприсваивания совершенно не ясно как объяснить, потому что это принципиально другая область — организация вычислений, а не сами вычисления. То есть, делегирование вычислений кому то другому, а не сами вычисления.
EP>Проще для всех — есть тысячи примеров императивщины, как в школе, так и в повседневной жизни:
У меня ощущение, что ты читаешь мои сообщения пяти- или десятилетней давности и берешь идеи оттуда.
Вычисления и программирование оных это две большие разницы. Было бы по твоему, то без малого все бы умели программировать хоть чуть-чуть. А этого не происходит — смотри на ЗП разработчиков и их количество в общей массе.
Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи. А просто объяснить функцию Фибоначчи не нужны никакие вычислители, формулу нарисовал и всё.
Более того, этот человек сможет проверить её же в Экселе том же, на раз. К программированию это не приблизит, но фибоначчи объяснить вполне получится.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Вот на такой базе ему можно объяснить очень многое. А вот твои переприсваивания совершенно не ясно как объяснить, потому что это принципиально другая область — организация вычислений, а не сами вычисления. То есть, делегирование вычислений кому то другому, а не сами вычисления. EP>>Проще для всех — есть тысячи примеров императивщины, как в школе, так и в повседневной жизни: I>У меня ощущение, что ты читаешь мои сообщения пяти- или десятилетней давности и берешь идеи оттуда.
lolwut?
I>Вычисления и программирование оных это две большие разницы.
Я в первую очередь и говорю про понимание написанного.
I>Было бы по твоему, то без малого все бы умели программировать хоть чуть-чуть.
Тем не менее, непосредственно программирование тоже встречается в повседневной жизни — разве трудно составить рецепт, или например описание маршрута?
I>А этого не происходит — смотри на ЗП разработчиков и их количество в общей массе.
Во-первых программирование помимо описания последовательности действий требует абстрактного мышления, тягу к математике — без них можно программировать, но результат будет посредственным.
Во-вторых для программирования нужна тяга к машинам, и какая-никакая интровертность. То есть программистов мало не потому что трудно, а потому что далеко не всем интересно.
I>Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи.
Ему не нужна модель вычислителя — у него вычислитель уже есть в голове.
Итеративную версию чисел Фибоначчи можно элементарно объяснить ребёнку даже если он не умеет складывать числа — с помощью линейки и циркуля.
I>А просто объяснить функцию Фибоначчи не нужны никакие вычислители, формулу нарисовал и всё. I>Более того, этот человек сможет проверить её же в Экселе том же, на раз. К программированию это не приблизит, но фибоначчи объяснить вполне получится.
Попробуй объяснить вот этот "идиоматичный ФП" код ребёнку:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Вычисления и программирование оных это две большие разницы.
EP>Я в первую очередь и говорю про понимание написанного.
Начинать объяснять любой итерационный алгоритм можно не раньше, чем человек поймет сам вычислитель.
I>>Было бы по твоему, то без малого все бы умели программировать хоть чуть-чуть.
EP>Тем не менее, непосредственно программирование тоже встречается в повседневной жизни — разве трудно составить рецепт, или например описание маршрута?
И где здесь вычислитель навроде машины тьюринга или регистровой машины ?
I>>А этого не происходит — смотри на ЗП разработчиков и их количество в общей массе.
EP>Во-первых программирование помимо описания последовательности действий требует абстрактного мышления, тягу к математике — без них можно программировать, но результат будет посредственным.
Судя по тому, что подавляющего большинства прграммистов математика отсутсвует...
EP>Во-вторых для программирования нужна тяга к машинам, и какая-никакая интровертность. То есть программистов мало не потому что трудно, а потому что далеко не всем интересно.
Зато деньги многим интересны. В других областях люди спокойно занимаются нелюбимым делом, если денех хватает. А в программухе это не проходит, это скорее исключение.
I>>Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи.
EP>Ему не нужна модель вычислителя — у него вычислитель уже есть в голове.
Машина тьюринга или регистровая машина ? Жжош !
EP>Итеративную версию чисел Фибоначчи можно элементарно объяснить ребёнку даже если он не умеет складывать числа — с помощью линейки и циркуля.
Для ребенка в этом возрасте это будут просто линии и квадраты, а не фибоначчи.
I>>А просто объяснить функцию Фибоначчи не нужны никакие вычислители, формулу нарисовал и всё. I>>Более того, этот человек сможет проверить её же в Экселе том же, на раз. К программированию это не приблизит, но фибоначчи объяснить вполне получится.
EP>Попробуй объяснить вот этот "идиоматичный ФП" код ребёнку: EP>
Или даже не ребёнку, а своему коллеге, который с ФП не сталкивался.
В этом примере ты предлагаешь объяснять оптимизации хаскеля и хвостовую рекурсию, то есть, конкретный вариант а не фибоначчи. То есть, проблема в том что явно привязался к вычислителю
Нужно объяснять вот такой или классический рекурсивный
Не буду цитировать всё твоё сообщение. В целом из него ясно, что ты подразумеваешь под высокоуровневостью скорее отсутствие синтаксического шума, а не наличие какие-то предметных возможностей... Это конечно тоже вариант, но на мой взгляд не особо продуктивный.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Конкретно такой может и нет, но есть другая. И вообще, все эти ФЯ по сравнению с Хаскелем сильно вряд ли ФЯ Так, гибриды.
Так есть. Но о том и речь, что чистые функциональные не нужны.
I>Если уж сравнивать монадный хаскель с С++, то надо обязательно посмотреть на ко-монады.
Вообще то у меня там претензии не к самим монадам (это же на самом деле достаточно удобный инструмент для определённых задач), а к реализации IO/ST в Хаскеле. Просто оно там и сделано через соответствующие монады, так что получается приходится их ругать. )))
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Конкретно такой может и нет, но есть другая. И вообще, все эти ФЯ по сравнению с Хаскелем сильно вряд ли ФЯ Так, гибриды.
_>Так есть. Но о том и речь, что чистые функциональные не нужны.
Тебе они не нужны, уже давно выяснили.
I>>Если уж сравнивать монадный хаскель с С++, то надо обязательно посмотреть на ко-монады.
_>Вообще то у меня там претензии не к самим монадам (это же на самом деле достаточно удобный инструмент для определённых задач), а к реализации IO/ST в Хаскеле. Просто оно там и сделано через соответствующие монады, так что получается приходится их ругать. )))
Я пока не увидел никаких обоснованых претензий
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Не буду цитировать всё твоё сообщение. В целом из него ясно, что ты подразумеваешь под высокоуровневостью скорее отсутствие синтаксического шума, а не наличие какие-то предметных возможностей... Это конечно тоже вариант, но на мой взгляд не особо продуктивный.
Мне кажется ты скипнул не читая.
Отсутствие синтаксического шума это всего лишь необходимый признак. Есть еще один, — абстракции, кторые дают наименьшее количетсво блоков в решении задачи.
Вот наличие этих двух признаков есть необходимое и достаточное условие для того, что бы считать язык высокоуровневым.
На самом деле высокоуровневый это относительный термин. ассемблер относительно машинных кодов высокоуровневый язык. А С++ относительно ассемблера так же высокоуровневый язык.
То есть, чем ближе язык к железу, тем он более низкоуровневый. Чем ближе к математике — тем более высокоуровневый.
Ну и специализацию надо учитывать. Скажем, c т.з. Datalog языки C++, Haskell и ассемблер будут примерно одинаково низкоуровневыми
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Тебе они не нужны, уже давно выяснили.
Тот же OCaml мне вполне нравится. )
I>Я пока не увидел никаких обоснованых претензий
Так, напишу здесь всё своё видение последний раз. Не для того чтобы тебя убедить (при твоей упёртости это мало реально ), а просто чтобы подвести некий итог и кидать сюда ссылки потом, если ещё возникнут вопросы. Писать в дальнейшем на эту тему уже не собираюсь.
И так, появилась идея создать чистый функциональный язык. Для этого надо как-то решить проблему не вписывающихся в эту концепцию обязательных нюансов программирования. Как минимум это "изменение состояния" и ввод/вывод (тоже в общем то состояние, только как бы внешнего мира). В Хаскеле эту проблему решили с помощью выделения всего кода ST/IO в некую специальную резервацию. Кстати, построение резервации выполнено с помощью монадных техник (далеко не единственный вариант) и как раз исключительно это и является причиной такого широкого использования монад в Хаскеле (с этого моего утверждения и началась вся эта дискуссия). Так вот, в результате мы получили внутри Хаскеля ещё один маленький встроенный язык, причём уже чётко императивный. Естественно он убогонький и неудобный, причём не только по сравнению с самим Хаскелем, но и в сравнение с классическими императивными языками (что не удивительно, т.к. у в них именно такая функциональность оттачивалась годами). Но видимо авторы языка посчитали это приемлемой ценой за возможность писать вне этого подъязыка строго чистый и ленивый код.
И для определённого вида приложений это действительно замечательно. Например, если мы возьмём приложение, которое считает что-то сложное и потом просто печатает это в консоль, то вся "нехорошая" часть приложения сведётся к виду "main=print $ pure_main", а вся остальная часть приложения будет представлять из себя красивый чистый и ленивый код. Красота!
Однако если мы вернёмся из академического мира в реальность, то там ситуация становится противоположной. При написание скажем какого-нибудь десктопного GUI, наибольший объём кода у нас становится не в области нормального Хаскеля, а в области того самого убогого императивного подъязыка. Со всеми вытекающими из этого последствиями. И в итоге весь смысл изначальной идей оказывается выкинутым в помойку.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, чем ближе язык к железу, тем он более низкоуровневый. Чем ближе к математике — тем более высокоуровневый.
Не думаю) ФЯ — это совсем не признак высокоуровневости. Это скорее тоже низкий уровень, но совсем с другой стороны.
I>Ну и специализацию надо учитывать. Скажем, c т.з. Datalog языки C++, Haskell и ассемблер будут примерно одинаково низкоуровневыми
Воот, с этим уже согласен. Кстати, Пролог мне всегда очень нравился. )))
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>То есть, чем ближе язык к железу, тем он более низкоуровневый. Чем ближе к математике — тем более высокоуровневый.
_>Не думаю) ФЯ — это совсем не признак высокоуровневости. Это скорее тоже низкий уровень, но совсем с другой стороны.
Любой ФЯ намного ближе к математике чем С++ а следовательно и уровнем выше.
В С++ такая вещь, как композиция функций, это много-много ручной работы, вагоны темплейтов распиханых по разным уголкам, а в ФЯ это все одной строчкой.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Тебе они не нужны, уже давно выяснили.
_>Тот же OCaml мне вполне нравится. )
Ты на нем не пишешь в продакшн Судя по тем вещам, которые ты выдал в разговоре про монады, короутины и async/await ты яростно защищает императивные фичи.
_>И так, появилась идея создать чистый функциональный язык. Для этого надо как-то решить проблему не вписывающихся в эту концепцию обязательных нюансов программирования. Как минимум это "изменение состояния" и ввод/вывод (тоже в общем то состояние, только как бы внешнего мира). В Хаскеле эту проблему решили с помощью выделения всего кода ST/IO в некую специальную резервацию. Кстати, построение резервации выполнено с помощью монадных техник (далеко не единственный вариант) и как раз исключительно это и является причиной такого широкого использования монад в Хаскеле (с этого моего утверждения и началась вся эта дискуссия). Так вот, в результате мы получили внутри Хаскеля ещё один маленький встроенный язык, причём уже чётко императивный. Естественно он убогонький и неудобный, причём не только по сравнению с самим Хаскелем, но и в сравнение с классическими императивными языками
Дальше можно не читать, потому что ты съехал на субъективные вещи. Я вот тоже самое могу сказать про С++, в ём два языка — один обычный, наследник С++, а другой мутный, запутаный и неудобный язык шаблонов.
_>Однако если мы вернёмся из академического мира в реальность, то там ситуация становится противоположной. При написание скажем какого-нибудь десктопного GUI, наибольший объём кода у нас становится не в области нормального Хаскеля, а в области того самого убогого императивного подъязыка. Со всеми вытекающими из этого последствиями. И в итоге весь смысл изначальной идей оказывается выкинутым в помойку.
Я хаскель разбираю в основном по таким вот примерам и пока что ни разу не ужаснулся. Нужно всего то разделять UI и логику приложения, IO и обработку данных.
Что характерно, если поступать иначе, то в любом языке будет тупой низкоуровневый мусор ближе всего похожий на Си, только более глупый и многословный. Повторяю — в любом.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Любой ФЯ намного ближе к математике чем С++ а следовательно и уровнем выше.
С чего это "следовательно"? ) Я же сказал, что близость к математике не означает ещё ничего.
I>В С++ такая вещь, как композиция функций, это много-много ручной работы, вагоны темплейтов распиханых по разным уголкам, а в ФЯ это все одной строчкой.
А в ФЯ другие вещи требуют много-много ручной работы, в то время как в C++ делаются одной строкой. Я же говорю, ФЯ — это не уровень, а просто другой взгляд. И он тоже может быть разных уровней.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты на нем не пишешь в продакшн Судя по тем вещам, которые ты выдал в разговоре про монады, короутины и async/await ты яростно защищает императивные фичи.
Монады, короутины и async/await не имеет никакого отношения к функциональщине. Ну разве что для монад ещё требуется некий минимум типа первоклассных функций, но это есть в очень многих языках.
I>Дальше можно не читать, потому что ты съехал на субъективные вещи. Я вот тоже самое могу сказать про С++, в ём два языка — один обычный, наследник С++, а другой мутный, запутаный и неудобный язык шаблонов.
Это не субъективные вещи, а вполне очевидные. Про которые пишут даже специалисты по Хаскелю в учебниках.
I>Я хаскель разбираю в основном по таким вот примерам и пока что ни разу не ужаснулся. Нужно всего то разделять UI и логику приложения, IO и обработку данных.
Разделять то надо. Но при этом не обязательно в разных частях использовать "разные языки". )
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты на нем не пишешь в продакшн Судя по тем вещам, которые ты выдал в разговоре про монады, короутины и async/await ты яростно защищает императивные фичи.
_>Монады, короутины и async/await не имеет никакого отношения к функциональщине. Ну разве что для монад ещё требуется некий минимум типа первоклассных функций, но это есть в очень многих языках.
А я про то, как ты защищаешь императивные фичи.
I>>Дальше можно не читать, потому что ты съехал на субъективные вещи. Я вот тоже самое могу сказать про С++, в ём два языка — один обычный, наследник С++, а другой мутный, запутаный и неудобный язык шаблонов.
_>Это не субъективные вещи, а вполне очевидные. Про которые пишут даже специалисты по Хаскелю в учебниках.
Удобство стало очевидной вещью ? Чудеса. Ни разу не видел, что бы специалист по Хаскелю сказал, что Хаскель неудобен. Ссылку дашь ?
_>Разделять то надо. Но при этом не обязательно в разных частях использовать "разные языки". )
Правильно, не обязательно, а ты вещаешь как будто тебя силой заставляют. А вот в С++, кстати говоря, без "разных языков" вообще ничего внятного не делается. Более того, С++ это скорее три языка, а не два, с учетом того, что шаблоны включают в себя метапрограммирование.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Любой ФЯ намного ближе к математике чем С++ а следовательно и уровнем выше.
_>С чего это "следовательно"? ) Я же сказал, что близость к математике не означает ещё ничего.
Близость к математике это абстрации, это и есть уровень языка. Если ты не согласен, то дай внятное определение, что же такое уровень языка
I>>В С++ такая вещь, как композиция функций, это много-много ручной работы, вагоны темплейтов распиханых по разным уголкам, а в ФЯ это все одной строчкой.
_>А в ФЯ другие вещи требуют много-много ручной работы, в то время как в C++ делаются одной строкой. Я же говорю, ФЯ — это не уровень, а просто другой взгляд. И он тоже может быть разных уровней.
ФЯ это прежде всего уровень, близость к математике.
Вот, смотри — здесь нет никакого "другого" взгляда, здесь практически формула из учебника математики
f(1) -> 1
f(2) -> 1
f(N) -> f(N-1) + f(N-2)
"Другой" взгляд появится, когда ты перепишешь это в итерационном виде.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Удобство стало очевидной вещью ? Чудеса. Ни разу не видел, что бы специалист по Хаскелю сказал, что Хаскель неудобен. Ссылку дашь ?
Уже кидал одну из ссылок прямо в этой темке. И там естественно речь шла не вообще про Хаскель, а про монадную (подразумевая IO/ST) разновидность.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Уже кидал одну из ссылок прямо в этой темке. И там естественно речь шла не вообще про Хаскель, а про монадную (подразумевая IO/ST) разновидность.
На самом деле не важно, удобство непроверяемо и нефальсифицируемо
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Близость к математике это абстрации, это и есть уровень языка. Если ты не согласен, то дай внятное определение, что же такое уровень языка
Абстракции — это да. Но причём тут математика? )
Кстати, вот лично у меня как раз по математике образование высшего академического уровня (и совсем не с программерской стороны, а пофундаментальнее), но я не вижу там ничего такого особо высокоуровневого в смысле абстракций. Абстракции как-то больше в философии или в той же самой архитектуре ПО встречаются. )
I>ФЯ это прежде всего уровень, близость к математике. I>Вот, смотри — здесь нет никакого "другого" взгляда, здесь практически формула из учебника математики I>
I>"Другой" взгляд появится, когда ты перепишешь это в итерационном виде.
Ну да, ФЯ — это близость к математике. Но причём тут уровень языка? )
И кстати ты тут просто приводишь пример подходящий как раз под ФЯ. А можно наоборот накидать кучу примеров, которые будут выглядеть очевидно в императивном виде и очень сложно выражаться в ФЯ.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Кстати, вот http://habrahabr.ru/post/211871/ сегодня вышла статья очень в тему... Она как раз про то, что на мой взгляд является высокоуровневыми вопросами. И как видно, пока что у ФП дела с этим обстоят довольно мрачно.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Кстати, вот http://habrahabr.ru/post/211871/ сегодня вышла статья очень в тему... Она как раз про то, что на мой взгляд является высокоуровневыми вопросами. И как видно, пока что у ФП дела с этим обстоят довольно мрачно.
Я шота не вижу там определения. Там говорится "низкий дизайн" в контексте Хаскеля или ФЯ, а не в сравнении с ассемблером. Этот низкий уровень Хаскеля намного выше как ассемблера, так и с++.
И ежу понятно, что в каждом языке будут некоторые базовые конструкции которые и определяют низкий уровень на этом языке. Но при этом низкий уровень Хаскеля вообще никак не соотносится с железом. Скажем с С++ ровно наоборот — низкоуровневые конструкции запилены под архитектуру современных микропроцессоров.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: I>>Близость к математике это абстрации, это и есть уровень языка. Если ты не согласен, то дай внятное определение, что же такое уровень языка
_>Абстракции — это да. Но причём тут математика? )
При том, что математика это абстрации в чистом виде, еще чище чем в Хаскеле.
_>Кстати, вот лично у меня как раз по математике образование высшего академического уровня (и совсем не с программерской стороны, а пофундаментальнее), но я не вижу там ничего такого особо высокоуровневого в смысле абстракций. Абстракции как-то больше в философии или в той же самой архитектуре ПО встречаются. )
Я честно говоря не знаю, что ты понимаешь под словом абстракция
I>>"Другой" взгляд появится, когда ты перепишешь это в итерационном виде.
_>Ну да, ФЯ — это близость к математике. Но причём тут уровень языка? )
При том, что есть всего два полюса — железо и специфичная область математики. Одно принято считать низким уровнем, а другое — высоким.
_>И кстати ты тут просто приводишь пример подходящий как раз под ФЯ. А можно наоборот накидать кучу примеров, которые будут выглядеть очевидно в императивном виде и очень сложно выражаться в ФЯ.
Можно накидать сотню строчек на ассемблере и может оказаться так, что для этого клочка нет и не может быть ниодной аналитической модели, что с того ? Это всё равно будет низкий уровень.
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Greeter, Вы писали:
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Принципы пакетирования, я их понимаю, но в "полном объеме" ни когда ими не пользовался.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
EP>Это никакой не Tree Sort, это именно пародия на quick sort.
Не понятно, какой смысл вы вкладываете в слова "пародия на quick sort", но это совершенно точно tree sort. Называть это quicksort, конечно, неправильно.
То, что это tree sort в глаза сразу не бросается потому, что он дефористирован вручную. Т.е. функция построения дерева (несбалансированного)
data Tree a = Leaf | Node (Tree a) a (Tree a)
toTree [] = Leaf
toTree (p:xs) = Node (toTree lesser) p (toTree greater) where
lesser = filter (< p) xs
greater = filter (>= p) xs
и "сплющивания" дерева
toList Leaf = []
toList (Node l x r) = toList l ++ [x] ++ toList r
просто "сфьюжены" вручную.
EP>Quick Sort делит массив на две части (вырезая середину), и продолжает рекурсивно в каждой из частей. Начиная с определённой глубины текущий Range полностью поместится в L3, ещё глубже — L2, потом в L1 и так далее.
Ну, не каждый divide-and-conquer алгоритм считается cache-oblivious. Почитайте про какой-нибудь funnel-sort там разница хорошо понятна. Да и как divide-and-conquer quick sort — не фонтан. Потому, что качество деления у него от данных зависит (во отличие от той же сортировки слияниями).
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я шота не вижу там определения. Там говорится "низкий дизайн" в контексте Хаскеля или ФЯ, а не в сравнении с ассемблером. Этот низкий уровень Хаскеля намного выше как ассемблера, так и с++.
I>И ежу понятно, что в каждом языке будут некоторые базовые конструкции которые и определяют низкий уровень на этом языке. Но при этом низкий уровень Хаскеля вообще никак не соотносится с железом. Скажем с С++ ровно наоборот — низкоуровневые конструкции запилены под архитектуру современных микропроцессоров.
Речь о другом. В этой статье обсуждаются действительно высокоуровневые вещи, определяющие архитектуру ПО. Для большинства языков (как императивных, так и функциональных) эти вещи не имеют прямого выражения в структурах языка, а существуют сами по себе. Так вот, если для императивных языков эта область имеет громадное количество готовых концепций, специализированных инструментов и т.п., то для функциональных автор сумел наскрести 1,5 известных концепции и 0 готовых инструментов. Собственно большую часть статьи автор и пытается придумать чем ему заменить в функциональном языке все эти известные и хорошо работающие вещи из мира императивных языков.
Т.е. если смотреть с самого верха, то программирование и на чистом C++ и на чистом Haskell'е весьма низкоуровневое. Однако, если под нашу конкретную задачу, существует готовый мощный фреймворк, то тогда программирование может резко стать очень высокоуровневым и на C++ и на Haskell'e. Хотя при таких раскладах это уже становится скорее программированием именно на этом фреймворке (как на неком неформализированном DSL). Т.е. в общем то ситуация равная, с поправкой на то, что для мира императивных языков подобных вещей существует на порядки больше и существуют специальные концепции и инструменты для их удобного построения.
Ну и есть языки, в которых данные вопросы решены уже на уровне самого языка. Это чаще всего всяческие специализированные DSL'и. Вот они и являются максимально высокоуровневыми, правда практически всегда это достигается резким сокращением универсальности.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>При том, что математика это абстрации в чистом виде, еще чище чем в Хаскеле.
Математика безусловно использует абстракции везде. А вот обратное уже совсем не верно... )
I>Я честно говоря не знаю, что ты понимаешь под словом абстракция
Смотря в каком контексте. Но здесь речь шла о том, что математика не обязательно имеет к этому какое-то отношение.
Вот например, подскажи мне какой раздел математики позволит мне записать концепцию ООП в виде формул? )
I>При том, что есть всего два полюса — железо и специфичная область математики. Одно принято считать низким уровнем, а другое — высоким.
Это оно у тебя так принято. )))
I>Можно накидать сотню строчек на ассемблере и может оказаться так, что для этого клочка нет и не может быть ниодной аналитической модели, что с того ? Это всё равно будет низкий уровень.
Конечно низкий. Т.е. и это и задание математической функции в коде — это низкий уровень. )
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>При том, что математика это абстрации в чистом виде, еще чище чем в Хаскеле.
_>Математика безусловно использует абстракции везде. А вот обратное уже совсем не верно... )
Математика только абстракции и использует. В ней нет ничего конкретного. 2 + 2 — абстракции в чистом виде, во первых сами числа, во вторых — операция
I>>Я честно говоря не знаю, что ты понимаешь под словом абстракция
_>Смотря в каком контексте. Но здесь речь шла о том, что математика не обязательно имеет к этому какое-то отношение.
математика это язык описания абстракций
_>Вот например, подскажи мне какой раздел математики позволит мне записать концепцию ООП в виде формул? )
Открой для себя семантику программирования, это дисциплина которая занимается построением и изучением математических моделей для всех языковых конструкций. На каком именно базисе будет построено ООП, не в курсе
I>>При том, что есть всего два полюса — железо и специфичная область математики. Одно принято считать низким уровнем, а другое — высоким.
_>Это оно у тебя так принято. )))
Нет, не у меня, не угадал.
I>>Можно накидать сотню строчек на ассемблере и может оказаться так, что для этого клочка нет и не может быть ниодной аналитической модели, что с того ? Это всё равно будет низкий уровень.
_>Конечно низкий. Т.е. и это и задание математической функции в коде — это низкий уровень. )
... а в Киеве дядька.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Речь о другом. В этой статье обсуждаются действительно высокоуровневые вещи, определяющие архитектуру ПО. Для большинства языков (как императивных, так и функциональных) эти вещи не имеют прямого выражения в структурах языка, а существуют сами по себе. Так вот, если для императивных языков эта область имеет громадное количество готовых концепций, специализированных инструментов и т.п., то для функциональных автор сумел наскрести 1,5 известных концепции и 0 готовых инструментов. Собственно большую часть статьи автор и пытается придумать чем ему заменить в функциональном языке все эти известные и хорошо работающие вещи из мира императивных языков.
То есть, ты хочешь уровень привязать к инструментам ? Эдак окажется, что машинный код это самый высокоуровневй язык, потому что для него наверное пару миллионов инструментов, ну вот например декомпилер, линкер и тд и тд.
_>Т.е. если смотреть с самого верха, то программирование и на чистом C++ и на чистом Haskell'е весьма низкоуровневое.
Из этого не следует, что у этих языков один и тот же уровень или хотя бы уровни близкие.
>Однако, если под нашу конкретную задачу, существует готовый мощный фреймворк, то тогда программирование может резко стать очень высокоуровневым и на C++ и на Haskell'e. Хотя при таких раскладах это уже становится скорее программированием именно на этом фреймворке (как на неком неформализированном DSL). Т.е. в общем то ситуация равная, с поправкой на то, что для мира императивных языков подобных вещей существует на порядки больше и существуют специальные концепции и инструменты для их удобного построения.
В общем случае если мы сделаем АПИ для этого фремворка в разных языках, внезапно, будет разница в том, что как эффективно использовать и где за каким деталями придется следить.
Вот в С++ ты точно не сможешь избавиться от указателей, инстанцирований, деклараций шаблонов, указания типов и тд и тд и тд
А в Хаскеле — запросто.
_>Ну и есть языки, в которых данные вопросы решены уже на уровне самого языка. Это чаще всего всяческие специализированные DSL'и. Вот они и являются максимально высокоуровневыми, правда практически всегда это достигается резким сокращением универсальности.
DSL как правило это небольшая, очень узкая область математики
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И так, появилась идея создать чистый функциональный язык. Для этого надо как-то решить проблему не вписывающихся в эту концепцию обязательных нюансов программирования. Как минимум это "изменение состояния" и ввод/вывод (тоже в общем то состояние, только как бы внешнего мира). В Хаскеле эту проблему решили с помощью выделения всего кода ST/IO в некую специальную резервацию. Кстати, построение резервации выполнено с помощью монадных техник (далеко не единственный вариант) и как раз исключительно это и является причиной такого широкого использования монад в Хаскеле (с этого моего утверждения и началась вся эта дискуссия). Так вот, в результате мы получили внутри Хаскеля ещё один маленький встроенный язык, причём уже чётко императивный. Естественно он убогонький и неудобный, причём не только по сравнению с самим Хаскелем, но и в сравнение с классическими императивными языками (что не удивительно, т.к. у в них именно такая функциональность оттачивалась годами). Но видимо авторы языка посчитали это приемлемой ценой за возможность писать вне этого подъязыка строго чистый и ленивый код.
Всё совершенно наоборот. Нет никаких "не вписывающихся в концепцию" нюансов; ФП с самого начала эквивалентно МТ (см. Тезис Чёрча).
ФП честно объясняет: у вас нет никакого "глобального вычислителя", который неявно передаётся от команды к команде. Если вам нужно состояние — то вы описываете его явно. Дело не в резервации, а в том, что выписывать руками нудную передачу состояния — лень. Поэтому внимательные ФП-шники заметили, что "результат функции" и "результат функции плюс состояние мира" можно описать абстрактно. А из любой чистой функции можно получить функцию, работающую с состоянием, путём применения той же техники, которая применима к функциям, работающим с "необязательными значениями". И эта техника — как раз монады. Всё.
Ваши рассуждения про резервацию должны бы быть применимы к любой другой монаде — например, к монаде List, или Optional. Но почему-то вам кажется, что IO/ST — это какая-то отдельная резервация, а Optional — это нормальный ФП код.
_>И для определённого вида приложений это действительно замечательно. Например, если мы возьмём приложение, которое считает что-то сложное и потом просто печатает это в консоль, то вся "нехорошая" часть приложения сведётся к виду "main=print $ pure_main", а вся остальная часть приложения будет представлять из себя красивый чистый и ленивый код. Красота!
Совершенно верно.
_>Однако если мы вернёмся из академического мира в реальность, то там ситуация становится противоположной. При написание скажем какого-нибудь десктопного GUI, наибольший объём кода у нас становится не в области нормального Хаскеля, а в области того самого убогого императивного подъязыка. Со всеми вытекающими из этого последствиями. И в итоге весь смысл изначальной идей оказывается выкинутым в помойку.
Странно. Весь "десктопный GUI" в современных системах — это реализация оконной функции. Совершенно непонятно, почему вы считаете эту функцию какой-то особенной. Просто она вызывается много раз за время жизни приложения, а не один, как функция main.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вот например, подскажи мне какой раздел математики позволит мне записать концепцию ООП в виде формул? )
Computer Science.
См. https://www.google.ru/search?q=theory+of+classification+site:jot.fm Чистая математика, вся концепция ООП в виде формул.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так это же не ФЯ с его ограничениями на иммутабельность — мы можем создавать что угодно, не только возвращая значения из функций. )
Ну, понятно, что вам угодно возвращать только то, что можно в плюсах. Вот замыкания возвращать проблематично, потому и неугодно.
_>Шаблоны проектирования прекрасно реализуются и без всякого МП, так что оно собственно тут ни при чём. Так вот, возвращаясь к шаблонам проектирования... Это разве на ваш взгляд не абстракции достаточно высокого уровня?
Нет, не реализуются. Без метапрограммирования никаких шаблонов проектирования в коде нет — только результат их применения в голове программиста. Поэтому к уровню кода они никакого значения не имеют.
_>Вот например возьмём такое общеизвестное простейшее приложение как "Блокнот". Из каких математических объектов он будет состоять, если мы его реализуем по высокоуровневому? )
Из функций, категорий, моноидов, функторов, монад и т.д.
_>Нуну)
_>Возьмём например такой простейший код, работающий через константные ссылки: _>
_>prepare :: Array Int Int -> Array Int Int
_>prepare а = а//[(1, а!1*а!1)]
_>test :: Array Int Int -> Int
_>test а = let r=prepare а
_> in sum $ elems r
_>main = print $ test $ listArray (0, length l -1) l
_> where l= [1, 2, 3]
_>
Ну конечно, если брать какую-нибудь убогую библиотеку, да еще и специально писать ужасы — тогда конечно.
Вот как выглядит нормальный код, использующий нормальную библиотеку:
prepare a = a // [(1, a!1^2)]
test = V.sum . prepare
main = print . test . V.fromList $ [1..3::Int]
_>Его прямым аналогом на C++ будет что-то вроде:
Нет, прямой аналог этого кода на C++ написать нельзя, потому что системы контроля эффектов в нем нет.
_>
_>А теперь предположим, что нам захотелось переделать это под неконстантные ссылки. Кстати, вполне реальная задачка, если у нас массив не из 3-ёх элементов, а из 3*10^9. На C++ это станет выглядеть так: _>
_>Видно, что код практически не изменился по своей структуре, а стал только проще — просто стёрли лишнее.
Ну так потому что код один и тот же. Странно ожидать, что один и тот же код будет выглядеть по разному.
_>Ну и теперь полюбуемся, как будет выглядеть что-то подобное на Хаскеле: _>
_>prepare :: STArray s Int Int -> ST s ()
_>prepare a = do
_> x <- readArray a 1
_> writeArray a 1 (x*x)
_>test :: STArray s Int Int -> ST s Int
_>test a = do
_> prepare a
_> l <- getElems a
_> return $ sum l
_>main = print $ runST $ do
_> let l=[1, 2, 3]
_> a <- newListArray (0, length l -1) l :: ST s (STArray s Int Int)
_> test a
_>
prepare a = do
x <- M.read a 1
M.write a 1 (x*x)
return a
test a = fmap V.sum (V.unsafeFreeze =<< prepare a)
main = print =<< test =<< (V.thaw . V.fromList $ [1..3::Int])
Что характерно, этот код отличается по скорости от первого моего примера на ~10% (если вектора взять по 100M элементов и преобразовывать не из списка, иначе измеряемое различие вообще не получить), т.е в "наивном" коде не убрано оптимизатором одно единственное лишнее копирование вектора.
_>И это ещё в лучше случае, если getElems в реальности создаёт ссылку, а не выделяет память (я просто не в курсе таких тонкостей). А если getElems выделяет память, то её использовать нельзя и придётся ещё самим писать новую версию sum, которая умеет работать с типом STArray s Int Int.
Вообще говоря, преобразовывать в список ленивый образом, "без копирования" небезопасно. Список можно проходить частями и никто не гарантирует, что изменяемый массив за это время не поменяется. Собственно поэтому в моем коде unsafeFreeze — я-то знаю, что собираюсь потребить все данные прямо тут, в функции sum, а компилятор нет. Именно этим копированием второй вариант от наивной реализации и отличается — если вместо unsafeFreeze написать freeze при преобразовании добавится копирование и разницы между вариантами не будет. Конечно, плохо, что для мутабельных массивов нет такого же богатого набора функций как и для иммутабельных, но это библиотечная проблема.
_>Но даже если забыть про этот момент, то в целом видно, что изначальный хаскельный код при переходе к монадному (который необходим для существования неконстантных ссылок) изменился до неузнаваемости.
Я вроде бы сразу признал, что преобразование между "нелифтнутым" и "лифтнутым" кодом требует значительной модификации кода. Речь-то была о сравнении "лифтнутого" и кода на обычном императивном языке.
_>Причём код не просто полностью изменился, а стал заметно страшнее — смысловая часть в нём погребена под кучей монадного синтаксического мусора.
Конечно он стал страшнее, по сравнению с "наивной" версией. Но не страшнее плюсовой, синтаксический мусор в которой существует вовсе без всякого смысла и оправдания.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Что-то я не понял, что вы тут хотели сказать. Что описываемую задачку можно решить без монадного кода? ) Если можно, то тогда с удовольствием посмотрю на это... Если же нельзя, то тогда в чём претензии к моим комментариям? )
Вы же сами сказали, что вам нужно получать в итоге переписывание вектора по месту. Значит по крайней мере одна функция-примитив с "монадным кодом" будет, хотя использовать ее в коде, использующем библиотеку не обязательно. Или это из моего объяснения было непонятно? Пользователю библиотеки доступен набор функций из иммутабельного массива в иммутабельный массив, реализованные через другие функции из иммутабельного массива в иммутабельный массив, а где-то в основании всего этого — пара-тройка примитивов, которые работают с мутабельными массивами и переписывают их по месту и которые автору библиотеки нужно написать. Из ниоткуда "монадный код" не возьмется, компилятор его сам не выдумает.
_>Если же нельзя, то тогда в чём претензии к моим комментариям? )
Началось все с того, что вы заявили, что проблема неустранимого копирования данных, при передаче их между функциями, для ФП принципиальная и нерешаемая. Я же продемонстрировал, что она не только решаема в принципе, но и решена для широкого класса случаев. Теперь вдруг требуется, чтоб и в процессе оптимизации ни на каком этапе так ненавидимый вами "монадный код" никогда не появлялся. Тут новости плохие, ваши чувства никто не щадит и не собирается, авторы таких библиотек не боятся "монадный код" использовать.
_>А что, без этих "лишних копирований" можно обойтись что ли? ) Как мы без них получим нормальные (не монадные) хаскельные функции? )
Никак бы не получили. Ну так эти копирования по условию задачи и нужно устранять. Они и устраняются. И не в ручную, а автоматически. Я это продемонстрировал. И где тут была ручная оптимизация?
_>Ну так мало ли откуда там идёт тот внешний буфер — далеко не факт, что он прямой результат new. А если делать дополнительную обёртку, то всё равно получим то самое копирование.
Захотим получим, не захотим — не получим. Все зависит от того, какие мы захотим иметь гарантии по безопасности.
_>Кстати, в реальности (изначальная задачка то из вполне реальной области была) там это выглядит так: первичный буфер предоставляет ОС, вызывая наш код 30 раз в секунду и передавая нам при этом указатель. Так вот на C++ естественно без проблем делается такая обработка вообще без выделения памяти — и внутри обработки одного кадра (про что и был код выше) и между кадрами. А как тут у Хаскеля дела? )
Вот так:
unsafeFromForeignPtr0 fp n = Vector n fp
т.е. Storable.Vector это просто структура, хранящая длину и указатель, который откуда угодно можно получать. Никакого копирования при этом не происходит.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Утомил меня этот наш бестолковый спор о терминах.
Спор начали вы, видимо обидевшись за C++ на слово "нетипизированный".
_>Вы пытаетесь цепляться за придуманные вами же определения и не обращаете внимания на смысл вообще.
Определение выдумал не я, на смысл внимание обращаю. Это вы выдумываете какие-то странные подвиды "используемого кода".
_>Предлагаю простейшее разрешение вопроса. Раз вы считаете, что шаблоны C++ нетипизированные, то тогда просто приведите ровно один любой пример, в котором из-за этой нетипизированности будет создаваться некорректно работающее ПО.
Ну опять двадцать пять. Работающее (запускающееся) ПО будет типизировано до того, как запустится. Мы говорим про обобщенный код, который никогда не запускается. В плюсах он и не типизируется. Не потому, что это не нужно, или наоборот для чего-то нужно, чтоб типизации не было. Это просто не сделано при разработке шаблонов.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Открой для себя семантику программирования, это дисциплина которая занимается построением и изучением математических моделей для всех языковых конструкций. На каком именно базисе будет построено ООП, не в курсе
См. мой ответ Синклеру (ниже).
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, ты хочешь уровень привязать к инструментам ? Эдак окажется, что машинный код это самый высокоуровневй язык, потому что для него наверное пару миллионов инструментов, ну вот например декомпилер, линкер и тд и тд.
Нет, речь не про такие инструменты. А например про UML и ещё множество других из этой же области.
I>В общем случае если мы сделаем АПИ для этого фремворка в разных языках, внезапно, будет разница в том, что как эффективно использовать и где за каким деталями придется следить. I>Вот в С++ ты точно не сможешь избавиться от указателей, инстанцирований, деклараций шаблонов, указания типов и тд и тд и тд I>А в Хаскеле — запросто.
Ну вот простой пример. Надо нам написать Блокнот, скажем под виндой (типа дефолтного).
Попробуем в начале без всяких мощных фреймворков. Естественно при этом будет гора кода с функциями, классами (хотя не обязательно) и т.п.
На чистом C++ будет естественно жуть, т.к. WinAPI.
На чистом Python'е будет дважды жуть. Т.к. и WinAPI и ещё надо до него добраться (внешний вызов).
На чистом Haskell'e будет трижды жуть. Т.к. и WinAPI и внешние вызовы и всё это будет внутри монадного кода.
Теперь возьмём какую-нибудь мощную библиотечку. Например wxWidgets или Qt (к ним есть биндинги отовсюду).
На C++ весь код превратился в одну страницу, причём там код простейший, представляющий собой исключительно вызовы функций библиотечки.
На Python'e будет буквально такой же код, как и на C++. Т.е. с точностью до замены скобочек на отступы.
На Haskell'е ситуация будет чуть хуже за счёт монадного мусора, но если приравнять его к своеобразному аналогу скобочек, то снова получится буквально такой же код.
I>DSL как правило это небольшая, очень узкая область математики
Тогда 1С придумывал математик под кайфом. )))
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Всё совершенно наоборот. Нет никаких "не вписывающихся в концепцию" нюансов; ФП с самого начала эквивалентно МТ (см. Тезис Чёрча). S>ФП честно объясняет: у вас нет никакого "глобального вычислителя", который неявно передаётся от команды к команде.
Фокус в том, что в реальности в современном компьютере находится именно императивный вычислитель, с состояниями. Более того, и окружающий мир очевидно имеет состояния (ну конечно если не верить в модель дерева вселенных, отображающем все вероятные развития событий). Так что в итоге чистая функциональная модель является плохой и для наших компьютеров и для нашего мира. Хотя для отдельных применений может быть полезна.
S>Если вам нужно состояние — то вы описываете его явно.
Вместо этого хака достаточно было бы пометить такие функции как неподходящие для кэширования и ленивого исполнения. И всё. Ну или наоборот, помечать остальные как чистые (такое уже есть в D например) и ленивые. Вместо этого, мы пытаемся всунуть реальный мир в неподходящую ему модель, для чего приходится передавать в функции воображаемые "состояния". Причём эти "состояния" ещё и обязательно форвардить дальше (т.к. иначе всё сломается) и в итоге они заражают весь код, если не применять специальные ограничители (вот и резервация наша).
S>Дело не в резервации, а в том, что выписывать руками нудную передачу состояния — лень. Поэтому внимательные ФП-шники заметили, что "результат функции" и "результат функции плюс состояние мира" можно описать абстрактно. А из любой чистой функции можно получить функцию, работающую с состоянием, путём применения той же техники, которая применима к функциям, работающим с "необязательными значениями". И эта техника — как раз монады. Всё.
Не совсем так. Для ограничения резервации используются специальные функции, типа runST. А монады используются для более удобной записи последовательности вызовов, т.е. для формирования императивного кода уже внутри резервации.
S>Ваши рассуждения про резервацию должны бы быть применимы к любой другой монаде — например, к монаде List, или Optional. Но почему-то вам кажется, что IO/ST — это какая-то отдельная резервация, а Optional — это нормальный ФП код.
1. Optional и List не связаны с нарушением чистоты.
2. Optional и List имеют личный функциональный смысл. Поэтому их подобия встречаются во многих языках. В то время как IO и ST не имеют подобного смысла и являются всего лишь порождением сомнительного дизайна языка.
S>Странно. Весь "десктопный GUI" в современных системах — это реализация оконной функции. Совершенно непонятно, почему вы считаете эту функцию какой-то особенной. Просто она вызывается много раз за время жизни приложения, а не один, как функция main.
Дело не в том откуда её вызывают, а в том что мы вызываем в ней. Там будут системные вызовы, т.е. снова сплошная монада IO.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Занятно. Не видел подобного раньше. Но это всё равно не о том, про что я говорил. Здесь пытаются создать математическую модель некого ООП кода, а я говорил о математическом выражение самой концепции ООП и т.п.
Т.е. если там в качестве абстракции используются понятия класс, объект, функция и т.п., то я говорил об абстракциях типа ООП, SOLID и т.п. Т.е. вообще на другом уровне.
Но всё равно спасибо за ссылку. Довольно любопытно, полистаю в свободное время)
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет, не реализуются. Без метапрограммирования никаких шаблонов проектирования в коде нет — только результат их применения в голове программиста. Поэтому к уровню кода они никакого значения не имеют.
Т.е. например в C# или Java шаблонов проектирования не существует? )))
K>Из функций, категорий, моноидов, функторов, монад и т.д.
Это можно сказать про любое приложение в функциональном стиле. А я спрашивал про конкретное.
K>Ну конечно, если брать какую-нибудь убогую библиотеку, да еще и специально писать ужасы — тогда конечно.
Т.е. стандартная библиотека Хаскеля убогая? ) Понятно... )))
А какая у нас нормальная? )
K>Вот как выглядит нормальный код, использующий нормальную библиотеку: K>...
Практически тоже самое, только убрали описание типов в функциях.
K>Нет, прямой аналог этого кода на C++ написать нельзя, потому что системы контроля эффектов в нем нет.
Ооооо, снова наша таинственная польза от системы контроля эффектов. Которая много раз заявлялась, но ни разу не демонстрировалась... Нуну)))
K>Я вроде бы сразу признал, что преобразование между "нелифтнутым" и "лифтнутым" кодом требует значительной модификации кода. Речь-то была о сравнении "лифтнутого" и кода на обычном императивном языке.
Уже хорошо.
K>Конечно он стал страшнее, по сравнению с "наивной" версией. Но не страшнее плюсовой, синтаксический мусор в которой существует вовсе без всякого смысла и оправдания.
О да, о да. Только в C++ версии нет ни единого оператора/вызова функции не по делу. А в Haskell версии (даже с помощью "нормальной" библиотеки), которая вроде как должна быть вообще без мусора, мы имеем "всего лишь" fmap, V.unsafeFreeze, V.thaw, которые вообще непонятно чем заняты по отношению к прямой функциональности нашего кода. И это если забыть про вынужденно кривой код модификации самого массива.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Началось все с того, что вы заявили, что проблема неустранимого копирования данных, при передаче их между функциями, для ФП принципиальная и нерешаемая. Я же продемонстрировал, что она не только решаема в принципе, но и решена для широкого класса случаев. Теперь вдруг требуется, чтоб и в процессе оптимизации ни на каком этапе так ненавидимый вами "монадный код" никогда не появлялся. Тут новости плохие, ваши чувства никто не щадит и не собирается, авторы таких библиотек не боятся "монадный код" использовать.
Ну да, решённая с помощью добавления императивного кода. )))
K>Вот так: K>
K>unsafeFromForeignPtr0 fp n = Vector n fp
K>
K>т.е. Storable.Vector это просто структура, хранящая длину и указатель, который откуда угодно можно получать. Никакого копирования при этом не происходит.
Я немного не об этом. Я про то, что нам потом надо именно к этим данным применить тот наш набор функций. А потом (после того как вернём управление из обработки, ОС обновит буфер и снова вызовет нас) ещё раз и т.д...
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну опять двадцать пять. Работающее (запускающееся) ПО будет типизировано до того, как запустится. Мы говорим про обобщенный код, который никогда не запускается. В плюсах он и не типизируется. Не потому, что это не нужно, или наоборот для чего-то нужно, чтоб типизации не было. Это просто не сделано при разработке шаблонов.
Т.е. некий волшебник берёт наш нетипизированный код и типизирует его на этапе создания приложения? ) Какая классная магия. Можно свободно писать всё что угодно и при этом автоматически будет гарантия отсутствия ошибок. Вот бы во всех языках так...
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Нет, не реализуются. Без метапрограммирования никаких шаблонов проектирования в коде нет — только результат их применения в голове программиста. Поэтому к уровню кода они никакого значения не имеют. _>Т.е. например в C# или Java шаблонов проектирования не существует? )))
Нет, не существует. Вы вообще-то процитировали ответ на ваш вопрос — см.выше.
_>Это можно сказать про любое приложение в функциональном стиле. А я спрашивал про конкретное.
Конкретно в текстовом редакторе:
Rope в котором хранится редактируемый текст. Дерево — монада, порядок текстовых блоков — моноид.
Лейаут виджетов — моноид.
Последовательность нажатий на клавиши — функтор.
Ширина окна — аппликативный функтор.
Сериализатор/десериализатор файла настроек — аппликативный функтор.
Парсер для подсветки кода — монада.
IOC-контейнер — монада.
и т.д.
K>>Ну конечно, если брать какую-нибудь убогую библиотеку, да еще и специально писать ужасы — тогда конечно. _>Т.е. стандартная библиотека Хаскеля убогая? ) Понятно... )))
Вы даже не представляете всю убогость стандартной библиотеки хаскеля — она поражает воображение! Это если считать стандартной библиотекой то, что в репорте описано. Та часть библиотеки array, которую вы использовали ни в каких стандартах не описана, кстати. Более того, на стандартизированном подмножестве хаскеля она даже нереализуема.
Если же считать стандартом де факто набор библиотек из haskell-platform то и используемая мной (vector) и вами (array) библиотеки стандартные, просто array морально устарела за годы до того, как код, на C++ который вы тут приводите, стал стандартизированным.
_>А какая у нас нормальная? )
vector
_>Ооооо, снова наша таинственная польза от системы контроля эффектов. Которая много раз заявлялась, но ни разу не демонстрировалась... Нуну)))
Именно тут я про пользу ничего не говорил. Просто объяснил почему этот код аналогом не является и почему на C++ аналог написать нельзя. Польза, впрочем, в обсуждаемом примере уже очевидна — оптимизатор выкинул несколько ненужных копирований (все кроме одного), в результате разницы по производительности между "наивным" примером с иммутабельными массивами и примером с мутабельными почти нет.
_>Уже хорошо.
Я тут это написал еще до того, как начал с вами обсуждать ужасы "монадного кода".
_>Только в C++ версии нет ни единого оператора/вызова функции не по делу.
Разумеется есть. Например cbegin() и cend().
_>А в Haskell версии (даже с помощью "нормальной" библиотеки), которая вроде как должна быть вообще без мусора, мы имеем "всего лишь" fmap, V.unsafeFreeze, V.thaw, которые вообще непонятно чем заняты по отношению к прямой функциональности нашего кода.
Они конвертируют мутабельные массивы в иммутабельные и обратно. Потому, что набор функций для работы с иммутабельными богаче. Разумеется, нет никаких принципиальных проблем написать такие же для мутабельных, просто это не сделано.
_>И это если забыть про вынужденно кривой код модификации самого массива.
В чем же его "вынужденная кривизна"?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну да, решённая с помощью добавления императивного кода. )))
Нет. Решена она не с помощью добавления императивного кода. Если пользоваться императивным кодом — тут и решать нечего. Последовательность функций меняющих массив по месту, никаких копирований между ними нет. Я же руками как раз добавил лишние копирования, а компилятор их убрал полностью автоматически.
Вы вообще читаете, что я вам пишу?
Пользователю библиотеки доступен набор функций из иммутабельного массива в иммутабельный массив, реализованные через другие функции из иммутабельного массива в иммутабельный массив, а где-то в основании всего этого — пара-тройка примитивов, которые работают с мутабельными массивами и переписывают их по месту и которые автору библиотеки нужно написать. Из ниоткуда "монадный код" не возьмется, компилятор его сам не выдумает.
Я продемонстрировал как, используя существующую библиотеку как базу, реализовать такие примитивы и получить библиотеку с запрашиваемыми вами свойствами. Почему существующие библиотеки, которые устраняют промежуточные данные, работают не так как вы заказывали (не ходят по мутабельному массиву несколько раз, а стараются преобразовать несколько проходов в один) я объяснил.
_>Я немного не об этом. Я про то, что нам потом надо именно к этим данным применить тот наш набор функций. А потом (после того как вернём управление из обработки, ОС обновит буфер и снова вызовет нас) ещё раз и т.д...
Я как раз об этом. Набор функций определенных над иммутабельными массивами превращается в код, который двигает указатель и пишет туда, куда указатель указывает.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Т.е. некий волшебник берёт наш нетипизированный код и типизирует его на этапе создания приложения? ) Какая классная магия. Можно свободно писать всё что угодно и при этом автоматически будет гарантия отсутствия ошибок. Вот бы во всех языках так...
Какая еще магия? Нетипизированный обобщенный код в плюсах сначала специализируется, а только потом типизируется. Во всех остальных языках типизируется обобщенный код. Вот бы в плюсах так, как во всех остальных языках!
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>То есть над одним DSL — Eigen, надстраивается другой — МКЭ. Уровень абстракции повышается, а runtime penalty минимальный, если вообще присутсвует.
И что? Что вы этим примером хотите доказать?
EP>Вы постоянно пытаетесь противопоставить "ФП" и "низкоуровневый код". Как-будто только ФП это высокий уровень. Поэтому я и спросил про C#/Java.
Мы говорим о поддержке ФП в C++. Что удивительного, что под высокоуровневым кодом понимается ФП? Какое отношение к обсуждаемой теме имеет то, бывают ли какие-то другие высокоуровневые подходы?
EP>Конкретный пример — runtime reflection.
Какое это имеет отношение к ФП? Вообще говоря, рефлексия и абстракцией не является — это наоборот инструментов для проделывания в абстракциях дыр. Хотя конечно, на основе рефлексии можно создавать какие-то инструменты для абстрагирования. Для обобщения по структуре языкового "объекта", например. Но непосредственно абстракцией рефлексия не является.
EP>В большинстве случаев достаточно compile-time reflection. EP>У runtime reflection огромный overhead, а у compile-time — нулевой.
Не собираюсь развивать эту тему про рефлексию, но для какого-нибудь любителя динамики это ваше заявление прозвучит точно так же, как для меня ваши заявления по поддержке ФП: "Конкретный пример — овес. В большинстве случаев достаточно песка." Я-то даже согласен, что в большинстве случаев кт-рефлексии достаточно. Это однако не означает, что наличие кт-рефлексии дает поддержку рт-рефлексии. И наоборот. Но вы, похоже, обо всех фичах судите в такой парадигме: есть песок — ставим галочку рядом с "овес". То, что песок неважная замена овсу вас вообще ни в какой степени не беспокоит. Для вас лично это только плюс. Неприхотливость это достоинство. Но вы поймите, что когда вы кому-то заявляете, что поддержка есть — этот кто-то понимает под словом "поддержка" не осознание ненужности наличия — как вы — а совсем иное.
K>>И где же у указателя эти "пределы"? EP>В ISO C++. EP>За этими пределами — here be dragons, в виде undefined behaviour.
И где в абстракции "указатель" эти операции dragons : pointer -> bool и behaviour : pointer -> (undefined + defined)?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Я вам показал как поддерживается ФП. И да, для практических целей тормозящая реализация fibs на ленивых списках не нужна.
А тормозящая реализация чего нужна? Продемонстрируйте тогда нетормозящую поддержку ФП — я разве против?
EP>Для более сложных задач — возможно. Но вопрос был про простые задачи. EP>Было заявлено что fibs это идиоматический hello world, и ленивость это пища ФП. Если же для простейших задач ленивость вредна — то видимо это и не "пища ФП", ведь так?
Нет не так. В данном случае fibs демонстрирует некий инструментарий ФП. Для подтверждения заявлений о поддержке ФП было бы неплохо продемонстрировать поддержку такого инструментария. Для этой задачи полезность fibs вообще никакого значения не имеет, а вот краткость и легкость реализации fibs как раз очень удобна. Вы можете продемонстрировать что-то более впечатляющее, но если элегантная реализация fibs вызвала у вас такие затруднения, что вы даже показывать ее не хотите — с более впечатляющим и полезным примером будет только хуже.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Копирование, перемещение и refcounting тоже гарантирует доступность.
Копирование и перемещение можно использовать только в маргинальных юзкейсах. Подсчет ссылок действительно обеспечивает доступность для широкого спектра юзкейсов, вот только управлять памятью в условиях типичной для ФП ее организации (со множеством циклов) не может. С таким же успехом можно заявить, что аллокатор, который никогда не освобождает память, а только выделяет ее все гарантирует. А толку-то? На практике им пользоваться невозможно. Гарантии же как таковой для доступности языковых объектов в плюсах нет в принципе.
Не говоря уже о том, что использовать рефкоунтинг — это, фактически, конструировать замыкания вручную. А такая поддержка замыканий во всех языках есть.
EP>Есть точные GC — но они менее автоматизированные чем консервативные. При использовании точных нужно заменять T* на gc_ptr<T>, etc.
Ну замечательно, т.е. захватывать в замыкания можно будет нормально только объекты размещенные в специальной куче, откуда никаких ссылок не будет вообще, и все ссылки куда нужно как корневые регистрировать. Так и вижу миллионы программистов на плюсах, пишуших ФП-код и использующих точный сборщик.
Следующим шагом уже можно заявлять в качестве поддержки ФП интероп с хаскелем.
EP>Даже если не требовать prompt finalization, получается что нет никакого UFP-автоматизма — нельзя просто захватить какую-то переменную, нужно ещё и cкобки убирать, которые могут быть выше замыкания несколькими уровнями (что и было в исходном примере).
Да о чем речь — для файла гарантия слабее, чем для "языкового объекта", о чем я сразу и сказал (хотя бы потому, что есть метод закрытия файла у объекта-хендлера), но не слабее, чем в плюсах.
И что неожиданного в том, что инструментарий обеспечения prompt finalization за счет UFP не дает решать UFP без проблем? Был бы в языке аналогичный скобкам ограничитель времени жизни для языковых объектов — конечно о каком-то решении UFP в языке говорить было бы неуместно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет, не существует. Вы вообще-то процитировали ответ на ваш вопрос — см.выше.
Интересно, тогда что это у нас, например здесь http://ru.wikipedia.org/wiki/Singleton#.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_.D0.BD.D0.B0_C.23?)
K>Конкретно в текстовом редакторе: K>Rope в котором хранится редактируемый текст. Дерево — монада, порядок текстовых блоков — моноид. K>Лейаут виджетов — моноид. K>Последовательность нажатий на клавиши — функтор. K>Ширина окна — аппликативный функтор. K>Сериализатор/десериализатор файла настроек — аппликативный функтор. K>Парсер для подсветки кода — монада. K>IOC-контейнер — монада. K>и т.д.
Хы, ну если заменить слово монада на слово процедура, то классический ООП код тоже спокойно будет попадать под такое определение. )))
K>Именно тут я про пользу ничего не говорил. Просто объяснил почему этот код аналогом не является и почему на C++ аналог написать нельзя.
Угу, угу. аналога написать нельзя, но пользы от этого не имеющего аналогов нет. Я приблизительно так себе и представлял... )
K>Польза, впрочем, в обсуждаемом примере уже очевидна — оптимизатор выкинул несколько ненужных копирований (все кроме одного), в результате разницы по производительности между "наивным" примером с иммутабельными массивами и примером с мутабельными почти нет.
Польза в виде борьбы с проблемами, вызванными неудачным дизайном язык — это конечно очень интересно. )))
K>В чем же его "вынужденная кривизна"?
Ууу, там много всего. Хотя первоисточник проблемы общий. Ну если взять этот наш конкретный код... Как насчёт записать его в виде чего-то типа "M.write a 1 (M.read a 1)^2"? )
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет. Решена она не с помощью добавления императивного кода. Если пользоваться императивным кодом — тут и решать нечего. Последовательность функций меняющих массив по месту, никаких копирований между ними нет. Я же руками как раз добавил лишние копирования, а компилятор их убрал полностью автоматически.
Фокус в том, что изначальный мой код, который мы и оптимизировали, был вообще без императивных кусков.
Естественно очевидно, что можно было легко оптимизировать тот мой код, переписав его целиком на императивном (монадном) подвиде Хаскеля. Однако это никому не интересно.
Вы продемонстрировали любопытную технику, в которой свели императивную часть до маленьких областей непосредственной работы с массивом, окружив её копированием так, что оно гарантированно будет вырезаться оптимизатором.
Это было интересно. Но это не отменяет того факта, что получить оптимизированный код на нормальном Хаскеле не выходит без написания императивного кода. Причём в данном случае это особо чувствуется, т.к. сам код преобразования массива явно безопасный (никаких там системных вызовов и т.п.) и необходимость добавления монад обусловлена исключительно проблемами в дизайне языка.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Какая еще магия? Нетипизированный обобщенный код в плюсах сначала специализируется, а только потом типизируется. Во всех остальных языках типизируется обобщенный код. Вот бы в плюсах так, как во всех остальных языках!
Это ещё зачем? ) Если такой подход уменьшает наши возможности (Евгений приводил пример где и Хаскель пасует, а про Java/C# вообще можно смешно упоминать) в написание кода, при ровно тех же гарантиях отсутствия ошибок в создаваемом ПО? )
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>То есть, ты хочешь уровень привязать к инструментам ? Эдак окажется, что машинный код это самый высокоуровневй язык, потому что для него наверное пару миллионов инструментов, ну вот например декомпилер, линкер и тд и тд.
_>Нет, речь не про такие инструменты. А например про UML и ещё множество других из этой же области.
Uml это проектирование, а не язык программирования. Ты всего то спутал области. Эти инструменты применимы к любому языку программирования, хоть к ассемблеру. Более того — один и тот же набор квадратов одинаково пригоден для любого яп.
I>>А в Хаскеле — запросто.
_>На C++ весь код превратился в одну страницу, причём там код простейший, представляющий собой исключительно вызовы функций библиотечки. _>На Python'e будет буквально такой же код, как и на C++. Т.е. с точностью до замены скобочек на отступы. _>На Haskell'е ситуация будет чуть хуже за счёт монадного мусора, но если приравнять его к своеобразному аналогу скобочек, то снова получится буквально такой же код.
Обычно делается так — на низкоуровневом языке пишется небольшая либа, которая используется на высокоуровневом.
_>Тогда 1С придумывал математик под кайфом. )))
1С это никакой не ДСЛ.
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Uml это проектирование, а не язык программирования. Ты всего то спутал области. Эти инструменты применимы к любому языку программирования, хоть к ассемблеру. Более того — один и тот же набор квадратов одинаково пригоден для любого яп.
Ага, для любого... И как раз поэтому автор обсуждаемой статьи так радуется в начале, что хотя бы один тип uml диаграммок подходит для Хакскеля. А оставшуюся часть статьи пытается придумать свои велосипеды для замены других типов.
I>1С это никакой не ДСЛ.
1С — это много чего в одном флаконе. В том числе и DSL. )
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Uml это проектирование, а не язык программирования. Ты всего то спутал области. Эти инструменты применимы к любому языку программирования, хоть к ассемблеру. Более того — один и тот же набор квадратов одинаково пригоден для любого яп.
_>Ага, для любого...
Ты главное не отвлекайся — уровень унутреязыковых возможостей и уровень внешних инструментов это две большие разницы. А то я вижу ты готов ассемблер записать в языки сверх-высокого уровня на том основании, что можно взять и нагенерить код по квадратам из UML.
>И как раз поэтому автор обсуждаемой статьи так радуется в начале, что хотя бы один тип uml диаграммок подходит для Хакскеля. А оставшуюся часть статьи пытается придумать свои велосипеды для замены других типов.
UML это графический язык моделирования-проектирования общего назначения. Есть и другие, и все они, что характерно, предназачены для моделирования всевозможных решений самых разных инженерных задач в разных областях.
Никто в своем уме не разрабатывает диаграмки "для С++", "для Фортрана", "для лиспа Хаскеля".
I>>1С это никакой не ДСЛ.
_>1С — это много чего в одном флаконе. В том числе и DSL. )
А если я назову тебя исламистом, то ты станешь бегать по городу и кричать "Аллах Акбар" ?
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты главное не отвлекайся — уровень унутреязыковых возможостей и уровень внешних инструментов это две большие разницы. А то я вижу ты готов ассемблер записать в языки сверх-высокого уровня на том основании, что можно взять и нагенерить код по квадратам из UML.
Здесь речь уже не о конкретных языках, а о парадигмах. Функциональная, ООП и т.п. И у них, как оказывается, совсем разная ситуация с инструментами.
I>UML это графический язык моделирования-проектирования общего назначения. Есть и другие, и все они, что характерно, предназачены для моделирования всевозможных решений самых разных инженерных задач в разных областях.
Да, UML используется не только в программирование. Как раз поэтому там так много видов диаграмм, а непосредственно в программирование обычно используется только 3-5 их видов. Так вот, если мы попробуем использовать их при программирование в функциональном стиле, то увидим что ничего хорошего не выходит. Самая популярная диаграммка классов (на ней же часто рисуют и пакеты) не лезет никак. А именно с помощью этой диаграммы обычно получается "уменьшать сложность". Диаграмма объектов тогда естественно тоже не при делах, хотя она и не такая нужная. Диаграммки последовательности (для понимания взаимодействия) и деятельности (для понимания алгоритмов) хороши для императивного кода, так что в контексте чистого функционального языка тоже мимо (разве что для внутримонадного кода в случае Хаскеля и то криво). Что там остаётся то? Разве что диаграмма компонентов нормально ложится, и то она слишком высокоуровневая для эффективного уменьшения сложности.
А вместо всего этого, специалисты по функциональному подходу предлагают нам использовать просто концептуальные схемы (concept map), т.е. при переходе на функциональную парадигму мы получаем откат в инструментах проектирования-моделирования на десятилетия назад.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты главное не отвлекайся — уровень унутреязыковых возможостей и уровень внешних инструментов это две большие разницы. А то я вижу ты готов ассемблер записать в языки сверх-высокого уровня на том основании, что можно взять и нагенерить код по квадратам из UML.
_>Здесь речь уже не о конкретных языках, а о парадигмах. Функциональная, ООП и т.п. И у них, как оказывается, совсем разная ситуация с инструментами.
То есть, ты не готов обсуждать языки, а хочешь перепрыгнуть на внешние инструменты ?
I>>UML это графический язык моделирования-проектирования общего назначения. Есть и другие, и все они, что характерно, предназачены для моделирования всевозможных решений самых разных инженерных задач в разных областях.
_>Да, UML используется не только в программирование. Как раз поэтому там так много видов диаграмм, а непосредственно в программирование обычно используется только 3-5 их видов. Так вот, если мы попробуем использовать их при программирование в функциональном стиле, то увидим что ничего хорошего не выходит.
А если головой двери открывать, тоже ничего хорошего не выйдет. UML он для решения задач, а не для программирования в каком либо стиле. Вот надо тебе показать взаимодействие компонентов — все это на UML есть.
>Самая популярная диаграммка классов (на ней же часто рисуют и пакеты) не лезет никак.
Да запросто. Надо понимать, что ты за задачу хочешь решать. Если писать код с помощью UML, то это уже двадцать лет как отказались делать.
> А именно с помощью этой диаграммы обычно получается "уменьшать сложность".
Весь UML нужен для "уменьшать сложность", а не одна только диаграмма классов.
>Диаграмма объектов тогда естественно тоже не при делах, хотя она и не такая нужная. Диаграммки последовательности (для понимания взаимодействия) и деятельности (для понимания алгоритмов) хороши для императивного кода, так что в контексте чистого функционального языка тоже мимо
И это неправильный подход. Последовательности никуда не деваются. Начни с простого — авторизация, серверный компонент, Yesod.
>(разве что для внутримонадного кода в случае Хаскеля и то криво). Что там остаётся то? Разве что диаграмма компонентов нормально ложится, и то она слишком высокоуровневая для эффективного уменьшения сложности.
То есть, ты хотел писать код UMLом, не вышло. Странно, и на С++ та же фигня получается. UML давно перестали использовать так, как ты предлагаешь.
_>А вместо всего этого, специалисты по функциональному подходу предлагают нам использовать просто концептуальные схемы (concept map), т.е. при переходе на функциональную парадигму мы получаем откат в инструментах проектирования-моделирования на десятилетия назад.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, ты не готов обсуждать языки, а хочешь перепрыгнуть на внешние инструменты ?
Мы тут обсуждаем в основном парадигмы. А в этом контексте интересны и языки (поэтому часто Хаскель всплывает, как редкий пример чистого ФЯ) и инструменты и всё остальное.
Лично я положительно отношусь и к ООП и к функциональному стилю и ещё много к чему. Но в рамках гибридов. А вот "чистые" языки (как тот же Хаскель) на мой взгляд почти всегда оказываются ущербными. Конечно если мы говорим о языках общего назначения, а не о специализированных DSL.
А вот с твоей позицией "чем ближе код к функциональному стилю, тем он выше уровнем" я точно не могу согласиться. Это именно разные стили, а не разные уровни.
Ну и как пример, я тебе продемонстрировал, что в вопросе проектирования архитектуры (уж точно не низкоуровневый вопрос) у функциональной парадигмы наблюдается огромный провал по сравнению с тем же ООП.
I>А если головой двери открывать, тоже ничего хорошего не выйдет. UML он для решения задач, а не для программирования в каком либо стиле. Вот надо тебе показать взаимодействие компонентов — все это на UML есть.
Он для проектирования (в том числе). А проектированием занимаются уже с учётом предполагаемых к использования парадигм.
I>Да запросто. Надо понимать, что ты за задачу хочешь решать. Если писать код с помощью UML, то это уже двадцать лет как отказались делать.
Причём тут генерация кода? ) Или ты хочешь сказать, что типа генерации Haskell кода по диаграмме классов нет, а вот инструмент для рисования диаграммы классов по готовому Haskell коду существует? )))
I>
Что такое? ) Концептуальные схемы — это инструмент из которого вырос и UML и множество других инструментов. Но это всё зарождалось в 70-ые годы прошлого века. Рекомендовать его для программирования во втором десятилетие 21-го века можно только от полной безысходности (отсутствия каких либо продвинутых специализированных инструментов). А именно это и делают кругом любители функциональщины. И в обсуждаемой здесь статье с хабра (http://habrahabr.ru/post/211871/) автор этим занимается и в других местах тоже самое http://stackoverflow.com/questions/2457903/can-uml-be-used-to-model-a-functional-program...
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Мы тут обсуждаем в основном парадигмы. А в этом контексте интересны и языки (поэтому часто Хаскель всплывает, как редкий пример чистого ФЯ) и инструменты и всё остальное.
Для инструментов создай отдельный топик
_>Лично я положительно отношусь и к ООП и к функциональному стилю и ещё много к чему. Но в рамках гибридов. А вот "чистые" языки (как тот же Хаскель) на мой взгляд почти всегда оказываются ущербными. Конечно если мы говорим о языках общего назначения, а не о специализированных DSL.
А мне вот больше С++ кажется ущербным
_>А вот с твоей позицией "чем ближе код к функциональному стилю, тем он выше уровнем" я точно не могу согласиться. Это именно разные стили, а не разные уровни.
Я говорю про близость к математике, а тебе мерещится чтото другое.
_>Ну и как пример, я тебе продемонстрировал, что в вопросе проектирования архитектуры (уж точно не низкоуровневый вопрос) у функциональной парадигмы наблюдается огромный провал по сравнению с тем же ООП.
Ты ничего не продемонстрировал Архитектура это не рисование квадратов в UML, как то так. Сильно вряд ли хаскель будет работать с БД как то отлично от того, как это делают другие средтсва.
I>>А если головой двери открывать, тоже ничего хорошего не выйдет. UML он для решения задач, а не для программирования в каком либо стиле. Вот надо тебе показать взаимодействие компонентов — все это на UML есть.
_>Он для проектирования (в том числе). А проектированием занимаются уже с учётом предполагаемых к использования парадигм.
Нет, проектированием в первую очередь занимаются с учетом поставленых задач. Скажем конечный автомат выглядит абсолютно одинаково вне зависимости от того, каким языком будешь пользоваться.
А тебя послушать, так Хаскель не годится для автоматов, потом что в них требуется состояние реализовывать.
I>>Да запросто. Надо понимать, что ты за задачу хочешь решать. Если писать код с помощью UML, то это уже двадцать лет как отказались делать.
_>Причём тут генерация кода? ) Или ты хочешь сказать, что типа генерации Haskell кода по диаграмме классов нет, а вот инструмент для рисования диаграммы классов по готовому Haskell коду существует? )))
Ты хочешь программировать с помощью UML на хаскеле
I>>
_>Что такое? ) Концептуальные схемы — это инструмент из которого вырос и UML и множество других инструментов. Но это всё зарождалось в 70-ые годы прошлого века. Рекомендовать его для программирования во втором десятилетие 21-го века можно только от полной безысходности (отсутствия каких либо продвинутых специализированных инструментов). А именно это и делают кругом любители функциональщины. И в обсуждаемой здесь статье с хабра (http://habrahabr.ru/post/211871/) автор этим занимается и в других местах тоже самое http://stackoverflow.com/questions/2457903/can-uml-be-used-to-model-a-functional-program...
Я такое постоянно вижу при чем у архитектов которые насквозь императивные. А вот диаграммы классов последний раз видел даже не помню когда
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я говорю про близость к математике, а тебе мерещится чтото другое.
В общем моя точка зрения в том, что уровень языка не связан с используемой парадигмой.
I>Ты ничего не продемонстрировал Архитектура это не рисование квадратов в UML, как то так. Сильно вряд ли хаскель будет работать с БД как то отлично от того, как это делают другие средтсва.
UML вполне себе помогает в проектирование архитектуры.
А причём тут БД? ) Кстати, я конечно не в курсе деталей, но подозреваю, что в случае Хаскеля там будет сплошной монадный ужас.
I>Ты хочешь программировать с помощью UML на хаскеле
Нет, я хочу услышать о каких-нибудь инструментах, помогающие проектировать архитектуру большого приложения, которое предполагается написать на чистом функциональном языке.
Для случая ООП языков я таких инструментов знаю не мало.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я говорю про близость к математике, а тебе мерещится чтото другое.
_>В общем моя точка зрения в том, что уровень языка не связан с используемой парадигмой.
_>А причём тут БД? ) Кстати, я конечно не в курсе деталей, но подозреваю, что в случае Хаскеля там будет сплошной монадный ужас.
conn <- connectSqlite3 "test.db"
result <- quickQuery' conn "SELECT id, desc from test where id <= ? ORDER BY id, desc" [toSql maxId]
Ужос !
I>>Ты хочешь программировать с помощью UML на хаскеле
_>Нет, я хочу услышать о каких-нибудь инструментах, помогающие проектировать архитектуру большого приложения, которое предполагается написать на чистом функциональном языке. _>Для случая ООП языков я таких инструментов знаю не мало.
Это одни и те же инструменты. Если не задаваться целью программировать на UML, то получается примерно одно и то же.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я говорю про близость к математике, а тебе мерещится чтото другое.
_>В общем моя точка зрения в том, что уровень языка не связан с используемой парадигмой.
В общем ты никак не можешь сформулировать, что же такое уровень языка. О том, что в разных парадигмах есть языки разных уровней, напоминать не надо. Нужно взять да посмотреть, чем отличается императивный питон от императивного ассемблера или от императивного С++. Внезапно — питон ближе к математике чем два других.
С функциональщиной примерно так же — там нат никакой железячной специфики. За счет этого она будет уровнем повыше С++. Вот если в будущем изобретут язык "как С++" но с полноценной реализацией всех функциональных возможностей, тогда можно будет пересмотреть сказаное
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
О, как я и думал монадный ужас.
I>Это одни и те же инструменты. Если не задаваться целью программировать на UML, то получается примерно одно и то же.
Если брать известные инструменты (которые для ООП языков созданы), то в них максимум 10% возможностей получится использовать для чистых функциональных языков. И то, любители подобного стиля советуют не использовать эти инструменты вообще, а рисовать вместо этого руками в свободном стиле.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В общем ты никак не можешь сформулировать, что же такое уровень языка. О том, что в разных парадигмах есть языки разных уровней, напоминать не надо.
ОК, хоть в чём-то договорились. )
I>Нужно взять да посмотреть, чем отличается императивный питон от императивного ассемблера или от императивного С++.
Ууу там много чего.
I>Внезапно — питон ближе к математике чем два других.
Каким это местом?
I>С функциональщиной примерно так же — там нат никакой железячной специфики. За счет этого она будет уровнем повыше С++. Вот если в будущем изобретут язык "как С++" но с полноценной реализацией всех функциональных возможностей, тогда можно будет пересмотреть сказаное
Всё правильно. Но это исключительно следствие отсутствия "аппаратных функциональных исполнителей кода". Были вроде как некие попытки (lisp машины и т.п.), но сейчас это всё мертво. Вследствие этого, чистые функциональные языки работают в неких эммуляторах и соответственно не имеют нормального доступа к железу. Но это всё относится к некому текущему выбору индустрии (не в пользу функциональщины), а не к некой фундаментальной высокоуровневости функциональной парадигмы.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ужос !
_>О, как я и думал монадный ужас.
Не заметил, просто другой синтаксис, не такой как в С++
I>>Это одни и те же инструменты. Если не задаваться целью программировать на UML, то получается примерно одно и то же.
_>Если брать известные инструменты (которые для ООП языков созданы), то в них максимум 10% возможностей получится использовать для чистых функциональных языков. И то, любители подобного стиля советуют не использовать эти инструменты вообще, а рисовать вместо этого руками в свободном стиле.
Эти инструменты не создавались для языков. Они создавались для моделирования и проектирования. Что и объясняет, почему туда перекочевали вещи, которые используются в областях далёких от разработки.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Внезапно — питон ближе к математике чем два других.
_>Каким это местом?
Тем самым. ООП и обобщенное программирование в ём гораздо сильнее плюсового, а как ООП относится к математике, тебе показал Синклер.
I>>С функциональщиной примерно так же — там нат никакой железячной специфики. За счет этого она будет уровнем повыше С++. Вот если в будущем изобретут язык "как С++" но с полноценной реализацией всех функциональных возможностей, тогда можно будет пересмотреть сказаное
_>Всё правильно. Но это исключительно следствие отсутствия "аппаратных функциональных исполнителей кода". Были вроде как некие попытки (lisp машины и т.п.), но сейчас это всё мертво. Вследствие этого, чистые функциональные языки работают в неких эммуляторах и соответственно не имеют нормального доступа к железу. Но это всё относится к некому текущему выбору индустрии (не в пользу функциональщины), а не к некой фундаментальной высокоуровневости функциональной парадигмы.
Нету функциональных исполнителей, есть железо работающее по другим принципам. В ём нет инструкций которые манипулируют регистром IP, по той причине, что этот регистр отсутствует. Уже за счет этого код сам по себе становится немного другого уровня.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не заметил, просто другой синтаксис, не такой как в С++
Просто тут не видно всей монады. )))
I>Эти инструменты не создавались для языков. Они создавались для моделирования и проектирования. Что и
объясняет, почему туда перекочевали вещи, которые используются в областях далёких от разработки.
Ещё раз: "проектировать и моделировать" надо с учётом особенностей используемого для программирования языка. Так вот если мы возьмём чистый функциональный язык, то увидим, что наш инструмент для "проектирования и моделирования" резко теряет свои возможности.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Тем самым. ООП и обобщенное программирование в ём гораздо сильнее плюсового, а как ООП относится к математике, тебе показал Синклер.
С чего бы это в Питоне сильнее ООП и обобщённое программирование (а где оно там вообще в Питоне)?
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не заметил, просто другой синтаксис, не такой как в С++
_>Просто тут не видно всей монады. )))
Ну как обычно — вот здесь всё хорошо, а вот в той части, что не показана — ужос-ужос !
I>>Эти инструменты не создавались для языков. Они создавались для моделирования и проектирования. Что и _>объясняет, почему туда перекочевали вещи, которые используются в областях далёких от разработки.
_>Ещё раз: "проектировать и моделировать" надо с учётом особенностей используемого для программирования языка. Так вот если мы возьмём чистый функциональный язык, то
увидим, что наш инструмент для "проектирования и моделирования" резко теряет свои возможности.
Ну да, протокол single-side авторизации внезапно начнет зависеть от того, на каком языке он реализован. Вот чудо !
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Тем самым. ООП и обобщенное программирование в ём гораздо сильнее плюсового, а как ООП относится к математике, тебе показал Синклер.
_>С чего бы это в Питоне сильнее ООП и обобщённое программирование (а где оно там вообще в Питоне)?
С того, что там динамический полиморфизм, мультиметоды и много чего еще.
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>С того, что там динамический полиморфизм, мультиметоды и много чего еще.
_>Динамический полиморфизм есть наверное в любом ООП языке)))
Ога. Только возможности отличаются на порядки.
_>Мультиметодов в самом Питоне нет. Но их можно реализовать в виде библиотеки. Так же как и в C++.
Ну вот и сравни размер кода.
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Например попробуй реализовать такое — вызвать несуществующий метод у объекта. Разумеется, безо всяких исключений и тд и тд.
I>То есть, всё как завещал изобретатель ООП сэр Алан Кей (у которого ООП в с++ вызвало глубокое недоумение).
И?
В C++ будет ошибка времени компиляции, а в Питоне будет ошибка времени исполнения. В чём разница? )
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Например попробуй реализовать такое — вызвать несуществующий метод у объекта. Разумеется, безо всяких исключений и тд и тд.
I>>То есть, всё как завещал изобретатель ООП сэр Алан Кей (у которого ООП в с++ вызвало глубокое недоумение).
_>И?
_>В C++ будет ошибка времени компиляции, а в Питоне будет ошибка времени исполнения. В чём разница? )
Не угадал. Подсказка — в С++ нужна генерация кода, а в Питоне — работает само.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Например попробуй реализовать такое — вызвать несуществующий метод у объекта. Разумеется, безо всяких исключений и тд и тд. I>Не угадал. Подсказка — в С++ нужна генерация кода, а в Питоне — работает само.
Эврика! Только что проверил. Сделал на Питоне класс, у которого нет методов prove_P_equals_NP, print_money, get_meaning_of_life, do_everything_user_wanted, попробовал их вызвать — все отлично работают! Это прорыв!
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Эврика! Только что проверил. Сделал на Питоне класс, у которого нет методов prove_P_equals_NP, print_money, get_meaning_of_life, do_everything_user_wanted, попробовал их вызвать — все отлично работают! Это прорыв!
А сказать что хотел ?
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не угадал. Подсказка — в С++ нужна генерация кода, а в Питоне — работает само.
_>Это ты вообще о чём? )
Все о том же.
У тебя варианты
1. ты не в курсе, как такое делается — твоя компетенция недостаточна для продолжения разговора
2. не можешь признать фактическое положение дел — нет смысла с тобой продолжать
3. написать как есть
если ты выбираешь п.3, можно продолжить про область применения этой фичи, если у тебя есть какие то сомнения.
Итого, если таки п.3, то от тебя требуется или краткое описание или ссылка.
Вообще, судя по тому, как быстро ты прекратил тему мультиметодов, уже все ясно — уровень питона намного выше, чем С++.
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
DM>>Эврика! Только что проверил. Сделал на Питоне класс, у которого нет методов prove_P_equals_NP, print_money, get_meaning_of_life, do_everything_user_wanted, попробовал их вызвать — все отлично работают! Это прорыв!
I>А сказать что хотел ?
Хотел намекнуть, что в языках вроде питона можно вызвать некоторый специальный метод вместо несуществующего, но нельзя вызвать сам несуществующий, ему взяться неоткуда. Кстати, в D тоже есть такая фишка. А в С++ "вы не должны этого хотеть", там это ошибка времени компиляции, как и было сказано выше.
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Например попробуй реализовать такое — вызвать несуществующий метод у объекта. Разумеется, безо всяких исключений и тд и тд. I>То есть, всё как завещал изобретатель ООП сэр Алан Кей (у которого ООП в с++ вызвало глубокое недоумение).
При всем уважении к Кею и Smalltalk, конкретно эта фича совершенно бесполезна и, более того, вредна.
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Все о том же. I>У тебя варианты I>1. ты не в курсе, как такое делается — твоя компетенция недостаточна для продолжения разговора I>2. не можешь признать фактическое положение дел — нет смысла с тобой продолжать I>3. написать как есть
I>если ты выбираешь п.3, можно продолжить про область применения этой фичи, если у тебя есть какие то сомнения. I>Итого, если таки п.3, то от тебя требуется или краткое описание или ссылка.
Я пока вообще не понял решение какой задачи ты хочешь получить. Поставь уже задачу и обсудим. )
I>Вообще, судя по тому, как быстро ты прекратил тему мультиметодов, уже все ясно — уровень питона намного выше, чем С++.
Так с мультиметодами же всё очевидно. Их нет ни в C++ ни в Питоне. Но они легко реализуются с помощью библиотеки и в C++ и в Питоне. ) Или ты хочешь с этим поспорить? )
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Итого, если таки п.3, то от тебя требуется или краткое описание или ссылка.
_>Я пока вообще не понял решение какой задачи ты хочешь получить. Поставь уже задачу и обсудим. )
Пока речь про языковую фичу, именно о ней идет речь в ООП по Алану Кею. Сходи вверх по треду и посмотри, если забыл про что речь.
I>>Вообще, судя по тому, как быстро ты прекратил тему мультиметодов, уже все ясно — уровень питона намного выше, чем С++.
_>Так с мультиметодами же всё очевидно. Их нет ни в C++ ни в Питоне. Но они легко реализуются с помощью библиотеки и в C++ и в Питоне. )
Ну то есть ты утверждаешь, что многословное решение означает такой же уровень как и намного более краткое, я правильно понял ?
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
I>>С того, что там динамический полиморфизм, мультиметоды и много чего еще.
ARK>Нормальных мультиметодов в питоне нет (да и вообще нигде хорошей реализации нет).
Около десятка строчек дают вполне нормальную реализацию.
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
I>>А сказать что хотел ?
DM>Хотел намекнуть, что в языках вроде питона можно вызвать некоторый специальный метод вместо несуществующего, но нельзя вызвать сам несуществующий, ему взяться неоткуда.
Это несущественная разница. Если я пишу y = x.getNotExistedValue() и получаю в y ожидаемое значение, то совершенно неинтересно, существует ли реально такой метод или нет.
>Кстати, в D тоже есть такая фишка. А в С++ "вы не должны этого хотеть", там это ошибка времени компиляции, как и было сказано выше.
"не должны этого хотеть" это ограничение возможностей ООП.
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Пока речь про языковую фичу, именно о ней идет речь в ООП по Алану Кею. Сходи вверх по треду и посмотри, если забыл про что речь.
Угу. Просто ты так её обозвал, что фиг поймёшь о чём была речь. Другие участники подсказали уже, что ты про возможность перегрузки операции вызова методов. Как раз то, что я демонстрировал в этой темке на языке D, для реализации автоматического использования обычных функций и операторов с монадами. Это полезная возможность и жаль что в C++ её нет. Но не думаю, что она имеет какое-то отношение к уровню языка. Кстати, а C++ и D с твоей точки зрения языки одного уровня или нет?)))
I>Ну то есть ты утверждаешь, что многословное решение означает такой же уровень как и намного более краткое, я правильно понял ?
Хы, ну так подключение и использование библиотеки мультиметодов будет абсолютно одного уровня многословности...
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
ARK>>При всем уважении к Кею и Smalltalk, конкретно эта фича совершенно бесполезна и, более того, вредна.
I>Наоборот, она очень полезна и именно по этому её вводят с JavaScript. Сделай это 10 лет назад, сегодняшняя вебразработка выглядела бы намного иначе.
В чем же состоит полезность?
Вредность очевидна — банальные опечатки не дают ошибок даже в рантайме.
Не знаю, как для веб-разработки, но для general purpose programming это ужасно.
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Около десятка строчек дают вполне нормальную реализацию.
Вообще да, для Питона, как для динамического языка, это возможно. Все равно в нем нет никаких статических проверок. Подходящий метод не нашли — эксепшен, и всего делов. Но вообще мне такой подход не нравится.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
То, про что я сказал двумя ответами выше. "Без метапрограммирования никаких шаблонов проектирования в коде нет — только результат их применения в голове программиста. Поэтому к уровню кода они никакого значения не имеют."
В приведенном вами примере по ссылке метапрограммирование используется, так о чем мы все-таки говорим?
_>Хы, ну если заменить слово монада на слово процедура, то классический ООП код тоже спокойно будет попадать под такое определение. )))
Нет, потому что про монады, моноиды, функторы, категории можно что-то сказать, как-то определить, у них и свойства есть, так что можно рассуждать о коде. А "процедура" это то же что и "сепулька". Сказать про нее с определенностью ничего нельзя, каких-то свойств у нее нет.
_>Угу, угу. аналога написать нельзя, но пользы от этого не имеющего аналогов нет. Я приблизительно так себе и представлял... )
В данном случае разговор о том, что аналог написать нельзя — только и всего.
_>Польза в виде борьбы с проблемами, вызванными неудачным дизайном язык — это конечно очень интересно. )))
Неудачность дизайна вовсе ниоткуда не следует. Вы ее вводите исключительно потому, что в плюсах дизайн совсем другой, ну и для оправдания монадофобии. Иммутабельность как прием вполне полезна и рекомендуется даже в языках, где вовсе никак не поддерживается (т.е. с дизайном "удачным" по вашему, иммутабельность не поощряющем). В хаскеле она поддерживается, в том числе имеются и обсуждаемые средства уменьшения издержек.
_>Ууу, там много всего. Хотя первоисточник проблемы общий. Ну если взять этот наш конкретный код... Как насчёт записать его в виде чего-то типа "M.write a 1 (M.read a 1)^2"? )
Вы все таки имеете в виду
M.write a 1 (M.read a 1 ^2)
-- или
M.write a 1 $ M.read a 1 ^2
ну, как сделать ^2 я уже писал в соседних ветках, а $ заменяется на =<< и получаем
M.write a 1 =<< M.read a 1 ^2
синтаксические затраты на лифтинг безусловно есть, я их не отрицаю, я утверждаю, что они компенсируются синтаксической легковесностью остального. Т.е. применений и определений функций, лямбд, сечениями, паттерн мэтчингом и т.д.
К примеру, можно определить функцию
over v i f = M.write v i =<< f (M.read v i)
и писать
over v 1 (^2)
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Фокус в том, что изначальный мой код, который мы и оптимизировали, был вообще без императивных кусков.
Мое решение тоже императивных кусков не имеет. Строго говоря, даже код, лежащий в фундаменте такого решения не имеет императивных кусков, просто у вас специальное определение для слова "императивный".
_>Естественно очевидно, что можно было легко оптимизировать тот мой код, переписав его целиком на императивном (монадном) подвиде Хаскеля. Однако это никому не интересно.
Ну да. Так этого никто и не делал. Хотя, вообще говоря, писать конкретный фильтр в виде того, что вы называете "императивным куском" может быть даже удобнее. И даже в этом случае ваши претензии непонятны — ведь они заключались, в основном, в том, что "монадизация" меняет сигнатуры, способы композиции функций и вообще распространяется по коду. Тут же "императивный кусок" изолирован, функция нелифтнута, композиция обычная, а соединяет весь конвейер в один "императивный кусок" именно компилятор, автоматически.
_>Это было интересно.
Эти техники (устранение промежуточных структур данных) уже лет двадцать назад были впервые использованы в стандартной библиотеке ФЯ, так что самое любопытное тут не они, а способность видеть "ручную оптимизацию" на месте автоматической.
_>Но это не отменяет того факта, что получить оптимизированный код на нормальном Хаскеле не выходит без написания императивного кода.
Ну, раз вы сами определяете нечто под названием "нормальный хаскель" — вы же можете определить его как произвольно убогое подмножество хаскеля, так что ничего удивительного в этом нет.
Началось все с того, что вы утверждали, будто бы проблема промежуточных значений — принципиальная проблема ФП.
Я продемонстрировал, что проблема это вполне решаемая даже для кода не выходящего за рамки некоего выдуманного вами убогого хаскеля.
Но если нужно все преобразовывать к коду, который изменяет массив на месте, то вроде бы очевидно, что такой код (меняющий массив на месте) где-то присутствует, даже если в пользовательском коде его нет. Но если его нет в пользовательском коде, то что собственно вам не нравится?
_>Причём в данном случае это особо чувствуется, т.к. сам код преобразования массива явно безопасный (никаких там системных вызовов и т.п.)
у вас какое-то странное представление о системе контроля за эффектами. Что значит "явно безопасный"? Вот почему строки часто делают иммутабельными. Их изменять же полностью безопасно — никаких "системных вызовов" при этом?
_> и необходимость добавления монад обусловлена исключительно проблемами в дизайне языка.
И что это за проблемы?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Это ещё зачем? ) Если такой подход уменьшает наши возможности (Евгений приводил пример где и Хаскель пасует, а про Java/C# вообще можно смешно упоминать) в написание кода, при ровно тех же гарантиях отсутствия ошибок в создаваемом ПО? )
В чем-то типизация, конечно, уменьшает возможности, потому что она иногда (насколько редко — зависит от развитости системы типов) запрещает вполне осмысленный код. Но типизация и увеличивает возможности. А примеры можно всякие приводить. В том числе и такие
, где C++ пасует, а Java/C# — нет, не говоря уже о Хаскеле.
Я считаю, что интегрально, по совокупности плюсов и минусов, типизация лучше ее отсутствия.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Интересно, тогда что это у нас, например здесь http://ru.wikipedia.org/wiki/Singleton#.D0.9F.D1.80.D0.B8.D0.BC.D0.B5.D1.80_.D0.BD.D0.B0_C.23?)
K>То, про что я сказал двумя ответами выше. "Без метапрограммирования никаких шаблонов проектирования в коде нет — только результат их применения в голове программиста. Поэтому к уровню кода они никакого значения не имеют."
K>В приведенном вами примере по ссылке метапрограммирование используется, так о чем мы все-таки говорим?
Какое ещё метапрограммирование в C#?
K>В данном случае разговор о том, что аналог написать нельзя — только и всего.
Ну да, конечно. Аналог написать нельзя, потому что в других языках нет контроля эффектов. А какая польза у нас тут от контроля эффектов? ) Никакой, но всё равно аналог написать нельзя. Угу.
K>Неудачность дизайна вовсе ниоткуда не следует. Вы ее вводите исключительно потому, что в плюсах дизайн совсем другой, ну и для оправдания монадофобии. Иммутабельность как прием вполне полезна и рекомендуется даже в языках, где вовсе никак не поддерживается (т.е. с дизайном "удачным" по вашему, иммутабельность не поощряющем). В хаскеле она поддерживается, в том числе имеются и обсуждаемые средства уменьшения издержек.
Не стоит путать факультативную иммутабельность (есть почти во всех языках) и обязательную (типа как в Хаскеле). Так же как не стоит путать факультативную чистоту (как в D) и обязательную (как в Хаскеле). Я весьма интенсивно использую первое во всех языках, если оно доступно. А вот обязательный вариант мне кажется бредовым и только мешающим. Точнее я вполне могу допустить вариант когда мы будем писать не const у иммутабельных, а наборот mutable у мутабельных (а остальные будут по дефолту иммутабельными) — тоже вполне себе вариант. Но в Хаскеле то даже такого нет.
K>синтаксические затраты на лифтинг безусловно есть, я их не отрицаю, я утверждаю, что они компенсируются синтаксической легковесностью остального. Т.е. применений и определений функций, лямбд, сечениями, паттерн мэтчингом и т.д.
Ну так я нигде и не возражал тому, что классический (вне монад) Хаскель является вполне симпатичным языком. Только вот он как бы не для реального применения такой... )))
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В чем-то типизация, конечно, уменьшает возможности, потому что она иногда (насколько редко — зависит от развитости системы типов) запрещает вполне осмысленный код. Но типизация и увеличивает возможности. А примеры можно всякие приводить. В том числе и такие
, где C++ пасует, а Java/C# — нет, не говоря уже о Хаскеле.
Нет, по ссылке как раз виден пример убогости реализации в Java/C#, которая не поддерживает рекурсивные типы. Соответственно подобный Java/C# код по смыслу означает совершенно другое, чем он же, переведённый дословно на C++. А если переводить нормально, а не дословно, то всё будет нормально работать.
K>Я считаю, что интегрально, по совокупности плюсов и минусов, типизация лучше ее отсутствия.
Ну со вкусами конечно же спорить смысла нет — это личное дело каждого. )
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Какое ещё метапрограммирование в C#?
Убогое, как и все остальное в C#.
K>>В данном случае разговор о том, что аналог написать нельзя — только и всего.
_>Ну да, конечно. Аналог написать нельзя, потому что в других языках нет контроля эффектов. А какая польза у нас тут от контроля эффектов? ) Никакой, но всё равно аналог написать нельзя. Угу.
Ну да, конечно. Бузина не является дядькой, потому что дядька человек разумный, а бузина — наоборот — двудольная и цветковая. А какая польза у нас тут от разумности и двудольности? ) Никакой, но все равно дядька не бузина. Угу.
_>Не стоит путать факультативную иммутабельность (есть почти во всех языках) и обязательную (типа как в Хаскеле). Так же как не стоит путать факультативную чистоту (как в D) и обязательную (как в Хаскеле).
Конечно не стоит. Ну в этом и дизайнерское решение заключается. В одних языках иммутабельность используется, но ничего для этого нет. В других языках используется — а что-то для этого есть. Если мы что-то используем, то поддержка для этого (оптимизации, снижающие издержки, например) — это плохой дизайн. Программист же должен закалять волю и разум, а не расслабляться. Вот если поддержки нет — решение удачное, жизнь медом не покажется.
K>>синтаксические затраты на лифтинг безусловно есть, я их не отрицаю, я утверждаю, что они компенсируются синтаксической легковесностью остального. Т.е. применений и определений функций, лямбд, сечениями, паттерн мэтчингом и т.д.
_>Ну так я нигде и не возражал тому, что классический (вне монад) Хаскель является вполне симпатичным языком.
Все еще не совсем понятно, что значит "вне монад", но перечисленные мной факторы синтаксической легковесности вполне работают и используются и в том коде, который вы считаете "внутри монад".
_>Только вот он как бы не для реального применения такой... )))
Да позиция понятна, все симпатичное для реального применения не годится по той же причине, по какой плац нужно подметать ломом.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, по ссылке как раз виден пример убогости реализации в Java/C#, которая не поддерживает рекурсивные типы.
А чего не проблема шаманизма сразу? Вообще заявка мощная, такого комментария я вроде в эпохальных обсуждениях примера тут и на лоре не еще видел.
_>Соответственно подобный Java/C# код по смыслу означает совершенно другое, чем он же, переведённый дословно на C++. А если переводить нормально, а не дословно, то всё будет нормально работать.
Это нужно обязательно развить. Объясните скорее, при чем тут "неподдержка рекурсивных типов в C#/Java" и как это нормально перевести на C++?
K>>Я считаю, что интегрально, по совокупности плюсов и минусов, типизация лучше ее отсутствия. _>Ну со вкусами конечно же спорить смысла нет — это личное дело каждого. )
Это, вообще-то не дело вкуса, а технический вопрос.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Какое ещё метапрограммирование в C#? K>Убогое, как и все остальное в C#.
В C# версии 5+ вроде как должно появиться. Но здесь то текущая версия — где там конкретно обнаружилось метапрограммирование? )
K>Конечно не стоит. Ну в этом и дизайнерское решение заключается. В одних языках иммутабельность используется, но ничего для этого нет. В других языках используется — а что-то для этого есть. Если мы что-то используем, то поддержка для этого (оптимизации, снижающие издержки, например) — это плохой дизайн. Программист же должен закалять волю и разум, а не расслабляться. Вот если поддержки нет — решение удачное, жизнь медом не покажется.
Не, речь совсем не об этом. Поддержка — это обычно добавление каких-то возможностей. А в Хаскеле мы имеем скорее запрещение всего остального, кроме нашей парадигмы. Т.е. собственно говоря никто не мешал бы сделать язык со всеми возможностями Хаскеля и плюс нормальная поддержка других парадигм.
K>Да позиция понятна, все симпатичное для реального применения не годится по той же причине, по какой плац нужно подметать ломом.
К сожалению не годится. Вот я например не считаю тот же C++ идеалом (у меня к нему есть гора претензий) и с удовольствием заменил бы его на что-то лучшее, но не выходит по разным причинам. Ну в случае Хаскеля сам кривой дизайн языка не подходит. А вот например D (который является большим шагом вперёд в верном направление) не подходит из-за слабого развития инфраструктуры (собственно у Хаскеля есть и эта проблема, но там это уже не важно).
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Это нужно обязательно развить. Объясните скорее, при чем тут "неподдержка рекурсивных типов в C#/Java" и как это нормально перевести на C++?
Очевидно же, что одинаковая внешне запись на C++ и на Java/C# означают совершенно разные по реальному смыслу вещи. Так что тупое копирование кода из одного языка в другой не позволяет нам получать всегда работающий код, потому как он может просто означать другое. Как и в этом случае.
K>Это, вообще-то не дело вкуса, а технический вопрос.
Если бы так, то весь мир работал бы на 2-3 языка и всё. )
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Хы, ну так подключение и использование библиотеки мультиметодов будет абсолютно одного уровня многословности...
То есть, ты снова перепрыгиваешь с языка на использование фремворка. Странно как то — вроде говорим про язык, а у тебя все ужасы и прелести "где то там".
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В C# версии 5+ вроде как должно появиться.
Рефлексия и рантайм кодогенерация были всегда. Некоторые улучшения в кодогенерации во второй версии, убогое цитирование в третьей, несколько улучшенное в четвертой.
_> Но здесь то текущая версия — где там конкретно обнаружилось метапрограммирование? )
Конкретно здесь:
(S) typeof(S).GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic,
null,
new Type[0],
new ParameterModifier[0]).Invoke(null);
_>Не, речь совсем не об этом. Поддержка — это обычно добавление каких-то возможностей.
Обсуждаемые в данном случае добавленные возможности — это использование системы типов (вместо честного слова) для контроля за эффектами и оптимизации, устраняющие часть накладных расходов от иммутабельности.
_>А в Хаскеле мы имеем скорее запрещение всего остального, кроме нашей парадигмы.
Вовсе нет. В хаскеле есть все то, что и в императивных языках, плюс функции, которых в императивных языках нет (только процедуры).
Если в бестиповом языке есть только тип ВсеЛюбое и мы можем складывать строки с массивами и умножать на числа, а в типизированном языке
есть типы для строк чисел и массивов — это же не значит, что "нет добавления возможностей", "запрещение всего остального". Аналогично и в хаскеле, на уровне типов различаются функции, которые в императивном языке различить невозможно.
_>Т.е. собственно говоря никто не мешал бы сделать язык со всеми возможностями Хаскеля и плюс нормальная поддержка других парадигм.
И где же этот чудо-язык? Его, конечно, сделать нельзя. Какие есть плюсы у хаскеля?
1) Более-менее полноценная поддержка для комбинирования комбинаторов.
2) Возможность рассуждать об этих комбинаторах как о математических объектах (с оговорками).
Для этого нужна более-менее нормальная система типов, полноценная поддержка ленивости, специальные оптимизации, и контроль за эффектами как сам по себе, так и для нормальной работы ленивости и оптимизатора. Неплохо было бы еще и завершимость проверять, чего в хаскеле нет и в этом смысле (как и в аспекте системы типов) он язык компромиссный и недоделанный. Собственно, на этом направлении и идет дальнейшее развитие как самого хаскеля, так и связанное с появлением родственных языков вроде омеги, агды и идриса. В этих языках могут отказаться от ленивости по умолчанию, но не от контроля за эффектами.
Если под "нормальной поддержкой других парадигм" вы понимаете именно отказ от контроля за эффектами — то с рассуждениями о коде, нормальной ленивостью и оптимизациями можно распрощаться, а значит и с полноценным комбинированием комбинаторов. Т.е. остается у нас только более-менее полноценная система типов и мы попадаем в мертвую зону между хаскелем и так называемыми "гибридами", забитую мертвыми ML-ями и дышащим на ладан окамлом. Это вечные девяностые — прогресс отсюда никуда не двинуть. От гибридов языки мертвой зоны выгодно отличаются полноценными системами типов и модулей, которыми гибриды жертвуют ради использования библиотек и рантаймов популярных мейнстримовых языков, но — по всей видимости — этого недостаточно.
Т.е. язык вашей мечты это, скажем так, предыдущее поколение ФЯП, после середины 2000-х либо вовсе умерших, либо влачащих жалкое существование и имеющих популярность малую даже в сравнении с хаскелем и успешными "гибридами", которые сами большой популярностью похвастать не могут.
Если под другой парадигмой понимать ООП, причем мейнстримовое, с сабтайпингом, а не марсианское-структурное, какое возможно в хаскеле и некоторых "негибридных" мл-ях, то оно наносит такой удар по системе типов, что о хоть сколько нибудь полноценной поддержке ФП говорить уже не приходится. Это так называемые "гибриды", которые любят декларировать "мультипарадигменность", но ФП там, как колбаса при коммунизме: чего не спроси — отвечают, что потребности нет.
_>К сожалению не годится. Вот я например не считаю тот же C++ идеалом (у меня к нему есть гора претензий) и с удовольствием заменил бы его на что-то лучшее, но не выходит по разным причинам. Ну в случае Хаскеля сам кривой дизайн языка не подходит. А вот например D (который является большим шагом вперёд в верном направление) не подходит из-за слабого развития инфраструктуры (собственно у Хаскеля есть и эта проблема, но там это уже не важно).
Ну, то есть, нужен язык в точности как C++, но с перламутровыми пуговицами? Тут, как мне кажется, надеяться не на что. Перламутровых пуговиц никогда не будет достаточно, чтоб перевесить инфраструктуру плюсов, в которую человеколет вложено чуть ли не больше, чем во все остальные языки вместе взятые.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Очевидно же, что одинаковая внешне запись на C++ и на Java/C# означают совершенно разные по реальному смыслу вещи.
Это, конечно, верно. Собственно, это как раз пример, написанный для того, чтоб это продемонстрировать.
_>Так что тупое копирование кода из одного языка в другой не позволяет нам получать всегда работающий код, потому как он может просто означать другое. Как и в этом случае.
Ну так я и спрашиваю — а как это перевести на C++ нормально?
И при чем тут "неподдержка рекурсивных типов в C#/Java"?
K>>Это, вообще-то не дело вкуса, а технический вопрос. _>Если бы так, то весь мир работал бы на 2-3 языка и всё. )
Тут неявно предполагается, что этот фактор единственный или, по крайней мере, решающий. Это, конечно, не так.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали: DM>Хотел намекнуть, что в языках вроде питона можно вызвать некоторый специальный метод вместо несуществующего, но нельзя вызвать сам несуществующий, ему взяться неоткуда. Кстати, в D тоже есть такая фишка. А в С++ "вы не должны этого хотеть", там это ошибка времени компиляции, как и было сказано выше.
Ну вот поэтому С++ и нравится не всем. В частности, для банальной вещи — реализация proxy в какой-нибудь RPC инфраструктуре — плюсы предлагают пользоваться компиляторами IDL. А современные динамические языки просто проксируют всё, что пришло.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, ты снова перепрыгиваешь с языка на использование фремворка. Странно как то — вроде говорим про язык, а у тебя все ужасы и прелести "где то там".
Так это ты предложил пообсуждать фичи отсутствующие в языках, но при этом имеющие множественные реализации в виде библиотек. Хотя лично я не особо представляю что тут собственно обсуждать — тут просто есть факт возможности/невозможности реализации данной фичи на данном языке. Ну и ещё можно добавить факт наличия/отсутствия уже готовой библиотеки. По поводу мультиметодов для C++ и Питона в этом смысле разницы нет.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Рефлексия и рантайм кодогенерация были всегда. Некоторые улучшения в кодогенерации во второй версии, убогое цитирование в третьей, несколько улучшенное в четвертой.
Ааа ну рантайм кодогенерация безусловно есть. В таком смысле метапрограммирование есть и в javascript и в bash. ))) Да и на ассемблере можно. )
K>Вовсе нет. В хаскеле есть все то, что и в императивных языках, плюс функции, которых в императивных языках нет (только процедуры). K>Если в бестиповом языке есть только тип ВсеЛюбое и мы можем складывать строки с массивами и умножать на числа, а в типизированном языке K>есть типы для строк чисел и массивов — это же не значит, что "нет добавления возможностей", "запрещение всего остального". Аналогично и в хаскеле, на уровне типов различаются функции, которые в императивном языке различить невозможно.
Вот никаких вы не можете понять простейшую вещь. Для данной фичи (например чистоты/ленивости) в языке могут быть не только режимы "не имеем поддержки" (как в большинстве языков) и "обязательно к использованию" (как в Хаскеле). Вполне возможен вариант "есть полноценная поддержка, но использовать фичу не обязательно" (как в D относительно чистоты).
K>И где же этот чудо-язык? Его, конечно, сделать нельзя. Какие есть плюсы у хаскеля?
K>1) Более-менее полноценная поддержка для комбинирования комбинаторов. K>2) Возможность рассуждать об этих комбинаторах как о математических объектах (с оговорками).
Это всё скорее следствия.
K>Для этого нужна более-менее нормальная система типов, полноценная поддержка ленивости, специальные оптимизации, и контроль за эффектами как сам по себе, так и для нормальной работы ленивости и оптимизатора. Неплохо было бы еще и завершимость проверять, чего в хаскеле нет и в этом смысле (как и в аспекте системы типов) он язык компромиссный и недоделанный. Собственно, на этом направлении и идет дальнейшее развитие как самого хаскеля, так и связанное с появлением родственных языков вроде омеги, агды и идриса. В этих языках могут отказаться от ленивости по умолчанию, но не от контроля за эффектами.
Так пускай будет даже по умолчанию такой режим, но должен быть спокойный способ не использовать данную фичу. Я уже приводил пример. Что в одних языках переменные по умолчанию мутабельные и есть слово const. Можно сделать наоборот и сделать иммутабельные по умолчанию и добавить ключевое слово mut (как в том же Rust) — это будет ближе к функциональному, но при этом не отметает поддержку классического. А в Хаскеле у нас его фичи не просто по умолчанию, а обязательны! В этом и есть ключевой минус.
K>Если под "нормальной поддержкой других парадигм" вы понимаете именно отказ от контроля за эффектами — то с рассуждениями о коде, нормальной ленивостью и оптимизациями можно распрощаться, а значит и с полноценным комбинированием комбинаторов. Т.е. остается у нас только более-менее полноценная система типов и мы попадаем в мертвую зону между хаскелем и так называемыми "гибридами", забитую мертвыми ML-ями и дышащим на ладан окамлом. Это вечные девяностые — прогресс отсюда никуда не двинуть. От гибридов языки мертвой зоны выгодно отличаются полноценными системами типов и модулей, которыми гибриды жертвуют ради использования библиотек и рантаймов популярных мейнстримовых языков, но — по всей видимости — этого недостаточно.
Не отказ, а опциональность. Кстати, OCaml очень даже не плохой язык, но сейчас несколько устарел уже.
K>Т.е. язык вашей мечты это, скажем так, предыдущее поколение ФЯП, после середины 2000-х либо вовсе умерших, либо влачащих жалкое существование и имеющих популярность малую даже в сравнении с хаскелем и успешными "гибридами", которые сами большой популярностью похвастать не могут.
Языка моей мечты я пока не видел. Но это будет скорее в том направление, что задают D, Rust с одной стороны и Python, Ruby и т.п. с другой.
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Это, конечно, верно. Собственно, это как раз пример, написанный для того, чтоб это продемонстрировать.
И в чём смысл демонстрировать такую очевидную вещь? )
K>Ну так я и спрашиваю — а как это перевести на C++ нормально? K>И при чем тут "неподдержка рекурсивных типов в C#/Java"?
На C++ подобные вещи вообще по другому записывают. Точнее то, что записано на C#/Java. Вот на Хаскеле (как я понял из обсуждения там) у нас совсем другой расклад с этим примером...
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ааа ну рантайм кодогенерация безусловно есть. В таком смысле метапрограммирование есть и в javascript и в bash. ))) Да и на ассемблере можно. )
Ваши ассоциативные ряды, конечно, интересны, но для тех, кто интересуется вашим внутренним миром, в отрыве от данного разговора. Давайте в это углубляться не будем и вернемся к тому, о чем мы говорили. Вы упомянули паттерны проектирования, как код на языке, а не некие неформальные концепции. Я попросил пояснить, имеется ли в виду метапрограммирование. Вы ответили, что нет, не имеется, но привели пример с использованием метапрограммирования. Вы тут противоречия не замечаете?
_>Вот никаких вы не можете понять простейшую вещь. Для данной фичи (например чистоты/ленивости) в языке могут быть не только режимы "не имеем поддержки" (как в большинстве языков) и "обязательно к использованию" (как в Хаскеле). Вполне возможен вариант "есть полноценная поддержка, но использовать фичу не обязательно" (как в D относительно чистоты).
Если данную фичу — контроль за эффектами "использовать не обязательно", то это означает, что таких фич как:
1) Полноценная ленивость
2) Возможность рассуждать о коде
3) Оптимизации, существенно меняющие код
4) Полноценное комбинирование комбинаторов
у нас нет. Т.е. если использовать контроль за эффектами не обязательно, то используете вы контроль за эффектами или нет уже не важно: он бесполезен.
K>>1) Более-менее полноценная поддержка для комбинирования комбинаторов. K>>2) Возможность рассуждать об этих комбинаторах как о математических объектах (с оговорками).
_>Это всё скорее следствия.
Ну да, это следствия дизайна хаскеля, который проектировался так, чтоб в нем было и первое и второе, т.е. как полноценный ФЯ.
_>Так пускай будет даже по умолчанию такой режим, но должен быть спокойный способ не использовать данную фичу. Я уже приводил пример. Что в одних языках переменные по умолчанию мутабельные и есть слово const. Можно сделать наоборот и сделать иммутабельные по умолчанию и добавить ключевое слово mut (как в том же Rust) — это будет ближе к функциональному, но при этом не отметает поддержку классического. А в Хаскеле у нас его фичи не просто по умолчанию, а обязательны! В этом и есть ключевой минус.
Ну так "иммутабельность по умолчанию" вроде let и let mutable против var const и var — это никакая не полноценная поддержка иммутабельности. Это только некоторый способ простимулировать написание "хорошего" кода и штрафовать "плохой", наподобие обсуждаемой (и осуждаемой мной) тут раньше системы карательных наименований. Упомянутую мной здесь пользу (специфические оптимизации, возможность рассуждать о коде и полноценная ленивость) на такой базе не построить, такая "поддержка" во всех ml-ях есть, а вот нормальной поддержки, без кавычек, там как раз и нет.
_>Не отказ, а опциональность.
В данном случае практически значимой разницы между "опциональность" и "отказ" нет.
_>Кстати, OCaml очень даже не плохой язык, но сейчас несколько устарел уже.
OCaml, конечно, лучше подавляющего большинства языков, и устаревший по сравнению с языками, которые можно по пальцам если не одной, то двух рук точно пересчитать (причем подавляющее большинство помимо авторов никто не знает). Это, однако, больше говорит не о качествах окамла, а о плачевном положении в области разработки языков и об удручающей неграмотности и узком кругозоре типичного автора языка программирования.
_>Языка моей мечты я пока не видел. Но это будет скорее в том направление, что задают D, Rust с одной стороны и Python, Ruby и т.п. с другой.
Могу вам только позавидовать, потому что такого добра будет еще немало сделано: это как раз те автоматы калашникова, которые всегда получаются у типичного автора ЯП.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И в чём смысл демонстрировать такую очевидную вещь? )
Я видел (и сам вел) несколько дискуссий длиной в бразиллион постов с теми, для кого это вовсе не очевидная вещь. Правда, демонстрировать ее действительно бесполезно: участники дискуссий остаются при своих заблуждениях.
K>>Ну так я и спрашиваю — а как это перевести на C++ нормально? K>>И при чем тут "неподдержка рекурсивных типов в C#/Java"?
_>На C++ подобные вещи вообще по другому записывают.
Это вы уже говорили. Я и спрашиваю: по другому — как?
_>Точнее то, что записано на C#/Java. Вот на Хаскеле (как я понял из обсуждения там) у нас совсем другой расклад с этим примером...
Как раз сходство между хаскельным, C# и Java кодом вполне прослеживается, потому что параметрический полиморфизм в этих языках в некоторой степени схожий, про C++ этого, конечно, не скажешь.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так это ты предложил пообсуждать фичи отсутствующие в языках, но при этом имеющие множественные реализации в виде библиотек. Хотя лично я не особо представляю что тут собственно обсуждать — тут просто есть факт возможности/невозможности реализации данной фичи на данном языке.
Мы говорим про уровень, а не про возможность-невозможность. Всё реализуемо везде. Это следует из полноты по тьюрингу. Вопрос только в количество строчек и выразительности результата. Вот это и есть уровень.
>Ну и ещё можно добавить факт наличия/отсутствия уже готовой библиотеки. По поводу мультиметодов для C++ и Питона в этом смысле разницы нет.
Разница есть. В С++ надо пахать и пахать, а в питоне на порядок меньше кода.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>То, про что я сказал двумя ответами выше. "Без метапрограммирования никаких шаблонов проектирования в коде нет — только результат их применения в голове программиста. Поэтому к уровню кода они никакого значения не имеют."
Лушче говорить 'паттерны', особенно если в контексте слово шаблон используется как template.
Не совсем понятно, что значит "шаблона нет, но есть результат его применения". Чтото навроде "слова 'жопа' нет, но есть и результат и обозначаемое этим словом место"
Паттерн программирования это просто какая то фича, которая поддерживается на уровне библиотеки или соглашения.
Разумеется, если паттерны применены правильно, то есть, легко обсуждать, использовать, майнтейнить, изучать, исследовать, трансформировать и тд и тд.
Сложное на самом деле определение для понимания, но дело в том, что такие же проблемы буквально везде, например есть слова здоровье, свобода, справедливость, благополучие и тд и тд. Если задаться целью определить все слова через родовые понятия, то придется кое где ходить по кругу. Для решения этой проблемы придется признать существование аксиоматических понятий или понятий не имеющих определения. Например в математике есть такое понятие, например "множество"
С другой стороны, паттерн это просто промежуточный шаг в формировании понятия, то есть полноценной абстракции. Так у людей происходит накопление опыта, в силу использования речи, что очевидно.
Можешь попробовать придумать область деятельности, которую до тебя никто еще не открывал и сразу увидишь, как люди первым делом вводят паттерны, а когда паттерны остаканиваются, появляются абстрации, понятия и сопутствующая математика.
Сделать это очень просто — придумай и опубликуй хорошую игру или открой новый бизнес. Как только оформится более-менее внятное коммюнити, сразу увидишь и паттерны и всё остальное. Часть будет новых, в зависимости от новизны твоей идеи, часть будет заинствованых, так же в зависимости от новизны идеи. Часть появится быстро, часть появится через некоторое время. Паттерны программирования ничем от этих паттернов не отличаются, абсолютно ничем.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ваши ассоциативные ряды, конечно, интересны, но для тех, кто интересуется вашим внутренним миром, в отрыве от данного разговора. Давайте в это углубляться не будем и вернемся к тому, о чем мы говорили. Вы упомянули паттерны проектирования, как код на языке, а не некие неформальные концепции. Я попросил пояснить, имеется ли в виду метапрограммирование. Вы ответили, что нет, не имеется, но привели пример с использованием метапрограммирования. Вы тут противоречия не замечаете?
В принципе паттерны проектирования максимально полезны именно введением некого общего языка понятий между программистами. Однако они вполне существуют и в виде кусков готового кода или даже библиотек. И для реализации в коде очень многих паттернов никакого метапрограммирования не требуется.
А что у нас с паттернами проектирования в функциональном стиле? ) Или с инструментами типа UML для функциональной парадигмы? )
K>Если данную фичу — контроль за эффектами "использовать не обязательно", то это означает, что таких фич как: K>1) Полноценная ленивость K>2) Возможность рассуждать о коде K>3) Оптимизации, существенно меняющие код K>4) Полноценное комбинирование комбинаторов K>у нас нет. Т.е. если использовать контроль за эффектами не обязательно, то используете вы контроль за эффектами или нет уже не важно: он бесполезен.
С чего бы это?
K>Ну так "иммутабельность по умолчанию" вроде let и let mutable против var const и var — это никакая не полноценная поддержка иммутабельности. Это только некоторый способ простимулировать написание "хорошего" кода и штрафовать "плохой", наподобие обсуждаемой (и осуждаемой мной) тут раньше системы карательных наименований. Упомянутую мной здесь пользу (специфические оптимизации, возможность рассуждать о коде и полноценная ленивость) на такой базе не построить, такая "поддержка" во всех ml-ях есть, а вот нормальной поддержки, без кавычек, там как раз и нет.
Я и не сказал, что поддержка заключается в наличие ключевого слова. Это был просто пример того, как можно делать упор на определённом стиле, не запрещая при этом другие. Никто не мешает сделать полноценную поддержку и при этом не навязывать её обязательное использование.
K>В данном случае практически значимой разницы между "опциональность" и "отказ" нет.
Опять же с чего бы это? ) Тот же пример чистоты в D говорит об обратном... )
K>Могу вам только позавидовать, потому что такого добра будет еще немало сделано: это как раз те автоматы калашникова, которые всегда получаются у типичного автора ЯП.
Кстати, хочу интересный нюанс отметить в этом смысле. В последнее время становятся нормой гетерогенные системы — очень многие успешные проекты используют несколько разных языков в связке. Казалось бы самое оно взять для такой связки языки с разными парадигмами. Ну например какой-нибудь там Фортран для вычислительной части и хаскель (или что-то скриптовое похожего вида, кстати а такое вообще есть?) для остального и т.п. Однако, если мы посмотрим в реальность, то увидим что среди современных сложных проектов лидирует связка C++/Python. Т.е. два мультипарадигменных языка! Более того, на мой взгляд, при всех своих различиях, они очень похожи одним базовым принципом: в них напихано множество различных парадигм и концепций, но при этом ни одна не является обязательной для использования. И судя по индустрии в данный момент, именно этот принцип и оказывается "побеждающим". При этом работа в такой связке оказывается очень похожа на обоих уровнях, а добавка Питона к C++ по сути позволяет повысить скорость разработки без потери эффективности и защищённости продукта. Думаю это и есть текущий вектор в будущее...
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Я видел (и сам вел) несколько дискуссий длиной в бразиллион постов с теми, для кого это вовсе не очевидная вещь. Правда, демонстрировать ее действительно бесполезно: участники дискуссий остаются при своих заблуждениях.
Не очевидно, что глупо пытаться переписывать в лоб с одного языка на другой? Хм хм хм...
K>Это вы уже говорили. Я и спрашиваю: по другому — как?
Вообще данная задача весьма бредова на мой взгляд, ну да ладно, если уж ради форумного обсуждения... Например можно что-то типа такого сделать:
#define cint struct{const int value;}
template<typename T> class Cons{
vector<int> data;
Cons()=default;
template<typename S, typename F> friend Cons<S> MakeCons(S s, F f);
template<typename S> friend int ScalarProduct(const Cons<S>& c1, const Cons<S>& c2);
};
template<typename S, typename F> Cons<S> MakeCons(S s, F f)
{
Cons<S> r;
for(int i=0; i<s.value; i++) r.data.push_back(f(i));
return r;
}
template<typename S> int ScalarProduct(const Cons<S>& c1, const Cons<S>& c2)
{return inner_product(c1.data.cbegin(), c1.data.cend(), c2.data.cbegin(), 0);}
int main()
{
int n;
cin>>n;
cint size{n};
auto cons1=MakeCons(size, [](int i){return i;});
auto cons2=MakeCons(size, [](int i){return i+1;});
//cint size1{n+1};
//auto cons2=MakeCons(size1, [](int i){return i;});//а такое не будет компилироваться
cout<<ScalarProduct(cons1, cons2)<<endl;
}
Получается аналогичная защита. Но при этом позволяет спокойно создавать компоненты для произведения не обязательно внутри одной функции, как в примерах C#/Java. Ну а про расход памяти и быстродействие думаю можно даже не упоминать — они тут получаются вообще не сравнимыми... )
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
>>Ну и ещё можно добавить факт наличия/отсутствия уже готовой библиотеки. По поводу мультиметодов для C++ и Питона в этом смысле разницы нет.
I>Разница есть. В С++ надо пахать и пахать, а в питоне на порядок меньше кода.
При использование готовой библиотеки? ) Не думаю. ) Если конечно не иметь в виду обычную разницу между динамическими и статическими языками в объявлениях типов и т.п.
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Разница есть. В С++ надо пахать и пахать, а в питоне на порядок меньше кода.
_>При использование готовой библиотеки? ) Не думаю. ) Если конечно не иметь в виду обычную разницу между динамическими и статическими языками в объявлениях типов и т.п.
Ну то есть библиотеки писать не надо, правильно ?
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В принципе паттерны проектирования максимально полезны именно введением некого общего языка понятий между программистами.
Точнее попыткой введения такого языка, не всегда удачной, потому что понятия это довольно расплывчатые и неформальные.
_>Однако они вполне существуют и в виде кусков готового кода или даже библиотек. И для реализации в коде очень многих паттернов никакого метапрограммирования не требуется.
Смотря что значит "для реализации в коде". Паттерн — это типовая проблема и решение для нее. Если имеется в виду решенная в соответствии с паттерном проблема — то да, конечно не требуется. То, что делает инструментарий метапрограммирования автоматически — программист сделал вручную без этого инструментария. Если имеется в виду код-решатель проблемы, который применяется к одному коду с проблемой и производит код без проблемы, с решением — то тут без метапрограммирования, как правило, не обойтись.
_>А что у нас с паттернами проектирования в функциональном стиле? ) Или с инструментами типа UML для функциональной парадигмы? )
Общим языком для ФП-программистов является (обычно, популяризированная и адаптированная) математика вообще и теория категорий в частности.
K>>если использовать контроль за эффектами не обязательно, то используете вы контроль за эффектами или нет уже не важно: он бесполезен.
_>С чего бы это?
Нет, я допускаю, что какая-то польза есть. Только не практическая, выражающаяся в получении новых инструментов для решения проблем, а духовная. "Чувство глубокого удовлетворения" какое-нибудь.
_>Я и не сказал, что поддержка заключается в наличие ключевого слова.
А в чем еще она заключается?
_> Это был просто пример того, как можно делать упор на определённом стиле, не запрещая при этом другие.
Ну я и говорю, речь идет о некоем синтаксическом воспитании. Большого смысла я в нем не вижу.
_> Никто не мешает сделать полноценную поддержку и при этом не навязывать её обязательное использование.
Смысл "навязывания использования" в том, что программист может рассчитывать, что другой программист делает то и другое, а вот это наоборот не делает. И, следовательно, делать то, чего иначе он делать не мог бы. Соответственно и компилятор может делать не консервативные оптимизации, которые только и возможны в условиях, когда никто никому ничего не навязывает, а гораздо более интересные оптимизации, которые опять таки делают практически приемлемым код, который без них только для форумных споров годится. Что тоже возможности программиста расширяет.
_>Опять же с чего бы это? ) Тот же пример чистоты в D говорит об обратном... )
О чем же он говорит? Это как-то конкретизировать можно? Нормальной ленивости в D нет, это я знаю. А как там с оптимизациями или, к примеру, STM дела обстоят?
_>хаскель (или что-то скриптовое похожего вида, кстати а такое вообще есть?)
Зависит от того, насколько похожее требуется и что под скриптовостью понимается.
_> C++/Python. Т.е. два мультипарадигменных языка! _> в них напихано множество различных парадигм и концепций
Где же в них мультипарадигменность? Два ООП языка. Они кроме ООП разве еще что-то поддерживают?
_> но при этом ни одна не является обязательной для использования.
Довольно сложно не использовать одну из одной доступных парадигм. Разве что не используя эти языки вообще.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
_>>Ну это проблемы исключительно ASP.NET. Как видно, достаточно универсальное решение делается на C++ всего в пару десятков строчек. ))) I>Ну сколько можно — еще одна попытка контекстно-свободный язык парсить регэкспом
Любой движок "регэкспов", поддерживающий lookahead/lookbehind, backreferences и (опционально) balancing groups, по факту реализуется на стековых автоматах, способных распознавать, как минимум, все LR(k) КС-языки. Пара примеров:
using System;
using System.Text.RegularExpressions;
namespace RegexesDemo
{
class Program
{
private static void Run(string regex, string[] items, string positive, string negative)
{
var r = new Regex(regex, RegexOptions.IgnorePatternWhitespace);
foreach (var item in items)
{
Console.WriteLine("\"{0}\" - {1}", item, r.IsMatch(item) ? positive : negative);
}
Console.WriteLine();
}
private static void Main()
{
// Проверка баланса скобок (распознавание строк языка "S → SS | (S) | ϵ")
Run(@"^(((?'Open'\())+((?'Close-Open'\)))+)*(?(Open)(?!))$"
,
new[] {"()", ")(", "(())", "((()", "(()())", "(()()("}, "сбалансировано", "не сбалансировано"
);
// Проверка палиндромности (распознавание строк языка "P → ϵ | a | b | ... | z | aPa | bPb | ... | zPz")
Run(
@"(?<Character>[a-z])+[a-z]?(?<-Character>\k<Character>)+(?(Character)(?!))",
new[] { "test", "kayak", "blablabla" },
"палиндром", "не палиндром"
);
Console.ReadKey();
}
}
}
Удобство синтаксиса современных "регэскпов" для описания нерегулярных грамматик и эффективность полученных таким образом парсеров — отдельная тема, но их использование в этом качестве уже давно не может считаться попыткой "свести контекстно-свободную грамматику к регулярной" (с)
Здравствуйте, kochetkov.vladimir, Вы писали:
KV>Любой движок "регэкспов", поддерживающий lookahead/lookbehind, backreferences и (опционально) balancing groups, по факту реализуется на стековых автоматах, способных распознавать, как минимум, все LR(k) КС-языки.
Спасибо за внимание, но месяца два или три назад в этом же треде или где то рядом я объяснял это же только без примеров.
В общем случае регекспы это все-таки регулярные грамматики. Фичи которые ты перечислил это расширения, которые есть не везде и не везде одинаково реализованы.
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Смотря что значит "для реализации в коде". Паттерн — это типовая проблема и решение для нее. Если имеется в виду решенная в соответствии с паттерном проблема — то да, конечно не требуется. То, что делает инструментарий метапрограммирования автоматически — программист сделал вручную без этого инструментария. Если имеется в виду код-решатель проблемы, который применяется к одному коду с проблемой и производит код без проблемы, с решением — то тут без метапрограммирования, как правило, не обойтись.
Речь о том, что многие паттерны можно реализовать в коде таким образом, что их можно вынести в библиотеки, подходящие для использования в произвольном случае.
K>Общим языком для ФП-программистов является (обычно, популяризированная и адаптированная) математика вообще и теория категорий в частности.
Ага, т.е. никаких инструментов помогающих в проектирования архитектуры сложных приложений не имеем... Я так и думал.
K>Смысл "навязывания использования" в том, что программист может рассчитывать, что другой программист делает то и другое, а вот это наоборот не делает. И, следовательно, делать то, чего иначе он делать не мог бы. Соответственно и компилятор может делать не консервативные оптимизации, которые только и возможны в условиях, когда никто никому ничего не навязывает, а гораздо более интересные оптимизации, которые опять таки делают практически приемлемым код, который без них только для форумных споров годится. Что тоже возможности программиста расширяет.
Так а в чём проблема, если все эти оптимизации компилятор будет делать для ЧАСТИ кода? Т.е. если половина программы (функции с модификатором pure, работающие с данными с модификатором const) будет обработана в соответствие с одними правилами, а оставшаяся с другими (отсутствием ленивости, консервативной оптимизацией и т.п.).
_>>Опять же с чего бы это? ) Тот же пример чистоты в D говорит об обратном... ) K>О чем же он говорит? Это как-то конкретизировать можно? Нормальной ленивости в D нет, это я знаю. А как там с оптимизациями или, к примеру, STM дела обстоят?
Он говорит о том, что можно вводить подобные возможности, не вводя обязательности использования. Ленивости в языке пока нет, но не вижу никаких проблем для её введения (может будет в версии 3). А вот с оптимизацией там как раз всё великолепно. Учитываются и такие вещи и ещё есть целая отдельная сложная и крайне эффективная область с вычислениями на стадии компиляции. Зародыш подобного есть в C++, но в слабой и неудобной форме.
_>>хаскель (или что-то скриптовое похожего вида, кстати а такое вообще есть?) K>Зависит от того, насколько похожее требуется и что под скриптовостью понимается.
Что-нибудь с динамической типизацией, при этом чисто функциональное и ленивое.
_>> C++/Python. Т.е. два мультипарадигменных языка! _>> в них напихано множество различных парадигм и концепций K>Где же в них мультипарадигменность? Два ООП языка. Они кроме ООП разве еще что-то поддерживают?
Ну это уже откровенный троллизм, который явно свидетельствует о том, что просто нечего сказать в ответ.
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Это просто достаточно компактный пример, демонстрирующий полиморфную рекурсию, а не какую-то бессмысленную "защиту".
Это точное решение конкретной задачки в полном соответствие с её изначальной формулировкой автором: http://www.linux.org.ru/forum/development/4300872. Причём показанное мною простейшее решение на C++ ещё и короче, эффективнее и функциональнее вариантов, предложенных на других языках.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете..
Здравствуйте, Ikemefula, Вы писали:
I>В общем случае регекспы это все-таки регулярные грамматики. Фичи которые ты перечислил это расширения, которые есть не везде и не везде одинаково реализованы.
Ну например в стандарт языка C++ регулярные выражения входят именно в таком виде.
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ну то есть библиотеки писать не надо, правильно ?
_>Мультиметодов? ) Ну можно конечно ещё один велосипед накидать... Но проще взять уже готовую)
Пока нет либ на все случаи жизни, то приходится писать их самому. Как то так.
Re[42]: Есть ли вещи, которые вы прницпиально не понимаете..
Здравствуйте, alex_public, Вы писали:
I>>В общем случае регекспы это все-таки регулярные грамматики. Фичи которые ты перечислил это расширения, которые есть не везде и не везде одинаково реализованы.
_>Ну например в стандарт языка C++ регулярные выражения входят именно в таком виде.
В твоих решениях таких фич не было, решения без регекспос у тебя сводились к регулярной грамматике, а в случае с хтмл все еще хуже — даже контекстно-свободная грамматика тебе не поможет (я уверен ты тут же накидаешь опровержение в две строчки на регэкспах).
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Это точное решение конкретной задачки в полном соответствие с её изначальной формулировкой автором: http://www.linux.org.ru/forum/development/4300872. Причём показанное мною простейшее решение на C++ ещё и короче, эффективнее и функциональнее вариантов, предложенных на других языках.
Да, забавный трюк. Жаль, что он не подходит для задач, отклоняющихся от предложенного сценария хотя бы на один шаг.
Даже вот так уже не работает:
int n;
cin >> n;
cint size1 {n};
auto cons1 = MakeCons(size1, [](int i){return i; });
cint size2 {n};
auto cons2 = MakeCons(size2, [](int i){return i; });//а такое не будет компилироватьсяreturn ScalarProduct(cons1, cons2);
Я уж не говорю о получении двух "массивов" из разных источников.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Речь о том, что многие паттерны можно реализовать в коде таким образом, что их можно вынести в библиотеки, подходящие для использования в произвольном случае.
Ну я и говорю: тут без метапрограммирования, как правило, не обойтись.
K>>Общим языком для ФП-программистов является (обычно, популяризированная и адаптированная) математика вообще и теория категорий в частности. _>Ага, т.е. никаких инструментов помогающих в проектирования архитектуры сложных приложений не имеем... Я так и думал.
Вы так усиленно это думали, что начисто проигнорировали мой ответ.
_>Так а в чём проблема, если все эти оптимизации компилятор будет делать для ЧАСТИ кода? Т.е. если половина программы (функции с модификатором pure, работающие с данными с модификатором const) будет обработана в соответствие с одними правилами, а оставшаяся с другими (отсутствием ленивости, консервативной оптимизацией и т.п.).
Ничего не понимаю. Вы же только что называли систему контроля над эффектами "ограничением возможностей". А теперь какие-то функции с идентификатором pure появились. Это же ограничение возможностей, так дело не пойдет — все функции должны быть непонятно какими.
_>Он говорит о том, что можно вводить подобные возможности, не вводя обязательности использования.
Чем в этом смысле по вашему подход D лучше подхода хаскеля?
_>Ленивости в языке пока нет
Ну, вот видите.
_>А вот с оптимизацией там как раз всё великолепно.
Т.е. в обсуждаемом по соседству случае компилятор D лишние копирования устранит, как и ghc?
_>Учитываются и такие вещи и ещё есть целая отдельная сложная и крайне эффективная область с вычислениями на стадии компиляции.
Тут речь идет именно о применении метапрограммирования для получения эффективного кода из некоего встроенного dsl, а не оптимизации общего назначения, я правильно понял?
_>Что-нибудь с динамической типизацией, при этом чисто функциональное и ленивое.
До известной статьи Дамаса и Милнера (т.е. до начала 80-х) такие языки действительно были, тот же автор протохаскеля-Миранды Тернер в свое время пару таких сделал. Но после они сошли на нет — без типов особо не развернешься, так же, как ЯП без контроля эффектов — это вечные 90-е, так и бестиповые языки — вечные 70-е.
Самый похожий на хаскель из известных мне скриптов — Pure — ни чистым, ни ленивым (по умолчанию) не является.
K>>Где же в них мультипарадигменность? Два ООП языка. Они кроме ООП разве еще что-то поддерживают? _>Ну это уже откровенный троллизм, который явно свидетельствует о том, что просто нечего сказать в ответ.
По-моему, вопрос совершенно нормальный. А вот ваш отказ от ответа на вопрос о том, что они еще, кроме обычного императивного программирования (ООП), поддерживают — как раз и означает, что вам сказать нечего.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так а в чём проблема, если все эти оптимизации компилятор будет делать для ЧАСТИ кода? Т.е. если половина программы (функции с модификатором pure, работающие с данными с модификатором const) будет обработана в соответствие с одними правилами, а оставшаяся с другими (отсутствием ленивости, консервативной оптимизацией и т.п.).
Проблема — в том, что для применения оптимизаций в одном месте, нужно соблюдать ограничения в другом.
Выбрасывать проверки выхода за границы диапазона при обращении по индексу можно только в том случае, если у нас весь код ведёт себя прилично — в частности, не порождает индексы, которые могут выйти за пределы разрешённого диапазона. Устранять лишние копирования можно только в случае ссылочной прозрачности — т.е. объект гарантированно immutable или single-owned. Код-нарушитель не просто будет "менее оптимальным", он тупо сломает "благонамеренный" код, который оптимизирован из расчёта на отсутствие нарушителей.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете..
Здравствуйте, Ikemefula, Вы писали:
I>В твоих решениях таких фич не было, решения без регекспос у тебя сводились к регулярной грамматике, а в случае с хтмл все еще хуже — даже контекстно-свободная грамматика тебе не поможет (я уверен ты тут же накидаешь опровержение в две строчки на регэкспах).
Ну так там просто примеры были такие тривиальные, что большего и не требовалось. ) А вообще я всяческими пред/пост условиями вполне пользуюсь в регулярных выражениях.
В целом же я тебе уже подробно рассказывал, какими инструментами предпочитаю пользоваться в сложных случаях, — не вижу смысла повторяться.
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Да, забавный трюк. Жаль, что он не подходит для задач, отклоняющихся от предложенного сценария хотя бы на один шаг. S>Даже вот так уже не работает:
Ну так а он и не должен компилироваться в таком случае — нам же необходимо гарантировать компилятором равенство длин векторов. А если бы такое собиралось, то добавление банального n++ в середину сразу же давало бы неправильную программу.
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну я и говорю: тут без метапрограммирования, как правило, не обойтись.
Это только в случае C++, потому как у него обобщённое программирование реализовано через метапрограммирование (что мы и обсуждали здесь). А во многих других языках достаточно именно просто обобщённое программирования (да и собственно нормальное метапрограммирование вообще мало где есть).
K>Вы так усиленно это думали, что начисто проигнорировали мой ответ.
Это про математику и теорию категорий в частности? ) Ну так можно мне увидеть какой-нибудь профессиональный инструмент для проектирования архитектуры ПО, основанный на этом? )
K>Ничего не понимаю. Вы же только что называли систему контроля над эффектами "ограничением возможностей". А теперь какие-то функции с идентификатором pure появились. Это же ограничение возможностей, так дело не пойдет — все функции должны быть непонятно какими.
Нет, это как раз добавление возможности. А ограничением будет требование иметь в коде только pure функции.
K>Чем в этом смысле по вашему подход D лучше подхода хаскеля?
Я же уже вроде несколько раз объяснял. Ну могу ещё раз, на примере той же самой чистоты:
— в C++: нет возможности, нет ограничений
— в D: есть возможность, нет ограничений
— в Haskell: есть возможность, есть ограничения (все функции должны быть такие).
K>Т.е. в обсуждаемом по соседству случае компилятор D лишние копирования устранит, как и ghc?
Насколько я помню, в том примере лишние копирования устранял не сам оптимизатор, а библиотечный код. Думаю, что на D такое тоже без проблем организуется. Но фокус в том, что оно там не нужно! Ведь о чём мы собственно говорили тогда? О типичном не чистом коде, работающем с неконстантными данными (это если мы говорим про эффективную реализацию). И именно из-за этого у нас были сложности с записью подобного на Хаскеле. Ну так а на D мы можем записать это прямо в явном виде, без всяких дополнительных ухищрений. У нас же здесь нет ограничения (!) в виде обязательной чистоты всего кода. И при этом никто нам не мешает использовать в соседнем коде чистые функции, пользуюсь всеми бонусами от них.
K>До известной статьи Дамаса и Милнера (т.е. до начала 80-х) такие языки действительно были, тот же автор протохаскеля-Миранды Тернер в свое время пару таких сделал. Но после они сошли на нет — без типов особо не развернешься, так же, как ЯП без контроля эффектов — это вечные 90-е, так и бестиповые языки — вечные 70-е.
Только что-то основной расцвет подобных языков наблюдается как раз сейчас, в 21-ом веке... ) Причём чем проще, тем популярнее. Мой любимый простенький Питончик на фоне остальных является ещё довольно серьёзным и сложным. ))) А если мы возьмём какой-нибудь JavaScript, который пролез уже и на серверы (node.js) и в десктоп (metro api win8)...
K>По-моему, вопрос совершенно нормальный. А вот ваш отказ от ответа на вопрос о том, что они еще, кроме обычного императивного программирования (ООП), поддерживают — как раз и означает, что вам сказать нечего.
На мой взгляд, задавать на подобном форуме вопросы, имеющие ответы в википедии или школьных учебниках — это как раз троллизм и есть. ))) Ну если есть желание говорить на таком уровне, то пожалуйста:
Здравствуйте, Sinclair, Вы писали:
S>Проблема — в том, что для применения оптимизаций в одном месте, нужно соблюдать ограничения в другом. S>Выбрасывать проверки выхода за границы диапазона при обращении по индексу можно только в том случае, если у нас весь код ведёт себя прилично — в частности, не порождает индексы, которые могут выйти за пределы разрешённого диапазона. Устранять лишние копирования можно только в случае ссылочной прозрачности — т.е. объект гарантированно immutable или single-owned. Код-нарушитель не просто будет "менее оптимальным", он тупо сломает "благонамеренный" код, который оптимизирован из расчёта на отсутствие нарушителей.
Непонятно в чём проблема. Вот имеем мы чистую функцию. Что это значит с точки зрения оптимизатора? Что результат её вызова с одними аргументами можно кэшировать и что можно произвольно передвигать точку её вызова (это кстати включает в себя ленивость). И чем может помешать оптимизатору нахождение рядом с вызовом чистой функции вызова ещё и не чистой? Да, со второй функции он не сможет ничего этого делать. Ну так мы и не требуем этого.
Или имеем константные объекты с одним содержимым (хотя для языков типа C++ это не так актуально, т.к. там принято явно указывать ссылки в таких случаях). Чем может помешать компилятору не размножать этот объект, нахождение рядом с ним некого неконстантного объекта?
И никто не предлагает иметь объекты, которые в одном месте константные, а в другом нет. Предлагается иметь и такие и такие по отдельности (собственно такое уже давно есть во многих языках). И аналогично с другими фичами типа чистоты и т.п. В том же D это во многом реализовано, но ещё не до конца (грубо говоря не все фичи Хаскеля перетащили, при этом сохраняя их необязательность, как в C++).
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете..
Здравствуйте, alex_public, Вы писали:
_>Ну так там просто примеры были такие тривиальные, что большего и не требовалось. ) А вообще я всяческими пред/пост условиями вполне пользуюсь в регулярных выражениях.
Нетривиальные и ты сам говорил что это экзотика.
_>В целом же я тебе уже подробно рассказывал, какими инструментами предпочитаю пользоваться в сложных случаях, — не вижу смысла повторяться.
Да ничего, см выше, ты уже отказался от своих слов. Как то так
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
S>>Проблема — в том, что для применения оптимизаций в одном месте, нужно соблюдать ограничения в другом. S>>Выбрасывать проверки выхода за границы диапазона при обращении по индексу можно только в том случае, если у нас весь код ведёт себя прилично — в частности, не порождает индексы, которые могут выйти за пределы разрешённого диапазона. Устранять лишние копирования можно только в случае ссылочной прозрачности — т.е. объект гарантированно immutable или single-owned. Код-нарушитель не просто будет "менее оптимальным", он тупо сломает "благонамеренный" код, который оптимизирован из расчёта на отсутствие нарушителей.
_>Непонятно в чём проблема. Вот имеем мы чистую функцию. Что это значит с точки зрения оптимизатора? Что результат её вызова с одними аргументами можно кэшировать и что можно произвольно передвигать точку её вызова (это кстати включает в себя ленивость). И чем может помешать оптимизатору нахождение рядом с вызовом чистой функции вызова ещё и не чистой? Да, со второй функции он не сможет ничего этого делать. Ну так мы и не требуем этого.
Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным.
_>Или имеем константные объекты с одним содержимым (хотя для языков типа C++ это не так актуально, т.к. там принято явно указывать ссылки в таких случаях). Чем может помешать компилятору не размножать этот объект, нахождение рядом с ним некого неконстантного объекта?
Если неконстантный объект имеет общие данные с константным, то результат программы может оказаться разным при копировании и передаче ссылки. Кстати константность вообще не гарантия, поэтому компилятор не производит никаких оптимизаций на основе константности.
_>И никто не предлагает иметь объекты, которые в одном месте константные, а в другом нет. Предлагается иметь и такие и такие по отдельности (собственно такое уже давно есть во многих языках). И аналогично с другими фичами типа чистоты и т.п. В том же D это во многом реализовано, но ещё не до конца (грубо говоря не все фичи Хаскеля перетащили, при этом сохраняя их необязательность, как в C++).
А как гарантировать что нечистые функции не влияют на чистые?
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
_>>Непонятно в чём проблема. Вот имеем мы чистую функцию. Что это значит с точки зрения оптимизатора? Что результат её вызова с одними аргументами можно кэшировать и что можно произвольно передвигать точку её вызова (это кстати включает в себя ленивость). И чем может помешать оптимизатору нахождение рядом с вызовом чистой функции вызова ещё и не чистой? Да, со второй функции он не сможет ничего этого делать. Ну так мы и не требуем этого.
G>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным. G>А как гарантировать что нечистые функции не влияют на чистые?
В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
_>>>Непонятно в чём проблема. Вот имеем мы чистую функцию. Что это значит с точки зрения оптимизатора? Что результат её вызова с одними аргументами можно кэшировать и что можно произвольно передвигать точку её вызова (это кстати включает в себя ленивость). И чем может помешать оптимизатору нахождение рядом с вызовом чистой функции вызова ещё и не чистой? Да, со второй функции он не сможет ничего этого делать. Ну так мы и не требуем этого.
G>>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным. G>>А как гарантировать что нечистые функции не влияют на чистые?
DM>В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
Это хорошо. А если данные не global и не static? Например есть объект у которого есть не изменяющий состояние метод и метод с сайд-эффектами, компилятор скажет что-нибудь по этому поводу?
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так а он и не должен компилироваться в таком случае — нам же необходимо гарантировать компилятором равенство длин векторов. А если бы такое собиралось, то добавление банального n++ в середину сразу же давало бы неправильную программу.
Ну я как бы не против, чтобы программа с добавлением n++ в середину ломалась. Просто здесь мы видим ограниченность компилятора: он в упор не видит того, что никакого n++ тут нету. Точнее, ограниченность решения. Ведь даже если я подставлю в обе строчки вместо n 42, компилятор по-прежнему не даст скомпилировать программу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
DM>>В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
G>Это хорошо. А если данные не global и не static?
Тут хуже. Если передается мутабельный объект, то "в одну реку нельзя войти дважды", никакого кэширования не будет. Но, как ни странно, компилятор не будет возражать называть функцию чистой.
G> Например есть объект у которого есть не изменяющий состояние метод и метод с сайд-эффектами, компилятор скажет что-нибудь по этому поводу?
Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным.
Что значит обращается? Если в смысле передачи параметра, то как бы нет никаких проблем. А если имеется в виду обращение изнутри функции к каким-то другим внешним неконстантным данным, то очевидно, что такая функция не является чистой.
G>Если неконстантный объект имеет общие данные с константным, то результат программы может оказаться разным при копировании и передаче ссылки. Кстати константность вообще не гарантия, поэтому компилятор не производит никаких оптимизаций на основе константности.
Это в каком языке интересно? )
G>А как гарантировать что нечистые функции не влияют на чистые?
Это должен делать компилятор (он просто не скомпилирует код, в котором модификатором pure помечены неправильные функции). В языке D такое есть. И в принципе возможно ввести подобное во многие языки.
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Ну я как бы не против, чтобы программа с добавлением n++ в середину ломалась. Просто здесь мы видим ограниченность компилятора: он в упор не видит того, что никакого n++ тут нету. Точнее, ограниченность решения. Ведь даже если я подставлю в обе строчки вместо n 42, компилятор по-прежнему не даст скомпилировать программу.
Так это уже просто совсем другая задача. Если мы хотим проверять равенство не по построению, а по реальному значению, то тогда всё намного проще. Если оно известно на момент компиляции (как 42 например), то решением будет уже готовый библиотечный класс std::array. А если не известно, то соответственно будет уже просто обычный if в рантайме. Изначально же мы решали задачу сравнения по построению, а не по значению и вот как раз она уже не такая стандартная...
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
S>>Ну я как бы не против, чтобы программа с добавлением n++ в середину ломалась. Просто здесь мы видим ограниченность компилятора: он в упор не видит того, что никакого n++ тут нету. Точнее, ограниченность решения. Ведь даже если я подставлю в обе строчки вместо n 42, компилятор по-прежнему не даст скомпилировать программу.
_>Так это уже просто совсем другая задача. Если мы хотим проверять равенство не по построению, а по реальному значению, то тогда всё намного проще. Если оно известно на момент компиляции (как 42 например), то решением будет уже готовый библиотечный класс std::array. А если не известно, то соответственно будет уже просто обычный if в рантайме. Изначально же мы решали задачу сравнения по построению, а не по значению и вот как раз она уже не такая стандартная...
Задача, на сколько понимаю, ставиться так: выразить с помощью типизации, что ScalarProduct принимает коллекции одинаковой длины.
Чтобы, если компилятор мог себе доказать, что оба параметра одинаковой длины (например, по построению), компиляция проходила успешно, иначе — выдавалась ошибка компиляции и нужно было, например, добавлять условие:
//Длина коллекций, конечно, не обязана быть константой времени компиляции.
cin >> n;
cin >> m;
auto v1 = make(n);
auto v2 = make(m);
if(n==m)//условие
ScalarProduct(v1, v2);
, чтобы ублажить компилятор.
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, artelk, Вы писали:
A>Задача, на сколько понимаю, ставиться так: выразить с помощью типизации, что ScalarProduct принимает коллекции одинаковой длины. A>Чтобы, если компилятор мог себе доказать, что оба параметра одинаковой длины (например, по построению), компиляция проходила успешно, иначе — выдавалась ошибка компиляции и нужно было, например, добавлять условие: A>
A>//Длина коллекций, конечно, не обязана быть константой времени компиляции.
A>cin >> n;
A>cin >> m;
A>auto v1 = make(n);
A>auto v2 = make(m);
A>if(n==m)//условие
A> ScalarProduct(v1, v2);
A>
A>, чтобы ублажить компилятор.
Задачка точно сформулирована здесь http://www.linux.org.ru/forum/development/4300872 и имеет два ключевых требования:
— проверка равенства размеров векторов на этапе компиляции
— размеры векторов не известны на момент компиляции.
Соответственно, сочетание этих требование и позволяет решать задачу исключительно методом сравнения размера по построению. Что является достаточно нестандартной задачкой. Хотя, как видно выше, на C++ она решается весьма просто. Кстати, можно было сделать и более красивое решение с помощью какого-нибудь там boost.proto, позволяющее реально произвольно задавать (и проверять) вектора, но это уже лень.
Ну а если убирать одно из этих требований, то просто получаем две тривиальнейших задачки с общеизвестными решениями через сравнение реальных размеров.
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Задачка точно сформулирована здесь http://www.linux.org.ru/forum/development/4300872 и имеет два ключевых требования: _> — проверка равенства размеров векторов на этапе компиляции _> — размеры векторов не известны на момент компиляции.
Там написано "Нам хочется, чтобы компилятор гарантировал нам, что длины этих векторов одинаковы". Это не эквивалентно "проверке равенства размеров векторов на этапе компиляции".
Предложенный вариант с if вполне корректен (при условии, что компилятор будет требовать его наличие).
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Там написано "Нам хочется, чтобы компилятор гарантировал нам, что длины этих векторов одинаковы". Это не эквивалентно "проверке равенства размеров векторов на этапе компиляции". ARK>Предложенный вариант с if вполне корректен (при условии, что компилятор будет требовать его наличие).
Ну там же есть примеры решения на Java/C# (заметно менее удобные, чем на C++), которые однозначно демонстрируют, что конкретно подразумевал автор задачки. Вот http://www.linux.org.ru/forum/development/4300872/page3#comment-4305706 например. И там в каждом варианте есть закомментированная строка, наличие которой блокирует компиляцию.
Re[82]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну там же есть примеры решения на Java/C# (заметно менее удобные, чем на C++), которые однозначно демонстрируют, что конкретно подразумевал автор задачки. Вот http://www.linux.org.ru/forum/development/4300872/page3#comment-4305706 например. И там в каждом варианте есть закомментированная строка, наличие которой блокирует компиляцию.
Да, верно. Не обратил внимания.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
DM>>>В D чистая функция "does not read or write any global or static mutable state" помимо прочего. Так что помешать ей не получится, если конечно не идти намеренно против системы типов, но тогда уже вся ответственность на нарушителе.
G>>Это хорошо. А если данные не global и не static?
DM>Тут хуже. Если передается мутабельный объект, то "в одну реку нельзя войти дважды", никакого кэширования не будет. Но, как ни странно, компилятор не будет возражать называть функцию чистой.
G>> Например есть объект у которого есть не изменяющий состояние метод и метод с сайд-эффектами, компилятор скажет что-нибудь по этому поводу?
DM>Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так? Ведь никак не проверяется что объект single-owned?
Кстати чем immutable отличается от const?
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Так и с первой не может ничего делать, если обе функции обращаются к одним и тем же данным.
_>Что значит обращается? Если в смысле передачи параметра, то как бы нет никаких проблем. А если имеется в виду обращение изнутри функции к каким-то другим внешним неконстантным данным, то очевидно, что такая функция не является чистой.
Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.
G>>Если неконстантный объект имеет общие данные с константным, то результат программы может оказаться разным при копировании и передаче ссылки. Кстати константность вообще не гарантия, поэтому компилятор не производит никаких оптимизаций на основе константности.
_>Это в каком языке интересно? )
Это в принципе в любом языке.
G>>А как гарантировать что нечистые функции не влияют на чистые?
_>Это должен делать компилятор (он просто не скомпилирует код, в котором модификатором pure помечены неправильные функции). В языке D такое есть.
Не силен в D, покажи пример.
_>И в принципе возможно ввести подобное во многие языки.
В общем случае получение такой гарантии приводит к решению проблемы останова. Так что в принципе ввести подобное в языки нельзя.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так? Ведь никак не проверяется что объект single-owned?
http://nwcpp.org/talks/2009/accu.pdf
Насколько я помню, в D нет single-owned объектов (то бишь уникальных ссылок).
G>Кстати чем immutable отличается от const?
Immutable не меняется никем и никогда, const не меняется только текущим клиентом.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой?
Не будет. Чистые функции в D не могут никак взаимодействовать с изменяемым состоянием (даже читать его): http://dlang.org/function.html
a pure function:
•does not read or write any global or static mutable state
•cannot call functions that are not pure
•can override an impure function, but an impure function cannot override a pure one
•is covariant with an impure function
•cannot perform I/O
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? ARK>Не будет. Чистые функции в D не могут никак взаимодействовать с изменяемым состоянием
К сожалению, еще как могут:
int gx = 5;
class A { int x, y; }
auto f(A a) pure
{
a.x = 1; // попытка обратиться к gx тут вызовет ожидаемую ошибку, а так все работаетreturn a.y + 2;
}
Ограничение лишь на глобальное состояние.
Правда, в доке упоминается еще "full, functional purity", когда она ничего не меняет, и тогда оптимизации сильнее, но на уровне языка это никак не отражено.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
DM>>Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
G>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так?
Система типов мешает. Если он в одном потоке immutable, он и в любом другом будет immutable, если не идти на сознательное нарушение и использовать касты.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>К сожалению, еще как могут: DM>Ограничение лишь на глобальное состояние.
Хм, если так, то это очень плохо.
По-хорошему, для таких фокусов параметры должны передаваться по значению или быть иммутабельными. Тут у Брайта какой-то адский косяк.
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
DM>>>Да, много всякого может сказать. Там есть три варианта: мутабельный, const и immutable. Когда метод помечен одним из способов, это воспринимается как если бы весь объект при вызове данного метода был такой, а потому мешать их сложно. Если создать объект как иммутабельный, там меняющие состояния методы не будут доступны, например. И наоборот, если не путаю.
G>>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так?
DM>Система типов мешает. Если он в одном потоке immutable, он и в любом другом будет immutable, если не идти на сознательное нарушение и использовать касты.
А в какой момент объект становится immutable? Как const в C++? Или на уровне типа задается? Или есть что-то типа механизма "заморозки" ?
Если ссылку на объект можно скопировать до того как он стал immutable, то гарантий по сути никаких нет.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, gandjustas, Вы писали:
G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой?
ARK>Не будет. Чистые функции в D не могут никак взаимодействовать с изменяемым состоянием (даже читать его): http://dlang.org/function.html ARK>
ARK>a pure function:
ARK>•does not read or write any global or static mutable state
ARK>•cannot call functions that are not pure
ARK>•can override an impure function, but an impure function cannot override a pure one
ARK>•is covariant with an impure function
ARK>•cannot perform I/O
А где здесь про состояние объекта? Оно не является global or static mutable state.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.
Что значит будет чистой или нет? ) Это решает программист, с помощью модификатора pure. А компилятор соответственно или позволяет собрать такой код или нет.
Далее, если мы говорим про такой объект, то это собственно по сути ничем не отличается от двух глобальных функций, которым передают в качестве параметра одну и ту же структуру. Ключевое тут "в качестве параметра", так что без проблем можно считать такую функцию чистой.
Только вот если передавать этой нашей чистой функции неконстантную функцию (или в случае ООП, вызывая метод неконстантного объекта), то очевидно, что никакие оптимизации типа кэширования или перемещения точки вызова невозможны, т.к. это будут вызовы с потенциально разными аргументами.
G>Это в принципе в любом языке.
Ну ну) А ничего что например в C++ константные данные располагаются вообще в другой памяти? ) Это конечно же если компилятор вообще будет выделять память под них — в большинстве случаев оно может просто в ассемблерном коде оказаться зашиты. )))
G>Не силен в D, покажи пример.
В ответ на такой код
int data;
pure int f(){return data;}
компилятор скажет: "Error: pure nested function 'f' cannot access mutable data 'data'".
G>В общем случае получение такой гарантии приводит к решению проблемы останова. Так что в принципе ввести подобное в языки нельзя.
И откуда тут взялась проблема остановки? )
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Хм, если так, то это очень плохо. ARK>По-хорошему, для таких фокусов параметры должны передаваться по значению или быть иммутабельными. Тут у Брайта какой-то адский косяк.
Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции). Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.
_>Что значит будет чистой или нет? ) Это решает программист, с помощью модификатора pure. А компилятор соответственно или позволяет собрать такой код или нет.
_>Далее, если мы говорим про такой объект, то это собственно по сути ничем не отличается от двух глобальных функций, которым передают в качестве параметра одну и ту же структуру. Ключевое тут "в качестве параметра", так что без проблем можно считать такую функцию чистой.
Это как? Даже если одна из функций потенциально меняет эту структуру? Тогда на какие оптимизации можно рассчитывать?
_>Только вот если передавать этой нашей чистой функции неконстантную функцию (или в случае ООП, вызывая метод неконстантного объекта), то очевидно, что никакие оптимизации типа кэширования или перемещения точки вызова невозможны, т.к. это будут вызовы с потенциально разными аргументами.
G>>Это в принципе в любом языке.
_>Ну ну) А ничего что например в C++ константные данные располагаются вообще в другой памяти? ) Это конечно же если компилятор вообще будет выделять память под них — в большинстве случаев оно может просто в ассемблерном коде оказаться зашиты. )))
Речь идет о константных параметрах и константных функциях.
G>>Не силен в D, покажи пример.
_>В ответ на такой код _>
_>int data;
_>pure int f(){return data;}
_>
компилятор скажет: "Error: pure nested function 'f' cannot access mutable data 'data'".
А если это написано внутри класса? data является полем (потенциально изменяемым), а f — функцией-членом.
G>>В общем случае получение такой гарантии приводит к решению проблемы останова. Так что в принципе ввести подобное в языки нельзя. _>И откуда тут взялась проблема остановки? )
См вопрос выше.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, AlexRK, Вы писали:
ARK>>Хм, если так, то это очень плохо. ARK>>По-хорошему, для таких фокусов параметры должны передаваться по значению или быть иммутабельными. Тут у Брайта какой-то адский косяк.
_>Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции). Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )
Константность — слабо формализованный термин. Неизменяемость (immutability) — более, стоит употреблять него.
Чистая функция, это функция которая:
1) Детерминирована — то есть при одинаковых входных значениях всегда дает одинаковые входные значения.
2) Не имеет наблюдаемых сайд-эффектов.
Если функция при вычислениях использует изменяемые данные, то она не может быть чистой (даже несмотря на модификаторы типа pure).
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Это как? Даже если одна из функций потенциально меняет эту структуру? Тогда на какие оптимизации можно рассчитывать?
Если мы передаём в чистую функцию неконстантную структуру, то ни на какие. Но от этого функция не перестаёт быть чистой. )
G>А если это написано внутри класса? data является полем (потенциально изменяемым), а f — функцией-членом.
Тогда без проблем, т.к. это аналогично чему-то типа "int f(const ref S s){return s.data;}", что очевидно является чистой функцией.
_>>И откуда тут взялась проблема остановки? ) G>См вопрос выше.
И?
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Это как? Даже если одна из функций потенциально меняет эту структуру? Тогда на какие оптимизации можно рассчитывать?
_>Если мы передаём в чистую функцию неконстантную структуру, то ни на какие. Но от этого функция не перестаёт быть чистой. )
По факту перестает. Теряется свойство детерминированности.
G>>А если это написано внутри класса? data является полем (потенциально изменяемым), а f — функцией-членом. _>Тогда без проблем, т.к. это аналогично чему-то типа "int f(const ref S s){return s.data;}", что очевидно является чистой функцией.
Не является, ибо нет гарантии то s никто не поменяет вне функции. Это значит что все оптимизации для чистых фукнций нельзя выполнить. Даже переупорядочить вычисления нельзя.
_>>>И откуда тут взялась проблема остановки? ) G>>См вопрос выше. _>И?
См ответ выше. Если бы компилятор мог проанализировать что делается в коде вокруг "чистых" функций, то мог бы выполнить оптимизации, а это сводится к проблеме останова.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Константность — слабо формализованный термин. Неизменяемость (immutability) — более, стоит употреблять него.
Это привычка из плюсов, где только const) А в D действительно есть отдельно const и immutable.
G>Чистая функция, это функция которая: G>1) Детерминирована — то есть при одинаковых входных значениях всегда дает одинаковые входные значения. G>2) Не имеет наблюдаемых сайд-эффектов.
Ну да.
G>Если функция при вычислениях использует изменяемые данные, то она не может быть чистой (даже несмотря на модификаторы типа pure).
Это если ссылка на эти данные откуда-то изнутри функции. А если речь идёт о передаваемых в качестве параметров, то никаких проблем.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>По факту перестает. Теряется свойство детерминированности.
Ничего подобного. Вызов нашей чистой функции, потом модифицирующей и потом снова чистой по смыслу является просто двумя вызовами чистой функции с двумя разными аргументами.
G>Не является, ибо нет гарантии то s никто не поменяет вне функции. Это значит что все оптимизации для чистых фукнций нельзя выполнить. Даже переупорядочить вычисления нельзя.
Оптимизации можно проводить только в пределах неизменности сущностей, передаваемых в качестве параметров в нашу функцию. И кстати для компилятора не проблема отслеживать эти вещи. Но это всё происходит вне нашей функции и никак не влияет на факт её чистоты. Чистая же она потому, что её результат зависит исключительно от параметров функции.
G>См ответ выше. Если бы компилятор мог проанализировать что делается в коде вокруг "чистых" функций, то мог бы выполнить оптимизации, а это сводится к проблеме останова.
Ничего подобного. Достаточно чтобы в языке можно было задать иммутабельные данные — тогда никаких анализов исполнения алгоритма не требуется и при этом всё получается точно. Хотя теоретически в неком минимальном виде (например для локальных переменных, на которые никто не ссылается) можно пробовать применять подобную оптимизацию и для не иммутабельных данных. Не знаю реализовано ли где-то подобное...
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Если мы передаём в чистую функцию неконстантную структуру, то ни на какие. Но от этого функция не перестаёт быть чистой. )
Напомню: задача была как раз в оптимизациях, а не в том, чтобы сделать функцию чистой.
Если у меня чистая функция вызывается дважды на мутабельных данных, я обязан выполнить оба вызова — а ну как состояние поменялось? Причём это не зависит от того, является ли функция чистой.
А вот если мне (компилятору) удастся доказать, что данные между вызовами не изменились, то я могу выполнять агрессивные оптимизации.
Начиная с выноса вызова за цикл.
Компиляторы С++ решают эту проблему при помощи агрессивного инлайнинга — там уже неважно, кто помечен const, а кто нет. После SSA — анализа станет понятно, кто и когда меняется, и каким минимальным кодом можно реализовать заданное наблюдаемое поведение.
К сожалению, этот подход не работает в глобальном масштабе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Напомню: задача была как раз в оптимизациях, а не в том, чтобы сделать функцию чистой.
Ну так а нам никто и не запрещает использование иммутабельных данных для наших чистых функций... Все мои комментарии выше являлись лишь пояснением того, что критерии чистой функции в D являются вполне логичными. Даже если они при этом и не всегда гарантируют максимальную оптимизацию.
S>Если у меня чистая функция вызывается дважды на мутабельных данных, я обязан выполнить оба вызова — а ну как состояние поменялось? Причём это не зависит от того, является ли функция чистой.
Конечно. Хотя в определённых простых случая (типа локальных переменных без ссылок) компилятор теоретически без проблем способен отслеживать изменения мутабельных данных. Но я не в курсе реализовано ли что-то подобное в D.
S>А вот если мне (компилятору) удастся доказать, что данные между вызовами не изменились, то я могу выполнять агрессивные оптимизации. S>Начиная с выноса вызова за цикл.
Ага. И как раз чистые функции вызванные на иммутабельных данных и дают такие гарантии. Причём для этого совсем не требуется вводить обязательную чистоту на весь язык (как в Haskell) — достаточно всего лишь пары модификаторов, как в D.
S>Компиляторы С++ решают эту проблему при помощи агрессивного инлайнинга — там уже неважно, кто помечен const, а кто нет. После SSA — анализа станет понятно, кто и когда меняется, и каким минимальным кодом можно реализовать заданное наблюдаемое поведение. S>К сожалению, этот подход не работает в глобальном масштабе.
Ну это вообще другая тема, которая в любом случае полезна.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>По факту перестает. Теряется свойство детерминированности.
_>Ничего подобного. Вызов нашей чистой функции, потом модифицирующей и потом снова чистой по смыслу является просто двумя вызовами чистой функции с двумя разными аргументами.
И че? Компилятор то все равно ничего оптимизировать не может. Ленивость тоже ввести не получится.
Напомню разговор начался с того, что умеет Хаскель.
G>>См ответ выше. Если бы компилятор мог проанализировать что делается в коде вокруг "чистых" функций, то мог бы выполнить оптимизации, а это сводится к проблеме останова.
_>Ничего подобного. Достаточно чтобы в языке можно было задать иммутабельные данные — тогда никаких анализов исполнения алгоритма не требуется и при этом всё получается точно. Хотя теоретически в неком минимальном виде (например для локальных переменных, на которые никто не ссылается) можно пробовать применять подобную оптимизацию и для не иммутабельных данных. Не знаю реализовано ли где-то подобное...
Имеено об этом я и говорю. На самом деле для оптимизаций достаточно single-owned объектов. То есть внтури функции точно известно что никто другой не поменяет объект (на него ссылки больше нигде нет), в вызывающей функции такая же картина. Это дает широкий простор компилятору.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>>>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так? DM>>Система типов мешает. Если он в одном потоке immutable, он и в любом другом будет immutable, если не идти на сознательное нарушение и использовать касты.
G>А в какой момент объект становится immutable? Как const в C++? Или на уровне типа задается? Или есть что-то типа механизма "заморозки" ?
При рождении. Фактически, если у нас есть класс А, то А и immutable A — это два разных типа. Создав объект как просто А, его нельзя передать туда, где ждут immutable, и наоборот: можно создать immutable A, он для всех будет immutable, меняющей функции его не передать, мутабельный метод не вызвать.
G>Если ссылку на объект можно скопировать до того как он стал immutable, то гарантий по сути никаких нет.
Нельзя, как следует из вышесказанного.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции). Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )
Не могу согласиться. Такие псевдо-чистые функции не являются прозрачными по ссылкам — заменить их значениями от своих аргументов нельзя.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции).
Классические чистые функции это вобщем не про данные в виде параметров
Классические чистые функции это
1. детерминизм
2. отсутствие побочных эффектов
При чем оба признака обязательны для чистоты.
(A a) => return a.y;
Отсутствие сторонних эффектов есть, а если А это изменяемое состояние, то детерминизма нет. Следовательно, функция не является чистой.
>Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )
Итого — у тебя снова своя собственная теория.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.
_>Что значит будет чистой или нет? ) Это решает программист, с помощью модификатора pure. А компилятор соответственно или позволяет собрать такой код или нет.
Похоже, понятно, почему топик тянется так долго
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>И че? Компилятор то все равно ничего оптимизировать не может. Ленивость тоже ввести не получится.
G>Напомню разговор начался с того, что умеет Хаскель.
Ну так это всё было пояснением к критериям (с которыми я согласен), выбранным в D для чистых функций. Никто же не говорит, что надо именно так (чистые функции с мутабельными параметрами) их использовать.
Хотя даже и так тоже не плохо, потому как даже если судить по данной темке (где-то очень далеко в начале), то главной фишкой автоматического контроля за чистотой в Хаскеле называли вовсе не оптимизацию, а именно гарантию компилятором отсутствия определённого класса ошибок (типа нечаянного изменения состояния функциями, которые по смыслу не должны этого делать).
Но и полноценная оптимизация опять же может работает без проблем — для этого достаточно просто использоваться иммутабельные параметры для чистой функций.
Т.е. мы получаем все преимущества этой фичи в Хаскеле, но локально, в нужном нам месте. При этом ничем не насилуя соседний код, который может абсолютно не укладываться в функциональную парадигму.
G>Имеено об этом я и говорю. На самом деле для оптимизаций достаточно single-owned объектов. То есть внтури функции точно известно что никто другой не поменяет объект (на него ссылки больше нигде нет), в вызывающей функции такая же картина. Это дает широкий простор компилятору.
Только тогда всё равно необходим некий флажок чистоты (пусть и невидимый программисту) для функций, т.к. они же могут быть в разных единицах трансляции...
Хотя в тех же плюсах с их агрессивным инлайном, шаблонами и фишками типа lto подобная оптимизация действительно может творить чудеса и без всяких спец. флагов. )))
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Не могу согласиться. Такие псевдо-чистые функции не являются прозрачными по ссылкам — заменить их значениями от своих аргументов нельзя.
А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Классические чистые функции это вобщем не про данные в виде параметров I>Классические чистые функции это
I>1. детерминизм I>2. отсутствие побочных эффектов
I>При чем оба признака обязательны для чистоты. I>
I>(A a) => return a.y;
I>
I>Отсутствие сторонних эффектов есть, а если А это изменяемое состояние, то детерминизма нет. Следовательно, функция не является чистой.
Я правильно понимаю, что с твоей точки зрения такая int f(int x) {return x;} функция тоже не является чистой?
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Отсутствие сторонних эффектов есть, а если А это изменяемое состояние, то детерминизма нет. Следовательно, функция не является чистой.
_>Я правильно понимаю, что с твоей точки зрения такая int f(int x) {return x;} функция тоже не является чистой?
Я выделил, что бы понятнее было. С моей точки зрения int не может быть изменяемым состоянием. А вот int* может
Вобщем кривляйся дальше.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.
Ну и чудеса. Мулька чистых функций в том, оптимизации можно делать не только руками, но и перекладывать на компилятор.
Иммутабельность позволяет реализовать детерминизм. Без иммутабельности его нет и быть не может.
Вот есть у нас обычная функция memoize, возвращает кеширующую функцию для своего параметра.
Теперь фокус
var f = (A a) => return a.x; // по твоей логике это чистая функцияvar f1 = memoize(f);
var a = new A();
f1(a); //вычисляем
f1(a); //возвращаем кешированое значение
a.mutate(); // модифицируем
f1(a); // ОПАНЬКИ ! получаем отстой в силу отсутствия детерминизма
Парадокс — чистая функция не может быть мемоизирована.
Отсюда ясно, почему нужен детерминизм.
Как вариант, можешь внести в свою теорию новый термин — абсолютно чистые функции
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.
Такие функции чистыми называть нельзя, ИМХО. Вопрос терминологии — что понимать под "чистыми функциями". Я всегда считал это эквивалентностью ссылочной прозрачности и для меня стало большой неожиданностью, что Брайт сделал такую кривизну в весьма грамотно спроектированном языке.
Что касается оптимизаций, то это отдельный вопрос. Оптимизируются ведь не только чистые функции. Ну да, модификатор "pure" плюс иммутабельные параметры — и прозрачность по ссылкам гарантирована. Но я просто не понимаю, НАФИГА вообще надо было давать возможность изменять в чистой функции мутабельные параметры?
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Иммутабельность позволяет реализовать детерминизм. Без иммутабельности его нет и быть не может. I>Вот есть у нас обычная функция memoize, возвращает кеширующую функцию для своего параметра. I>Теперь фокус
Фокус на один шаг хитрее должен быть, см. ниже.
I>f1(a); //вычисляем I>f1(a); //возвращаем кешированое значение I>a.mutate(); // модифицируем I>f1(a); // ОПАНЬКИ ! получаем отстой в силу отсутствия детерминизма
Не, если содержимое а изменилось, то новое значение не будет равно старому (хоть адрес и тот же), f1 пересчитает заново, все ок.
Но вот если меняется не содержимое а, а один из объектов, на которые а ссылается, тогда оппа.
Вот с иммутабельным а было бы все ок.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
_>>А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.
ARK>Такие функции чистыми называть нельзя, ИМХО. Вопрос терминологии — что понимать под "чистыми функциями".
Этот вопрос уже давно решен — детерминизм + отсутствие побочных эффектов.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Этот вопрос уже давно решен — детерминизм + отсутствие побочных эффектов.
Хм. Кем решен?
Термин "побочный эффект" — неформальный. Нагрев процессора или своп на диск — это побочный эффект?
Вот referential transparency — другое дело, тут все однозначно.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Иммутабельность позволяет реализовать детерминизм. Без иммутабельности его нет и быть не может.
Что за бред? ) Уже несколько раз тут говорилось, что если мы модицифицируем объект, передаваемый в качестве параметра в функцию, между двумя вызовами этой функции, то это просто равносильно вызовам этой нашей функции с РАЗНЫМИ параметрами. И соответственно будут возвращаться разные результаты, как и положено. И это совершенно детерминировано.
I>Вот есть у нас обычная функция memoize, возвращает кеширующую функцию для своего параметра. I>Теперь фокус I>
I>var f = (A a) => return a.x; // по твоей логике это чистая функция
I>var f1 = memoize(f);
I>var a = new A();
I>f1(a); //вычисляем
I>f1(a); //возвращаем кешированое значение
I>a.mutate(); // модифицируем
I>f1(a); // ОПАНЬКИ ! получаем отстой в силу отсутствия детерминизма
I>
I>Парадокс — чистая функция не может быть мемоизирована. I>Отсюда ясно, почему нужен детерминизм.
D. Mon уже подробно ответил на это выше. Детерминизм есть, это очевидно.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Такие функции чистыми называть нельзя, ИМХО. Вопрос терминологии — что понимать под "чистыми функциями". Я всегда считал это эквивалентностью ссылочной прозрачности и для меня стало большой неожиданностью, что Брайт сделал такую кривизну в весьма грамотно спроектированном языке.
Я думаю это сделано для того, чтобы использовать pure не столько для оптимизации, сколько для уменьшения ошибок в кодирование. По типу того же const, только более сильного.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Не, если содержимое а изменилось, то новое значение не будет равно старому (хоть адрес и тот же), f1 пересчитает заново, все ок. DM>Но вот если меняется не содержимое а, а один из объектов, на которые а ссылается, тогда оппа. DM>Вот с иммутабельным а было бы все ок.
Не, если у A определён правильный оператор сравнения, то должно корректно работать в любом случае.
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Термин "побочный эффект" — неформальный. Нагрев процессора или своп на диск — это побочный эффект? ARK>Вот referential transparency — другое дело, тут все однозначно.
Побочный эффект это изменение наблюдаемого глобального состояния виртуальной машины, сиречь процесса. Ссылочная прозрачность это просто один из вариантов реализации, то есть таким способом гарантируется, что глобальное состояние не изменяется.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Иммутабельность позволяет реализовать детерминизм. Без иммутабельности его нет и быть не может.
_>Что за бред? ) Уже несколько раз тут говорилось, что если мы модицифицируем объект, передаваемый в качестве параметра в функцию, между двумя вызовами этой функции, то это просто равносильно вызовам этой нашей функции с РАЗНЫМИ параметрами.
Это равносильно исключительно для объектов-значений. А как быть со ссылочными структурами ?
I>>Вот есть у нас обычная функция memoize, возвращает кеширующую функцию для своего параметра. I>>Теперь фокус I>>
I>>f1(a); // ОПАНЬКИ ! получаем отстой в силу отсутствия детерминизма
I>>
I>>Парадокс — чистая функция не может быть мемоизирована. I>>Отсюда ясно, почему нужен детерминизм.
_>D. Mon уже подробно ответил на это выше. Детерминизм есть, это очевидно.
Нет в примере никакого детерминизма. Вот простой пример — A состоит исключительно из ссылок на другие объекты, то, вообще говоря, не ясно, где границы этого того объекта что в параметре пришел. Более того, не ясно, как именно делать кеширование.
Теперь обратный фокус- делаем структуру значением или просто иммутабельной. Внезапно оказывается так, что не надо думать, что же считать тем самым объектом и совершенно не важно, из чего он состоит. А для кеширования, внезапно, достаточно всего лишь Identity.
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
DM>>Но вот если меняется не содержимое а, а один из объектов, на которые а ссылается, тогда оппа. DM>>Вот с иммутабельным а было бы все ок.
_>Не, если у A определён правильный оператор сравнения, то должно корректно работать в любом случае.
Перевожу — ты стесняешься, но хочешь сказать, что А должен вести себя как значение. Для развесистых структур, навроде деревьев, это утопия — придется сранивать практически все внутренние и внешние свойства на всю глубину вложенности.
Теперь осталось совсем немного. Представь себе, А кладется в кеш не только при мемоизации, а везде где это надо. Поскольку экземпляр А ведет себя как значение, то его не получится достать из кеша. Опаньки ! То есть, после модифицирования А кеш смысла не имеет. Более того — удалить из кеша по ключу так же не выйдет. Опаньки !
Подозреваю, проблему выше ты захочешь решить с помощью уникального идентификатора специально для таких кешей. То есть, объект-значение должен обладать еще и Identity. В общем случае это не решает проблему(оппа!), но в частных — поможет.
И вот у тебя для одного и того же класса понадобилось целых два оператора сравнения. Это, в кратце, означает, что вызывающий код должен быть в курсе того, как устроен объект А.
А теперь, на секундочку, предположим, что детерминизм у нас самый что ни есть православный — а именно на иммутабельных структурах.
Внезапно оказывается, что нужен всего один оператор сравнения и нет никаких проблем с кешем, вообще, и нет нужды сравнивать все свойства на всю глубину.
Re[52]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Ну я и говорю: тут без метапрограммирования, как правило, не обойтись. _>Это только в случае C++, потому как у него обобщённое программирование реализовано через метапрограммирование (что мы и обсуждали здесь). А во многих других языках достаточно именно просто обобщённое программирования
Сильно сомневаюсь. Точнее, какие-то вырожденные случаи ООП-паттернов проектирования может на одном параметрическом полиморфизме и можно реализовать, но вряд ли что-то нетривиальное. В вашем примере метапрограммирование присутствует. Если будете искать другие примеры на C#, имейте в виду, что констрейнт new тоже не "просто обобщённое программирование", а сахар для Activator.CreateInstance со всеми вытекающими.
_>Это про математику и теорию категорий в частности? ) Ну так можно мне увидеть какой-нибудь профессиональный инструмент для проектирования архитектуры ПО, основанный на этом? )
А, вы имеете в виду софт для архитекторов вроде IBM-овского? Нет, такого, конечно, нет.
_>Нет, это как раз добавление возможности. А ограничением будет требование иметь в коде только pure функции.
С какой стати это ограничение, если все, что можно сделать в императивном языке можно делать и одними только чистыми (причем по построению) функциями? Ограниченным будет как раз язык, в котором полноценными функциями, о которых можно рассуждать и которые можно оптимизировать являются не все.
_>Я же уже вроде несколько раз объяснял. Ну могу ещё раз, на примере той же самой чистоты: _>- в C++: нет возможности, нет ограничений _>- в D: есть возможность, нет ограничений
А возможность точно есть? А то вы их пока не продемонстрировали. Да и судя по тому, что здесь
написано, никакой системы контроля за эффектами в D и нет.
_>- в Haskell: есть возможность, есть ограничения (все функции должны быть такие).
Под ограничениями, я так понял, все еще имеется в виду небольшой синтаксический шум, компенсируемый отсутствием шума в других местах?
_>Насколько я помню, в том примере лишние копирования устранял не сам оптимизатор, а библиотечный код.
Что значит не сам оптимизатор, а код? Ну да, для того, чтоб что-то оптимизировалось нужен оптимизатор и код, который этот оптимизатор может оптимизировать.
_>Думаю, что на D такое тоже без проблем организуется.
Реализуется или реализовано?
_>Но фокус в том, что оно там не нужно!
А, понятно. Т.е. поддержкой чего-то в языке опять называется отсутствие потребности в такой колбасе. Чего-то такого я и ожидал.
_>Ведь о чём мы собственно говорили тогда? О типичном не чистом коде, работающем с неконстантными данными (это если мы говорим про эффективную реализацию). И именно из-за этого у нас были сложности с записью подобного на Хаскеле.
Какие еще сложности?
_>Ну так а на D мы можем записать это прямо в явном виде, без всяких дополнительных ухищрений. У нас же здесь нет ограничения (!) в виде обязательной чистоты всего кода. И при этом никто нам не мешает использовать в соседнем коде чистые функции, пользуюсь всеми бонусами от них.
Ничего не понимаю. А в хаскеле кто мешал использовать изменение по месту? Ведь код и в этом случае все равно получался лучше, чем на плюсах, хотя и хуже, чем в случае с работой с неизменяемыми данными, который благодаря "ненужным" оптимизациями еще и приближался по эффективности к тому, который работал с изменяемыми массивами.
_>Только что-то основной расцвет подобных языков наблюдается как раз сейчас, в 21-ом веке... )
Что же в этом хорошего?
_>Причём чем проще, тем популярнее. Мой любимый простенький Питончик на фоне остальных является ещё довольно серьёзным и сложным. ))) А если мы возьмём какой-нибудь JavaScript, который пролез уже и на серверы (node.js) и в десктоп (metro api win8)...
Это питон-то с яваскриптом со всеми их фокусами — простые языки? Не смешите.
_>На мой взгляд, задавать на подобном форуме вопросы, имеющие ответы в википедии или школьных учебниках — это как раз троллизм и есть. ))) Ну если есть желание говорить на таком уровне, то пожалуйста:
_>http://en.wikipedia.org/wiki/C%2B%2B хотя тут забыли метапрограммирование, _>http://en.wikipedia.org/wiki/Python_%28programming_language%29 а здесь забыли АОП.
Смотрим С++:
procedural, functional, object-oriented, generic
"процедурная" парадигма вообще никакого инструментария для написания хоть сколько-нибудь нетривиальных программ не дает и является красивым названием для "ничего нет". Функциональная парадигма, как мы выяснили в соседних ветках, в C++ не поддерживается. Обобщенное программирование парадигмой не является — это просто базворд для обозначаения средств для нормального типизирования ФП и ООП кода в языках, где таких средств изначально не было. Метапрограммирование также парадигмой не является. Таким образом, имеем поддержку ООП и необоснованные заявления о поддержке ФП — вот и вся мультипарадигменность.
Смотрим питон: object-oriented, imperative, functional, procedural, reflective
Про процедурное уже сказано, object-oriented и imperative — это, фактически, одно и то же, ФП в питоне поддерживается на игрушечном уровне, хоть и не так плохо как в C++, reflective — очередное выдавание фичи за парадигму.
Вообще, выдаванием фичь за парадигмы, либо просто высасыванием парадигм из пальца как здесь, можно обосновать мультипарадигменность любого языка программирования.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Это просто достаточно компактный пример, демонстрирующий полиморфную рекурсию, а не какую-то бессмысленную "защиту".
_>Это точное решение конкретной задачки в полном соответствие с её изначальной формулировкой автором: http://www.linux.org.ru/forum/development/4300872. Причём показанное мною простейшее решение на C++ ещё и короче, эффективнее и функциональнее вариантов, предложенных на других языках.
Что там изначально формулировал какой-то там автор, в данном случае значения не имеет. Я сослался на пример, как демонстрацию конкретной фичи, которая в хаскеле, яве, сишарпе (и, скорее всего, хотя проверять мне лень, окамле) есть, и которой в С++ (и, насколько я знаю, хотя проверять опять таки лень — в Аде и SML без расширений) наоборот нет. Исключительно как пример того, что полиморфизм в C#/Java хотя и убогий — по возможностям подмножеством плюсового не является.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Причём чем проще, тем популярнее. Мой любимый простенький Питончик на фоне остальных является ещё довольно серьёзным и сложным. ))) А если мы возьмём какой-нибудь JavaScript, который пролез уже и на серверы (node.js) и в десктоп (metro api win8)...
K>Это питон-то с яваскриптом со всеми их фокусами — простые языки? Не смешите.
Они на самом деле простые. Хаскель и С++ на порядок-другой сложнее. Скажем Питон я изучил даже не отвлекаясь на чтение мануалов. Увидел код, полез править и как то все само пошло. По моим наблюдением Питон большей частью так и изучают.
А вот Хаскель очень непростой язык. Большинство тех, кто пишут на питоне и джаваскрипте даже генераторы из хаскеля воспринимают с большим скрипом.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Перевожу — ты стесняешься, но хочешь сказать, что А должен вести себя как значение. Для развесистых структур, навроде деревьев, это утопия — придется сранивать практически все внутренние и внешние свойства на всю глубину вложенности.
I>Теперь осталось совсем немного. Представь себе, А кладется в кеш не только при мемоизации, а везде где это надо. Поскольку экземпляр А ведет себя как значение, то его не получится достать из кеша. Опаньки ! То есть, после модифицирования А кеш смысла не имеет. Более того — удалить из кеша по ключу так же не выйдет. Опаньки !
I>Подозреваю, проблему выше ты захочешь решить с помощью уникального идентификатора специально для таких кешей. То есть, объект-значение должен обладать еще и Identity. В общем случае это не решает проблему(оппа!), но в частных — поможет. I>И вот у тебя для одного и того же класса понадобилось целых два оператора сравнения. Это, в кратце, означает, что вызывающий код должен быть в курсе того, как устроен объект А.
Что за ерунда? ) Как ты вообще собираешься производить кэширование объектов не имеющих корректных операторов сравнения? Посмотри хотя бы тривиальные требования в том же std::map. А если такой оператор есть, то в чём тогда проблема? И никаких двух версий естественно не требуется.
I>А теперь, на секундочку, предположим, что детерминизм у нас самый что ни есть православный — а именно на иммутабельных структурах. I>Внезапно оказывается, что нужен всего один оператор сравнения и нет никаких проблем с кешем, вообще, и нет нужды сравнивать все свойства на всю глубину.
Хм, а я разве где-то говорил, что вариант с иммутабельными данными хуже? ) Как раз наоборот, я везде подчёркивал, что именно наличие иммутабельных параметров для чистых функций и позволяет делать дополнительную оптимизацию. Т.е. очевидно что это лучше. Но это не значит, что другой вариант вообще невозможен.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>А, вы имеете в виду софт для архитекторов вроде IBM-овского? Нет, такого, конечно, нет.
Ну не обязательно сразу прямо таких монстров вспоминать. Есть множество инструментов полегче. Для начала хотелось бы увидеть какой-то аналог того же UML (а вот для него имеются уже тысячи готовых инструментов любого уровня монструозности) для разработки, которую предполагается вести с помощью чистого функционального языка. Бывает же очень удобно набросать соответствующие диаграммки при продумывание архитектуры нового приложения. А что у нас служит заменой этого при работе в функциональной парадигме? )
K>С какой стати это ограничение, если все, что можно сделать в императивном языке можно делать и одними только чистыми (причем по построению) функциями? Ограниченным будет как раз язык, в котором полноценными функциями, о которых можно рассуждать и которые можно оптимизировать являются не все.
Мы же уже обсуждали, что реальность (и исполнитель программы и задачи) у нас на самом деле совсем не чистые. Без проблем подобным образом обычно можно записать только небольшую часть программы (логику на самом высшем уровне абстракции), а остальное приходится записывать с помощью извращений.
Собственно тезис выше в чём-то аналогичен общеизвестному из императивного мира. "На ассемблере без проблем можно написать абсолютно любой софт." Вопрос в том удобно ли это...
K>А возможность точно есть? А то вы их пока не продемонстрировали. Да и судя по тому, что здесь
написано, никакой системы контроля за эффектами в D и нет.
А что собственно демонстрировать? ) Есть определённые критерии для чистых функций в D и гарантии компилятора на их исполнение. Надо показать, что компилятор работает без ошибок что ли? )))
K>Под ограничениями, я так понял, все еще имеется в виду небольшой синтаксический шум, компенсируемый отсутствием шума в других местах?
Главный нюанс в том, что этот "небольшой" шум на самом деле не нужен, если позволить иметь в языке несколько парадигм. Что и демонстрирует D.
K>А, понятно. Т.е. поддержкой чего-то в языке опять называется отсутствие потребности в такой колбасе. Чего-то такого я и ожидал.
Ну так поясните зачем может понадобится оптимизация копирования иммутабельных данных при их "изменение", если в языке разрешены мутабельные данные, причём действия с ними неотличимы от иммутабельных? Т.е. всё, что мы нагородили для оптимизации в том примере на Хаскеле просто выкидывается на помойку за ненадобностью.
K>Какие еще сложности?
На Хаскеле у нас было два вида решения той задачки:
— красивый, но не эффективный
— более эффективный, но с кучей лишнего мусорного кода
А на любом языке, разрешающем нечистые функции (т.е. практически на всех языках) это можно записать и красиво и эффективно.
K>Ничего не понимаю. А в хаскеле кто мешал использовать изменение по месту? Ведь код и в этом случае все равно получался лучше, чем на плюсах, хотя и хуже, чем в случае с работой с неизменяемыми данными, который благодаря "ненужным" оптимизациями еще и приближался по эффективности к тому, который работал с изменяемыми массивами.
Как только на Хаскеле можно будет спокойно использовать нечистые функции, я с этим полностью соглашусь. )))
_>>Только что-то основной расцвет подобных языков наблюдается как раз сейчас, в 21-ом веке... ) K>Что же в этом хорошего?
Насчёт хорошего — это сложный вопрос... Но в любом случае это полностью опровергает ваши предыдущие слова об эпохах и типизациях... )
K>Это питон-то с яваскриптом со всеми их фокусами — простые языки? Не смешите.
В Питоне много возможностей за счёт мультипарадигменности, но в своей основе он весьма прост. Я бы сказал, что это идеальный язык для освоение программирования неспециалистами.
JS же вообще очень маленький и простенький язык. Правда в нём при этом уместилось множество неоднозначностей (типа C++ UB), но к сложности языка это вообще никакого отношения не имеет.
K>Смотрим С++:
K>procedural, functional, object-oriented, generic
K>"процедурная" парадигма вообще никакого инструментария для написания хоть сколько-нибудь нетривиальных программ не дает и является красивым названием для "ничего нет". Функциональная парадигма, как мы выяснили в соседних ветках, в C++ не поддерживается. Обобщенное программирование парадигмой не является — это просто базворд для обозначаения средств для нормального типизирования ФП и ООП кода в языках, где таких средств изначально не было. Метапрограммирование также парадигмой не является. Таким образом, имеем поддержку ООП и необоснованные заявления о поддержке ФП — вот и вся мультипарадигменность.
K>Смотрим питон: object-oriented, imperative, functional, procedural, reflective K>Про процедурное уже сказано, object-oriented и imperative — это, фактически, одно и то же, ФП в питоне поддерживается на игрушечном уровне, хоть и не так плохо как в C++, reflective — очередное выдавание фичи за парадигму.
K>Вообще, выдаванием фичь за парадигмы, либо просто высасыванием парадигм из пальца как здесь, можно обосновать мультипарадигменность любого языка программирования.
Хыхы, ну так если там всё так неверно, то может подредактируете данные статьи в википедии до верного состояния?
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Что там изначально формулировал какой-то там автор, в данном случае значения не имеет. Я сослался на пример, как демонстрацию конкретной фичи, которая в хаскеле, яве, сишарпе (и, скорее всего, хотя проверять мне лень, окамле) есть, и которой в С++ (и, насколько я знаю, хотя проверять опять таки лень — в Аде и SML без расширений) наоборот нет. Исключительно как пример того, что полиморфизм в C#/Java хотя и убогий — по возможностям подмножеством плюсового не является.
Что за фича? )
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
I>>Подозреваю, проблему выше ты захочешь решить с помощью уникального идентификатора специально для таких кешей. То есть, объект-значение должен обладать еще и Identity. В общем случае это не решает проблему(оппа!), но в частных — поможет. I>>И вот у тебя для одного и того же класса понадобилось целых два оператора сравнения. Это, в кратце, означает, что вызывающий код должен быть в курсе того, как устроен объект А.
_>Что за ерунда? ) Как ты вообще собираешься производить кэширование объектов не имеющих корректных операторов сравнения?
Не я, а ты. Это ведь ты хочешь иметь мутабельные объекты-значения в то время, как во всех языках без исключения объекты значения стараются делать иммутабельными, хоть джаваскрипте, хоть в С#, хоть Java.
>Посмотри хотя бы тривиальные требования в том же std::map. А если такой оператор есть, то в чём тогда проблема? И никаких двух версий естественно не требуется.
Я описал в чем проблема. Если непонятно, покажи где именно, а то я пока склоняюсь к тому, что ты не осилил.
I>>А теперь, на секундочку, предположим, что детерминизм у нас самый что ни есть православный — а именно на иммутабельных структурах. I>>Внезапно оказывается, что нужен всего один оператор сравнения и нет никаких проблем с кешем, вообще, и нет нужды сравнивать все свойства на всю глубину.
_>Хм, а я разве где-то говорил, что вариант с иммутабельными данными хуже? ) Как раз наоборот, я везде подчёркивал, что именно наличие иммутабельных параметров для чистых функций и позволяет делать дополнительную оптимизацию. Т.е. очевидно что это лучше. Но это не значит, что другой вариант вообще невозможен.
Я и говорю — в твоей теории не хватает одного понятия — абсолютно чистые функции. А то неудобно говорить "чистые функции с иммутабельными параметрами".
Чистота функции в классическом понимании даёт целую кучу полезных свойств. Например чистые функции можно сделать асинхронными, можно запускать в другом потоке, процессоре. Можно сделать ленивыми, а можно соптимизировать еще каким нибудь способом способом, включая мемоизацию.
Вот ради таких свойств и есть смысл вводить понятие чистоты. Без этих свойств чистота никому не нужна.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не я, а ты. Это ведь ты хочешь иметь мутабельные объекты-значения в то время, как во всех языках без исключения объекты значения стараются делать иммутабельными, хоть джаваскрипте, хоть в С#, хоть Java.
О как забавно... Ну расскажи какие средства есть в перечисленных языках для этих целей. )
I>Я и говорю — в твоей теории не хватает одного понятия — абсолютно чистые функции. А то неудобно говорить "чистые функции с иммутабельными параметрами".
Эммм, а как мы можем внести в определение вида функции (которое должно зависеть только от самой функции) то, каким образом мы её вызываем? ) Ведь если мы возьмём чистую функцию в определение языка D и передадим ей иммутабельные данные (не меняя её прототип!), то все оптимизации можно исполнять по полной.
I>Чистота функции в классическом понимании даёт целую кучу полезных свойств. Например чистые функции можно сделать асинхронными, можно запускать в другом потоке, процессоре. Можно сделать ленивыми, а можно соптимизировать еще каким нибудь способом способом, включая мемоизацию.
Что ещё за классическое понимание? ) Сколько у нас собственно языков поддерживающих чистые функции, чтобы можно было выводить некое общее определение? И сколько из них допускают использование мутабельных данных (не обязательно в таких функциях, а вообще)?
I>Вот ради таких свойств и есть смысл вводить понятие чистоты. Без этих свойств чистота никому не нужна.
С такой точки зрения и константность вообще не нужна...
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не я, а ты. Это ведь ты хочешь иметь мутабельные объекты-значения в то время, как во всех языках без исключения объекты значения стараются делать иммутабельными, хоть джаваскрипте, хоть в С#, хоть Java.
_>О как забавно... Ну расскажи какие средства есть в перечисленных языках для этих целей. )
Самые разные: замыкания, свойства только для чтения и тд
I>>Я и говорю — в твоей теории не хватает одного понятия — абсолютно чистые функции. А то неудобно говорить "чистые функции с иммутабельными параметрами".
_>Эммм, а как мы можем внести в определение вида функции (которое должно зависеть только от самой функции) то, каким образом мы её вызываем? )
Здесь D повторяет особенности С++. Чистые функции в D это совсем не то же, что и чистые функции в функциональном программировании.
>Ведь если мы возьмём чистую функцию в определение языка D и передадим ей иммутабельные данные (не меняя её прототип!), то все оптимизации можно исполнять по полной.
Мулька в том, что ты должен знать "кака унутре неонка" что бы применять оптимизации. Чистота функций для того и нужна, что бы не знать про такие детали.
I>>Чистота функции в классическом понимании даёт целую кучу полезных свойств. Например чистые функции можно сделать асинхронными, можно запускать в другом потоке, процессоре. Можно сделать ленивыми, а можно соптимизировать еще каким нибудь способом способом, включая мемоизацию.
_>Что ещё за классическое понимание? )
То самое, которое ты боишься для себя открыть. Нет смысла говорить про чистоту, если распробовать её можно только при определенных условиях.
>Сколько у нас собственно языков поддерживающих чистые функции, чтобы можно было выводить некое общее определение?
Ты в самом деле думаешь, что понятия выводятся по имеющимся языкам программирования ?
>И сколько из них допускают использование мутабельных данных (не обязательно в таких функциях, а вообще)?
Практически все
I>>Вот ради таких свойств и есть смысл вводить понятие чистоты. Без этих свойств чистота никому не нужна.
_>С такой точки зрения и константность вообще не нужна...
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, dimgel, Вы писали:
D>Здравствуйте, Greeter, Вы писали:
G>>Или не до конца понимаете в программировании?
D>Монады. Несколько раз подкатывал, без толку.
а я даже понял. они служат просто для сцепления, комбинирования методов.
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Вот ради таких свойств и есть смысл вводить понятие чистоты. Без этих свойств чистота никому не нужна.
_>С такой точки зрения и константность вообще не нужна...
Правильно. Константность нужна именно из-за своих свойств, а не просто так.
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну не обязательно сразу прямо таких монстров вспоминать. Есть множество инструментов полегче. Для начала хотелось бы увидеть какой-то аналог того же UML (а вот для него имеются уже тысячи готовых инструментов любого уровня монструозности) для разработки, которую предполагается вести с помощью чистого функционального языка.
Инструменты полегче можно использовать и так, зачем еще какие-то аналоги? Их и используют, правда редко. Вот, вполне популярный пакет lens у которого в документации UML-диаграмма, построенная во вполне "готовом инструменте" creately.com
_>Мы же уже обсуждали, что реальность (и исполнитель программы и задачи) у нас на самом деле совсем не чистые.
Это зависит от модели реальности. Волновые функции, операторы импульса/координат и гамильтониан совсем чистые.
_>Без проблем подобным образом обычно можно записать только небольшую часть программы (логику на самом высшем уровне абстракции),
На самом деле, в виде чистых функций можно записать всю программу, она на хаскеле именно так и записывается.
_>а остальное приходится записывать с помощью извращений.
Вы все повторяете про "проблемы" и "извращения", хотя на самом деле ничего кроме небольшого синтаксического шума, компенсируемого отсутствием шума в других местах так и не продемонстрировали. Причем как-то его можно заметить только на примере в одну строчку, а чем строк больше — тем сильнее "якобы проблемный" вариант выигрывает у "якобы непроблемного".
_>Собственно тезис выше в чём-то аналогичен общеизвестному из императивного мира. "На ассемблере без проблем можно написать абсолютно любой софт." Вопрос в том удобно ли это...
Нет, конечно. Удобно — наоборот — на чистом ФЯ.
_>А что собственно демонстрировать? )
А что собственно демонстрировать уже неоднократно написано. Например здесь
1) Более-менее полноценная поддержка для комбинирования комбинаторов.
2) Возможность рассуждать об этих комбинаторах как о математических объектах (с оговорками).
Для этого нужна более-менее нормальная система типов, полноценная поддержка ленивости, специальные оптимизации, и контроль за эффектами как сам по себе, так и для нормальной работы ленивости и оптимизатора.
_>Есть определённые критерии для чистых функций в D и гарантии компилятора на их исполнение. Надо показать, что компилятор работает без ошибок что ли? )))
Нет, надо бы, как минимум, продемонстрировать какие-то осмысленные гарантии, потому что смысл проверки показанной по ссылке выше, может и есть, но лежит не в практической плоскости, а в плоскости карго-культа: Говорят, что лучших домах Филадельфии популярен контроль за эффектами. Что это такое мы не совсем понимаем, но что-нибудь проконтролируем и галочку поставим, а духи предков в награду за это нам пришлют бразиллионы сэкономленных мифических человекомесяцев.
_>Главный нюанс в том, что этот "небольшой" шум на самом деле не нужен, если позволить иметь в языке несколько парадигм. Что и демонстрирует D.
Этот действительно небольшой шум следовало бы сделать и еще меньше. Но вот что он не нужен D вовсе не демонстрирует, потому что, как мы выяснили, ничего аналогичного в D нет.
_>Ну так поясните зачем может понадобится оптимизация копирования иммутабельных данных при их "изменение", если в языке разрешены мутабельные данные, причём действия с ними неотличимы от иммутабельных?
Очевидно затем, что писать, читать, поддерживать и тестировать код, который работает с иммутабельными структурами данных обычно легче, чем тот, что работает с мутабельными.
_>На Хаскеле у нас было два вида решения той задачки: _>- красивый, но не эффективный
Вполне приемлемый, как раз за счет "ненужных" оптимизаций.
_>- более эффективный, но с кучей лишнего мусорного кода
Вот только демонстрирование куч "лишнего мусорного кода" все откладывается, в обсуждаемом примере его оказалось не больше, чем в коде на плюсах.
_>А на любом языке, разрешающем нечистые функции (т.е. практически на всех языках) это можно записать и красиво и эффективно.
Эффективно на некоторых можно (список очень короткий), а красиво, конечно, не получится.
_>Как только на Хаскеле можно будет спокойно использовать нечистые функции, я с этим полностью соглашусь. )))
Как только в хаскеле можно будет спокойно использовать "нечистые функции" — в нем нельзя будет использовать функции, т.е ничего от него не останется.
_>Насчёт хорошего — это сложный вопрос... Но в любом случае это полностью опровергает ваши предыдущие слова об эпохах и типизациях... )
Каким образом то, что нечто изобретенное в 60-х, например, используется и даже популярно сейчас опровергает то, что оно изобретено в 60-х? Вот если бы кто-то сказал, что что-то появилось сейчас, а вы бы доказали, что оно и в 60-х применялось — вот тогда это утверждение было бы опровергнуто.
K>>Это питон-то с яваскриптом со всеми их фокусами — простые языки? Не смешите.
_>В Питоне много возможностей за счёт мультипарадигменности,
И это пока евангелисты еще ультрапарадигменность не открыли: какая бездна возможностей откроется после этого — страшно даже представить.
_>но в своей основе он весьма прост. Я бы сказал, что это идеальный язык для освоение программирования неспециалистами.
Это потому, что за такое
>>> i = 42
>>> [i for i in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> i
9
специалист будет бить канделябром, а неспециалист смириться, потому что слаще питона ничего не пробовал?
_>JS же вообще очень маленький и простенький язык. Правда в нём при этом уместилось множество неоднозначностей (типа C++ UB), но к сложности языка это вообще никакого отношения не имеет.
Наоборот, как раз это сложность языка в первую очередь и определяют. И если в том же C++ обычно приходится сделать сложно именно потому, что нормально сделать нельзя из-за дизайнерского решения "не используешь — не платишь", которое как раз может быть оправдано, то в питонах и яваскриптах сделано сложно из-за узкого кругозора, воинствующего антиинтеллектуализма и общей склонности к халтуре.
_>Хыхы, ну так если там всё так неверно, то может подредактируете данные статьи в википедии до верного состояния?
Это сделать невозможно. Статьи про популярные языки являются уютными гнездами специфических комьюнити, которые все невеликое множество реально существующих достоинств этих языков уже перечислили и давно заняты высасыванием из пальца достоинств несуществующих. Длинные списки "парадигм" как раз и иллюстрируют это в наиболее яркой и гротескной форме. И любая попытка адекватно представить язык неминуемо приведет к тотальной войне правок с интересными личностями, которые это воспримут как преступное покушение на всемогуторность их любимого 256-ипарадигменного языка, особенно если авторами 255 из этих "парадигм" являются лично они.
Исправить тут ничего нельзя, это нужно просто иметь в виду.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Чистота функции в классическом понимании даёт целую кучу полезных свойств. Например чистые функции можно сделать асинхронными, можно запускать в другом потоке, процессоре. Можно сделать ленивыми, а можно соптимизировать еще каким нибудь способом способом, включая мемоизацию.
_>Что ещё за классическое понимание? ) Сколько у нас собственно языков поддерживающих чистые функции, чтобы можно было выводить некое общее определение? И сколько из них допускают использование мутабельных данных (не обязательно в таких функциях, а вообще)?
Кстати говоря, про классику. Martin Odersky в курсах functional programming и principles of reactive programming внятно объясняет, что это и почему это. Например см Functions and State. Он использует термин rewriting, а с тз лямбда счисления все переписывания которе завершаются должны давать один и тот же результат, например
теперь форкус, если взять императивную версию факториала, то внезапно оказывается, что переписывание не работает, что очевидно.
Еще фокус, если взять "как бы чистую" функцию, но без детерминизма, то, внезапно, получается, что переписывание снова не работает, что так же очевидно.
То есть, за объяснениями надо идти не в языки программирования, а втыкать в лямбда счисление.
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Самые разные: замыкания, свойства только для чтения и тд
Ну и как эти вещи могут помочь в гарантии иммутабельности локальной переменной, передаваемой в чистую функцию? )
I>Здесь D повторяет особенности С++. Чистые функции в D это совсем не то же, что и чистые функции в функциональном программировании.
Ещё раз: "чистые функции в ФП" — это крайне сомнительной понятие, т.к. практически все языки с ФП не имеют прямой поддержки данной возможности. Её имеет один чисто функциональный язык (Хаскель) и один мультипарадигменный (D). Так что проводить какие-то подобные сравнения очень странно. Более того, с учётом того, что в Хаскеле по сути нет мутабельных данных, указателей и т.п., то определения этих функций в Хаскеле и D совпадают — D просто расширяет это определение уже на ту область, которой в Хаскеле вообще нет.
I>Мулька в том, что ты должен знать "кака унутре неонка" что бы применять оптимизации. Чистота функций для того и нужна, что бы не знать про такие детали.
Тот факт, что результат действия функции зависит исключительно от переданных параметров, является более чем достаточным для любых оптимизаций вызовов данной функции.
>>И сколько из них допускают использование мутабельных данных (не обязательно в таких функциях, а вообще)? I>Практически все
Ну давай, перечисли хотя бы несколько. )))
_>>С такой точки зрения и константность вообще не нужна... I>Правильно. Константность нужна именно из-за своих свойств, а не просто так.
Ага. Причём это свойство во многих случаях никак не связано с оптимизацией, а связано с гарантиями на код. Точно так же может действовать и модификатор pure в D.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Инструменты полегче можно использовать и так, зачем еще какие-то аналоги? Их и используют, правда редко. Вот, вполне популярный пакет lens у которого в документации UML-диаграмма, построенная во вполне "готовом инструменте" creately.com
Диаграмма классов в Хаскеле? Мдаа, и чего только не сделаешь от бедности инструментов...
K>Это зависит от модели реальности. Волновые функции, операторы импульса/координат и гамильтониан совсем чистые.
Ага, ага... Т.е. электрон будет всегда пролетать только через левое отверстие (детерминизм чистой функции) и никогда через правое?
K>Вы все повторяете про "проблемы" и "извращения", хотя на самом деле ничего кроме небольшого синтаксического шума, компенсируемого отсутствием шума в других местах так и не продемонстрировали. Причем как-то его можно заметить только на примере в одну строчку, а чем строк больше — тем сильнее "якобы проблемный" вариант выигрывает у "якобы непроблемного".
Как раз если бы я привёл полный код той фильтрации, то его аналог на Хаскеле выглядел бы полным страхом (естественно при условии, что мы попытались бы сохранить приемлемое быстродействие).
K>Нет, конечно. Удобно — наоборот — на чистом ФЯ.
Ага, ага... Популярность Хаскеля это очень хорошо демонстрирует... Причём я даже не о популярности относительно главных монстров с огромным наследием (типа C++ и т.п.) — можем сравнить и с самыми новичками (типа какого-нибудь Go) и всё равно увидим отставание Хаскеля от них.
K>А что собственно демонстрировать уже неоднократно написано. Например здесь
K>1) Более-менее полноценная поддержка для комбинирования комбинаторов.
K>2) Возможность рассуждать об этих комбинаторах как о математических объектах (с оговорками).
K>Для этого нужна более-менее нормальная система типов, полноценная поддержка ленивости, специальные оптимизации, и контроль за эффектами как сам по себе, так и для нормальной работы ленивости и оптимизатора.
А причём тут это всё, если в данном контексте мы говорили только про чистоту? )
K>Нет, надо бы, как минимум, продемонстрировать какие-то осмысленные гарантии, потому что смысл проверки показанной по ссылке выше, может и есть, но лежит не в практической плоскости, а в плоскости карго-культа: Говорят, что лучших домах Филадельфии популярен контроль за эффектами. Что это такое мы не совсем понимаем, но что-нибудь проконтролируем и галочку поставим, а духи предков в награду за это нам пришлют бразиллионы сэкономленных мифических человекомесяцев.
Я вроде как показал конкретный пример кода, который компилятор не разрешает. Что не так то? )
K>Этот действительно небольшой шум следовало бы сделать и еще меньше. Но вот что он не нужен D вовсе не демонстрирует, потому что, как мы выяснили, ничего аналогичного в D нет.
Потому что он реально не нужен при наличие в языке нормальных мутабельных данных.
K>Очевидно затем, что писать, читать, поддерживать и тестировать код, который работает с иммутабельными структурами данных обычно легче, чем тот, что работает с мутабельными.
Так с реально иммутабельными данными в D тоже всё нормально. Та оптимизация в Хаскеле возникла при потребности эффективной (т.е. без копирования) модификации вроде как иммутабельных данных — в D такой проблемы просто не существует, т.к. есть и такие данные и такие.
K>Каким образом то, что нечто изобретенное в 60-х, например, используется и даже популярно сейчас опровергает то, что оно изобретено в 60-х? Вот если бы кто-то сказал, что что-то появилось сейчас, а вы бы доказали, что оно и в 60-х применялось — вот тогда это утверждение было бы опровергнуто.
Ааа так речь шла исключительно о времени изобретения концепции?) Тогда ладно. Но только тогда совершенно непонятно что плохого в этом.
K>Это потому, что за такое K>
>>>> i = 42
>>>> [i for i in xrange(10)]
K>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>> i
K>9
K>
K>специалист будет бить канделябром, а неспециалист смириться, потому что слаще питона ничего не пробовал?
А что тут собственно не так? ) Подобный код в принципе на очень многих языках пишется (разве что не везде так кратко, т.к. не везде есть генераторы).
K>Наоборот, как раз это сложность языка в первую очередь и определяют. И если в том же C++ обычно приходится сделать сложно именно потому, что нормально сделать нельзя из-за дизайнерского решения "не используешь — не платишь", которое как раз может быть оправдано, то в питонах и яваскриптах сделано сложно из-за узкого кругозора, воинствующего антиинтеллектуализма и общей склонности к халтуре.
Хм, возможно я и частично согласен со всем этим... Но всё же не стал бы называть подобное сложностью. Хотя бы потому, что очень многие пользователи данных языков могут долго долго программировать на них и при этом никогда не столкнуться с подобными UB и т.п.
K>Это сделать невозможно. Статьи про популярные языки являются уютными гнездами специфических комьюнити, которые все невеликое множество реально существующих достоинств этих языков уже перечислили и давно заняты высасыванием из пальца достоинств несуществующих. Длинные списки "парадигм" как раз и иллюстрируют это в наиболее яркой и гротескной форме. И любая попытка адекватно представить язык неминуемо приведет к тотальной войне правок с интересными личностями, которые это воспримут как преступное покушение на всемогуторность их любимого 256-ипарадигменного языка, особенно если авторами 255 из этих "парадигм" являются лично они. K>Исправить тут ничего нельзя, это нужно просто иметь в виду.
Я просто намекаю, что данная позиция уж очень напоминает некого Д'Артаньяна...
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Еще фокус, если взять "как бы чистую" функцию, но без детерминизма, то, внезапно, получается, что переписывание снова не работает, что так же очевидно.
Я тебе уже несколько раз писал, что чистые функции в определение D являются вполне себе детерминированными. Если ты за столько раз не можешь воспринять эту информацию, то я не вижу смысла продолжать разговор.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я тебе уже несколько раз писал, что чистые функции в определение D являются вполне себе детерминированными. Если ты за столько раз не можешь воспринять эту информацию, то я не вижу смысла продолжать разговор.
Этот "детерминизм" D не имеет никакого отношения к детерминизму в лямбда-счислении. Просто автор решил реализовать слово pure.
A a = new A();
x = f(a);
...
y = f(a);
Лямбда-счисление говорит, что независимо от того, что было на месте троеточия, x и y будут эквивалентны. Это и есть детерминизм.
Проверяем, вместо троеточия подставляем x.mutate(); и получаем, что x и y не эквивалентны.
Все, детерминизм закончился.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Самые разные: замыкания, свойства только для чтения и тд
_>Ну и как эти вещи могут помочь в гарантии иммутабельности локальной переменной, передаваемой в чистую функцию? )
Не надо вилять — мы говорили про иммутабельность объетов-значений, а не про локальные переменные
I>>Здесь D повторяет особенности С++. Чистые функции в D это совсем не то же, что и чистые функции в функциональном программировании.
_>Ещё раз: "чистые функции в ФП" — это крайне сомнительной понятие, т.к. практически все языки с ФП не имеют прямой поддержки данной возможности.
При чем здесь языки, если это растет из лямбда-счисления ?
I>>Мулька в том, что ты должен знать "кака унутре неонка" что бы применять оптимизации. Чистота функций для того и нужна, что бы не знать про такие детали.
_>Тот факт, что результат действия функции зависит исключительно от переданных параметров, является более чем достаточным для любых оптимизаций вызовов данной функции.
Разумеется не является. Для оптимизацией необходимо следующее:
x = f(a);
y = f(a);
В любой момент времени x и y должны быть эквивалентны, это основы лямбда-счисления. Ты хорошо понимаешь, что если a это мутабельный объект, то это условие невыполнимо ?
_>Ну давай, перечисли хотя бы несколько. )))
Рассматривай это как домашнее задание.
I>>Правильно. Константность нужна именно из-за своих свойств, а не просто так.
_>Ага. Причём это свойство во многих случаях никак не связано с оптимизацией, а связано с гарантиями на код. Точно так же может действовать и модификатор pure в D.
pure это полу-гарантии, на честном слове, если программист не ошибся, и то не ясно, как этим может воспользовать компилятор. Пудозреваю, никак, ибо случай выше неприменим
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Этот "детерминизм" D не имеет никакого отношения к детерминизму в лямбда-счислении. Просто автор решил реализовать слово pure.
I>
I>A a = new A();
I>x = f(a);
I>...
I>y = f(a);
I>
I>Лямбда-счисление говорит, что независимо от того, что было на месте троеточия, x и y будут эквивалентны. Это и есть детерминизм.
I>Проверяем, вместо троеточия подставляем x.mutate(); и получаем, что x и y не эквивалентны. I>Все, детерминизм закончился.
С чего это x и y должны быть одинаковыми, если ты передаёшь в функцию разные данные? Твоё сомнительное "определение" детерминизма ещё можно переделать к корректному приблизительно так:
A a();
const A t=a;
x = f(a);
...
if(a==t) y = f(a);
Вот при таком раскладе x и y действительно должны быть всегда (когда x и y вообще вычисляются) равны... )
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не надо вилять — мы говорили про иммутабельность объетов-значений, а не про локальные переменные
Мы говорили про чистые функции вообще то.
I>При чем здесь языки, если это растет из лямбда-счисления ?
В математике вообще нет понятий типа ссылок, указателей и т.п. Так что при переносе математики в программирование в любом случае приходится делать определённую адаптацию.
I>Разумеется не является. Для оптимизацией необходимо следующее: I>x = f(a); I>y = f(a); I>В любой момент времени x и y должны быть эквивалентны, это основы лямбда-счисления. Ты хорошо понимаешь, что если a это мутабельный объект, то это условие невыполнимо ?
Мутабельный это объект или нет:
1. Является внешним фактом относительно самой функции.
2. Полностью находится по контролем компилятора.
Так что ОТ ФУНКЦИИ компилятору нужно именно такое определение чистоты, как в D. А далее он уже может смотреть как её вызывают и соответственно решать какие оптимизации тут можно применять.
I>Рассматривай это как домашнее задание.
Слился значит, ну понятно... )
I>pure это полу-гарантии, на честном слове, если программист не ошибся, и то не ясно, как этим может воспользовать компилятор. Пудозреваю, никак, ибо случай выше неприменим
Да млин, ты не понимаешь что ли, что здесь речь не об оптимизации, а о гарантиях компилятора, что данная функция не имеет побочных эффектов? ) Так же как и скажем модификатор const позволяет компилятору давать определённые гарантии корректности кода, даже если при этом оптимизатор вообще не затрагивается.
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Проверяем, вместо троеточия подставляем x.mutate(); и получаем, что x и y не эквивалентны. I>>Все, детерминизм закончился.
_>С чего это x и y должны быть одинаковыми, если ты передаёшь в функцию разные данные?
Не я, а ты. Это ведь у тебя чистота включает в себя мутабельность.
>Твоё сомнительное "определение" детерминизма ещё можно переделать к корректному приблизительно так:
Оно не мое. Ты проигнорировал мой пример, это азы лямбда-счисления.
_>
_>
Код я скипнул — ты изобретаешь свою собственную версию лябда-счисления.
_>Вот при таком раскладе x и y действительно должны быть всегда (когда x и y вообще вычисляются) равны... )
Это в твоей версии лямбда-счислении. А вообще вот так
A a();
y = f(a)
...
x = f(a)
x должно быть эквивалентно y всегда, в любой момент времени.
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не надо вилять — мы говорили про иммутабельность объетов-значений, а не про локальные переменные
_>Мы говорили про чистые функции вообще то.
В данном контексте речь была пр объекты значения, цитирую " ты хочешь иметь мутабельные объекты-значения в то время, как во всех языках без исключения объекты значения стараются делать иммутабельными"
I>>При чем здесь языки, если это растет из лямбда-счисления ?
_>В математике вообще нет понятий типа ссылок, указателей и т.п. Так что при переносе математики в программирование в любом случае приходится делать определённую адаптацию.
Вообще то есть. ссылки, индексы, эквивалентность, идентичность объектов это математика в чистом виде.
I>>Разумеется не является. Для оптимизацией необходимо следующее: I>>x = f(a); I>>y = f(a); I>>В любой момент времени x и y должны быть эквивалентны, это основы лямбда-счисления. Ты хорошо понимаешь, что если a это мутабельный объект, то это условие невыполнимо ?
_>Мутабельный это объект или нет:
_>1. Является внешним фактом относительно самой функции.
Неверно. f(a) в любой момент времени обязано быть эквивалентно f(a). Если мутабельность это внешний факт, то и эквивалетность, внезапно, так же становится внешним фактом.
А раз так, то компилятор вынужден получить гарантии во внешнем коде, прежде чем приступать к оптимизации функции. В общем случае это нерешаемая задача, ибо мутабельный код препятствует ссылочной прозрачности.
_>2. Полностью находится по контролем компилятора.
Неверно. см выше, мутабельность исключает ссылочную прозрачность.
_>Так что ОТ ФУНКЦИИ компилятору нужно именно такое определение чистоты, как в D. А далее он уже может смотреть как её вызывают и соответственно решать какие оптимизации тут можно применять.
Не сможет он ничего сделать. Мутабельность сразу исключает ссылочную прозрачность, а раз так, то никакие оптимизации неприменимы.
I>>pure это полу-гарантии, на честном слове, если программист не ошибся, и то не ясно, как этим может воспользовать компилятор. Пудозреваю, никак, ибо случай выше неприменим
_>Да млин, ты не понимаешь что ли, что здесь речь не об оптимизации, а о гарантиях компилятора, что данная функция не имеет побочных эффектов? )
Ну так гарантий нет. Если понимать чистоту согласно лямбда-счислению, то все в порядке. А иначе твои слова требуют формальных доказательств, прямо как у Чёрча или Тьюринга.
>Так же как и скажем модификатор const позволяет компилятору давать определённые гарантии корректности кода, даже если при этом оптимизатор вообще не затрагивается.
const вообще говоря не нужен ,если брать за основу лямбда-счисление. Ручные подсказки компилятору вообще не нужны, компилятор сможет сам выяснить, где есть чистота, а где её нет.
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В данном контексте речь была пр объекты значения, цитирую " ты хочешь иметь мутабельные объекты-значения в то время, как во всех языках без исключения объекты значения стараются делать иммутабельными"
Правильно. И речь шла о передаче подобных объектов в качестве параметров функции. Так как там перечисленные языки обеспечивают подобную возможность? )
Или вдруг неожиданно окажется, что императивный C++ (не говоря уже про D) имеет тут возможностей больше, чем вроде как языки с налётом функциональности?
I>Вообще то есть. ссылки, индексы, эквивалентность, идентичность объектов это математика в чистом виде.
Речь не о математическом моделирование подобных сущностей, а о наличие их в самой математике.
I>Неверно. f(a) в любой момент времени обязано быть эквивалентно f(a). Если мутабельность это внешний факт, то и эквивалетность, внезапно, так же становится внешним фактом.
О, наконец то дошло...
I>А раз так, то компилятор вынужден получить гарантии во внешнем коде, прежде чем приступать к оптимизации функции. В общем случае это нерешаемая задача, ибо мутабельный код препятствует ссылочной прозрачности.
Чего чего? ) Речь идёт не об оптимизации кода функции (она вообще может быть в DLL некой), а об оптимизации её вызова (кэширование, ленивость и т.п.). И для этой задачи нам как раз достаточно знать, что функция чистая в определение D. После этого компилятор смотрит на её параметры (мы же оптимизируем вызов — все параметры у нас перед глазами, под полным контролем) и решает возможно ли применить подобную оптимизацию (если параметры иммутабельные) или нет.
I>Не сможет он ничего сделать. Мутабельность сразу исключает ссылочную прозрачность, а раз так, то никакие оптимизации неприменимы.
Ну так а кто тебе мешает использовать иммутабельные параметры то? ) Но при этом код будет спокойно работать и с мутабельными, просто без дополнительной (!) оптимизации.
I>Ну так гарантий нет. Если понимать чистоту согласно лямбда-счислению, то все в порядке. А иначе твои слова требуют формальных доказательств, прямо как у Чёрча или Тьюринга.
Эээ что? ) Я не пойму, ты сомневаешься, что компилятор будет гарантировать отсутствие побочных эффектов у функций помеченных модификатором pure? )
I>const вообще говоря не нужен ,если брать за основу лямбда-счисление. Ручные подсказки компилятору вообще не нужны, компилятор сможет сам выяснить, где есть чистота, а где её нет.
Угу, угу... Может и статическая типизация тогда тоже не нужна? )
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Диаграмма классов в Хаскеле? Мдаа, и чего только не сделаешь от бедности инструментов...
Мне даже интересно, чего бы вы ожидали от "специального инструмента для хаскеля" вместо диаграммы классов. Гаплограмму сепулек?
_>Ага, ага... Т.е. электрон будет всегда пролетать только через левое отверстие (детерминизм чистой функции) и никогда через правое?
Нет, конечно. Тем не менее волновая функция именно "чистая". Других функций-то не бывает.
_>Как раз если бы я привёл полный код той фильтрации, то его аналог на Хаскеле выглядел бы полным страхом (естественно при условии, что мы попытались бы сохранить приемлемое быстродействие).
Ну, как обычно — выглядел бы. А как только дойдет до конкретики опять выяснится, что это плохой пример, но вот что-то другое выглядело бы полным ужасом. Короче говоря, ваши монадические ужасы непознаваемы, в них нужно верить потому, что абсурдно, примеры только веру подрывают.
_>Ага, ага... Популярность Хаскеля это очень хорошо демонстрирует...
Удобство никак не связано с популярностью. Те же C++ и Java в числе самых популярных, а практически любой язык (кроме специально придуманных неудобными вроде Интеркола) удобнее, чем они.
_>Причём я даже не о популярности относительно главных монстров с огромным наследием (типа C++ и т.п.) — можем сравнить и с самыми новичками (типа какого-нибудь Go) и всё равно увидим отставание Хаскеля от них.
Смотрим какой-нибудь langpop и видим, что наблюдаемой разницы в популярности между Go и Haskell нет. Хотя, конечно, можно подобрать какую-нибудь метрику (частота встречаемости в новостной ленте любителя Го) где какая-то разница будет.
_>А причём тут это всё, если в данном контексте мы говорили только про чистоту? )
При том, что именно для этого всего чистота и нужна.
_>Я вроде как показал конкретный пример кода, который компилятор не разрешает. Что не так то? )
Ну а D. Mon показал конкретный пример кода, который компилятор разрешает. И никакой практически значимой разницы между примерами нет, т.е. ценность неразрешения компилятора нулевая.
K>>Этот действительно небольшой шум следовало бы сделать и еще меньше. Но вот что он не нужен D вовсе не демонстрирует, потому что, как мы выяснили, ничего аналогичного в D нет.
_>Потому что он реально не нужен при наличие в языке нормальных мутабельных данных.
Поддерживать в языке мутабельные данные как раз просто, для этого вообще ничего не нужно. Контроль за эффектами нужен, чтоб нормально поддерживать ФП. Если это не нужно, то и контроль за эффектами, в основном, не нужен — разве что для дрессировки программиста.
_>Так с реально иммутабельными данными в D тоже всё нормально.
Нет конечно, потому что для того, чтоб было все нормально нужны средства оптимизации, которые снижают накладные расходы на использование иммутабельных структур. Убирание лишних копирований иммутабельных массивов, дефорестация, "переписывание хвостов" у списков, в том числе и быстрое потокобезопасное, копирующий сборщик, который перемещает объекты в памяти так, чтоб улучшить локальность и так далее. Без этого иммутабельные данные останутся игрушкой.
_>Та оптимизация в Хаскеле возникла при потребности эффективной (т.е. без копирования) модификации вроде как иммутабельных данных — в D такой проблемы просто не существует, т.к. есть и такие данные и такие.
Ну так этот подход "вы можете работать с иммутабельными данными, но медленно и мучительно, зато вы можете с ними не работать, а работать с мутабельными" принципиально ущербный. Он к тому и сведется, что работать будут с мутабельными данными — вот и все. Смысл же поддержки чего-то в том, чтоб это можно было на практике использовать, а не для того, чтоб поставить галочку, отписаться на форуме, а использовать что-то другое.
_>Но только тогда совершенно непонятно что плохого в этом.
Да ничего плохого, как нет ничего плохого в том, чтоб использовать в 2014-ом году калькулятор HP-35 и ездить на Ford Falcon, например.
K>>Это потому, что за такое K>>
>>>>> i = 42
>>>>> [i for i in xrange(10)]
K>>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>>> i
K>>9
K>>
K>>специалист будет бить канделябром, а неспециалист смириться, потому что слаще питона ничего не пробовал?
_>А что тут собственно не так?
Тяжелый случай.
_>Подобный код в принципе на очень многих языках пишется
Это точно, только вот этот код "на очень многих языках" выдает совсем другой результат.
> let i = 42
> [i | i <- [0..9]]
[0,1,2,3,4,5,6,7,8,9]
> i
42
или
> let i = 42;;
> [for i in {0..9} -> i];;
val it : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
> i;;
val it : int = 42
_>Я просто намекаю, что данная позиция уж очень напоминает некого Д'Артаньяна...
Позиция придумывающего 257-ю парадигму, чтоб украсить вики-статью про любимый язык (и таким образом показать всем у кого гм... Д'Артаньян длиннее) не просто напоминает "позицию Д'Артаньяна", а является хрестоматийным ее примером.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В данном контексте речь была пр объекты значения, цитирую " ты хочешь иметь мутабельные объекты-значения в то время, как во всех языках без исключения объекты значения стараются делать иммутабельными"
_>Правильно. И речь шла о передаче подобных объектов в качестве параметров функции. Так как там перечисленные языки обеспечивают подобную возможность? )
Я уже перечислил.
_>Или вдруг неожиданно окажется, что императивный C++ (не говоря уже про D) имеет тут возможностей больше, чем вроде как языки с налётом функциональности?
Не больше. Вспотеешь описывать const все возможные параметры.
I>>Вообще то есть. ссылки, индексы, эквивалентность, идентичность объектов это математика в чистом виде.
_>Речь не о математическом моделирование подобных сущностей, а о наличие их в самой математике.
То есть, ты сомневаешься что лямбда-счисление и подобные вещи это математика ?
I>>А раз так, то компилятор вынужден получить гарантии во внешнем коде, прежде чем приступать к оптимизации функции. В общем случае это нерешаемая задача, ибо мутабельный код препятствует ссылочной прозрачности.
_>Чего чего? ) Речь идёт не об оптимизации кода функции (она вообще может быть в DLL некой), а об оптимизации её вызова (кэширование, ленивость и т.п.). И для этой задачи нам как раз достаточно знать, что функция чистая в определение D. После этого компилятор смотрит на её параметры (мы же оптимизируем вызов — все параметры у нас перед глазами, под полным контролем) и решает возможно ли применить подобную оптимизацию (если параметры иммутабельные) или нет.
И здесь оказывается, что у компилятора нет никаких гарантий иммутабельности, потому что это делается через ссылочную прозрачность, а её нет и быть не может.
I>>Не сможет он ничего сделать. Мутабельность сразу исключает ссылочную прозрачность, а раз так, то никакие оптимизации неприменимы.
_>Ну так а кто тебе мешает использовать иммутабельные параметры то? ) Но при этом код будет спокойно работать и с мутабельными, просто без дополнительной (!) оптимизации.
Если нет ссылочной прозрачности, то компилятор про иммутабельность ничего не узнает.
I>>Ну так гарантий нет. Если понимать чистоту согласно лямбда-счислению, то все в порядке. А иначе твои слова требуют формальных доказательств, прямо как у Чёрча или Тьюринга.
_>Эээ что? ) Я не пойму, ты сомневаешься, что компилятор будет гарантировать отсутствие побочных эффектов у функций помеченных модификатором pure? )
Я утверждаю, что ты изобретаешь парадигму, только стесняешься это признать. Вместо этого трактуешь лямбда-счисление так как тебе угодно.
I>>const вообще говоря не нужен ,если брать за основу лямбда-счисление. Ручные подсказки компилятору вообще не нужны, компилятор сможет сам выяснить, где есть чистота, а где её нет.
_>Угу, угу... Может и статическая типизация тогда тоже не нужна? )
Ты путаешь статическую типизацию и ручные аннотации типов и ограничений. Первое даёт гарантии, второе в общем случае не работает.
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>x должно быть эквивалентно y всегда, в любой момент времени.
_>И с чего ты взял подобную чушь? Под такое определение не подходит даже функция вида _>
_>int f(int v){return v;}
_>
_>Т.е. получается что она у тебя тоже не чистая? )
Подходит. f(5) всегда будет равно 5 и так все всегда будет f(5).
В лямбда счислении нет никаких присваиваний, поэтому f(x) всегда и везде будет f(x), и если x равно 5, то это эквивалентно f(5) и 5, и так независимо ни от чего.
Это в С++ ты можешь объявить переменную и переприсвоить, поэтому f(x) != f(x), но это говорит не о том, что функция не чистая, а о том, что твой код не имеет никакого отношения к лямбда-счислению. Чистота функции это растет из лямбда счисления. Нет лямбда-счисления -> чистота не имеет никакого смысла.
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так а кто тебе мешает использовать иммутабельные параметры то? ) Но при этом код будет спокойно работать и с мутабельными, просто без дополнительной (!) оптимизации. _>Угу, угу... Может и статическая типизация тогда тоже не нужна? )
Вообще говоря, если у компилятора есть полный исходный код, то ему вроде как и не нужен модификатор pure — он проанализирует тела всех функций и будет знать, какие чистые, а какие нет.
Получается, что pure нужен не только для дополнительных оптимизаций, а скорее для:
1) облегчения чтения кода программистом (не надо анализировать груду кода, достаточно взглянуть на сигнатуру функции);
2) облегчения модификации кода программистом (не получим — случайно — побочных эффектов там, где это не ожидается);
3) создания модульных систем, когда у нас исходников соседнего модуля нет, а есть только бинарник (правда, к D это не факт, что имеет отношение).
Очевидно, что для пунктов 1 и 2 нужны только "по-настоящему чистые" функции, допускающие только иммутабельные аргументы.
Иначе мы можем не просто потерять необязательную оптимизацию, но и случайно изменить поведение системы нежелательным образом.
int pure OuterFunc<T>(T param) where T : IMyInterface
{
param.Modify(); // можно ли вызывать? а черт его знаетvar result = InnerFunc(param); // InnerFunc тоже "чистая"
...
}
То есть модификатор pure в D далеко не так полезен, как мог бы быть.
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Мне даже интересно, чего бы вы ожидали от "специального инструмента для хаскеля" вместо диаграммы классов. Гаплограмму сепулек?
В том то и дело, что я не знаю как должен выглядеть подобный инструмент для Хаскеля, т.к. не видел вообще ни одного реального примера. Фанаты ФП конечно пытаются искать какие-то замены... Например вот http://habrahabr.ru/post/211871/ наша статья на эту тему, а вот http://stackoverflow.com/questions/2457903/can-uml-be-used-to-model-a-functional-program обсуждение на SO по этой теме. Но как видно, ничего серьёзного так и не предлагается. Максимум наколенные инструменты из 70-ых годов прошлого века.
K>Удобство никак не связано с популярностью. Те же C++ и Java в числе самых популярных, а практически любой язык (кроме специально придуманных неудобными вроде Интеркола) удобнее, чем они.
Нет языка удобного сразу во всех областях. Каждый (из популярных) хорош в своей специфической области. А вот насчёт Хаскеля я что-то не могу представить себе эту область...
K>Смотрим какой-нибудь langpop и видим, что наблюдаемой разницы в популярности между Go и Haskell нет. Хотя, конечно, можно подобрать какую-нибудь метрику (частота встречаемости в новостной ленте любителя Го) где какая-то разница будет.
Хы, данный рейтинг вообще ни о чём, т.к. на гитхабе живёт весьма специфическая аудитория. Лучше смотреть например здесь http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html или в других подобных более менее серьёзных ресурсах. Но в любом случае, даже если бы они были в точности равны, то это всё подтверждает мою мысль — достаточно взглянуть на дату рождения Хаскеля и Го...
K>Ну а D. Mon показал конкретный пример кода, который компилятор разрешает. И никакой практически значимой разницы между примерами нет, т.е. ценность неразрешения компилятора нулевая.
А что не так с тем примером? Он позволяет функции иметь побочные эффекты? )
K>Поддерживать в языке мутабельные данные как раз просто, для этого вообще ничего не нужно. Контроль за эффектами нужен, чтоб нормально поддерживать ФП. Если это не нужно, то и контроль за эффектами, в основном, не нужен — разве что для дрессировки программиста.
Ну так никто не против контроля эффектов. Просто не надо делать это обязательным, т.к. из этого тогда следует куча проблем.
K>Нет конечно, потому что для того, чтоб было все нормально нужны средства оптимизации, которые снижают накладные расходы на использование иммутабельных структур. Убирание лишних копирований иммутабельных массивов, дефорестация, "переписывание хвостов" у списков, в том числе и быстрое потокобезопасное, копирующий сборщик, который перемещает объекты в памяти так, чтоб улучшить локальность и так далее. Без этого иммутабельные данные останутся игрушкой.
Если есть сомнения в быстродействие работы с иммутабельными данными в D, то можем сравнить на каком-нибудь тесте...
K>Ну так этот подход "вы можете работать с иммутабельными данными, но медленно и мучительно, зато вы можете с ними не работать, а работать с мутабельными" принципиально ущербный. Он к тому и сведется, что работать будут с мутабельными данными — вот и все. Смысл же поддержки чего-то в том, чтоб это можно было на практике использовать, а не для того, чтоб поставить галочку, отписаться на форуме, а использовать что-то другое.
Ничего подобного. С иммутабельными данными тоже всё нормально. Не нужны именно оптимизации, позволяющие Хаскелю работать с иммутабельными данными в стиле мутабельных — в таком случае в D используем нормальные мутабельные.
И не надо думать, что если что-то использовать необязательно, то это не будут использовать. К примеру const в C++ можно не использовать вообще. Но весь нормальный код кругом в этих const'ах и т.п.
K>Да ничего плохого, как нет ничего плохого в том, чтоб использовать в 2014-ом году калькулятор HP-35 и ездить на Ford Falcon, например.
Ага, ага... Вот теорема Пифагора тоже в общем то устарела — не учитывает искривление пространства. Но что-то большинство народа по прежнему использует именно её, а не продвинутый вариант.
K>Это точно, только вот этот код "на очень многих языках" выдает совсем другой результат. K>
>> let i = 42
>> [i | i <- [0..9]]
K>[0,1,2,3,4,5,6,7,8,9]
>> i
K>42
K>
K>или K>
>> let i = 42;;
>> [for i in {0..9} -> i];;
K>val it : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
>> i;;
K>val it : int = 42
K>
Это всего лишь вопрос области видимости. Скажем вариант на C++/Java/C# опять же покажет другое.
K>Позиция придумывающего 257-ю парадигму, чтоб украсить вики-статью про любимый язык (и таким образом показать всем у кого гм... Д'Артаньян длиннее) не просто напоминает "позицию Д'Артаньяна", а является хрестоматийным ее примером.
Хыхы, википедию пишут Д'Артаньяны? ) Типа каждому выделяется по статье и больше никто на свете не способен её править? ))) Мда, это уже шедевр форумного спора...
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не больше. Вспотеешь описывать const все возможные параметры.
Вот это аргумент...
Это уже пошло что-то из области яблофанатов, которые говорят "не нужно" на любую фичу, которой у них нет. А потом (когда она через пару лет появляется), называют её ключевой и революционной.
Представляю реакцию на появление const где-нибудь в JS или C# лет через 5. )))
I>То есть, ты сомневаешься что лямбда-счисление и подобные вещи это математика ?
Ну покажи мне ссылки и указатели в лямбда-исчисление.
I>И здесь оказывается, что у компилятора нет никаких гарантий иммутабельности, потому что это делается через ссылочную прозрачность, а её нет и быть не может.
Если мы говорим про D, то там есть все гарантии благодаря соответствующей системе типов.
I>Я утверждаю, что ты изобретаешь парадигму, только стесняешься это признать. Вместо этого трактуешь лямбда-счисление так как тебе угодно.
Я вообще ничего не изобретаю. Я не автор D и вообще пока ещё не создавал свои языки.
I>Ты путаешь статическую типизацию и ручные аннотации типов и ограничений. Первое даёт гарантии, второе в общем случае не работает.
Ну покажи пример того, как они не работают. )
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не больше. Вспотеешь описывать const все возможные параметры.
_>Вот это аргумент...
Тебе, если в кратце, придется const писать вообще везде и не дай бог ошибиться.
_>Это уже пошло что-то из области яблофанатов, которые говорят "не нужно" на любую фичу, которой у них нет. А потом (когда она через пару лет появляется), называют её ключевой и революционной.
В данном случае от неё уже давно отказались.
_>Представляю реакцию на появление const где-нибудь в JS или C# лет через 5. )))
Она на самом деле нужна, но в основном для девелопера, а не для компилятора.
I>>То есть, ты сомневаешься что лямбда-счисление и подобные вещи это математика ?
_>Ну покажи мне ссылки и указатели в лямбда-исчисление.
Покажи мне, где я утверждаю, что ссылки и указатели это лямбда-счисление
I>>И здесь оказывается, что у компилятора нет никаких гарантий иммутабельности, потому что это делается через ссылочную прозрачность, а её нет и быть не может.
_>Если мы говорим про D, то там есть все гарантии благодаря соответствующей системе типов.
Точнее — отсутствие гарантий. Твой хвалёный D даже хвостовую рекурсию толком не умеет
I>>Я утверждаю, что ты изобретаешь парадигму, только стесняешься это признать. Вместо этого трактуешь лямбда-счисление так как тебе угодно.
_>Я вообще ничего не изобретаю. Я не автор D и вообще пока ещё не создавал свои языки.
Ты изобрёл понятие чистоты, выбросив из него основную вещь, которая следует из базовых принципов лябда счисления
I>>Ты путаешь статическую типизацию и ручные аннотации типов и ограничений. Первое даёт гарантии, второе в общем случае не работает.
_>Ну покажи пример того, как они не работают. )
Пример уже был, про модификатор pure. Ты правда стесняешься это признать и строишь теории навроде "нужны объекты значения, иммутабельность это внешний факт" и тд
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Подходит. f(5) всегда будет равно 5 и так все всегда будет f(5).
I>В лямбда счислении нет никаких присваиваний, поэтому f(x) всегда и везде будет f(x), и если x равно 5, то это эквивалентно f(5) и 5, и так независимо ни от чего.
I>Это в С++ ты можешь объявить переменную и переприсвоить, поэтому f(x) != f(x), но это говорит не о том, что функция не чистая, а о том, что твой код не имеет никакого отношения к лямбда-счислению. Чистота функции это растет из лямбда счисления. Нет лямбда-счисления -> чистота не имеет никакого смысла.
Вооот, наконец то до тебя начинает доходить то, о чём я уже давно тут говорю.
Можно работать с функцией (в смысле математики, а не программирования) определённой на поле действительных чисел, а можем продолжить её в область комплексных чисел. Так же и тут. Можно иметь понятие чистой функции только для иммутабельных параметров (как в лямбда-исчисление), а можно расширить это определение, включив и мутабельные. Причём как и в случае с комплексными/действительными числами, ключевым нюансом является то, что в старой области определения должно наблюдаться полное совпадение. Т.е. чистые функции D при работе с иммутабельными данными (напоминаю, что для них в D тоже есть свой модификатор) полностью совпадают с вариантом в Хаскеле (т.е. с классическим лямбда-исчислением).
По сути определение чистых функций в D выглядит как своеобразное аналитическое продолжение определения из Хаскеля. Причём это всё выглядит очень естественно, т.к. продолжение выполнено на область по сути отсутствующую в Хаскеле и естественно полностью отсутствующую в лямбда-исчисление.
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Подходит. f(5) всегда будет равно 5 и так все всегда будет f(5).
I>>В лямбда счислении нет никаких присваиваний, поэтому f(x) всегда и везде будет f(x), и если x равно 5, то это эквивалентно f(5) и 5, и так независимо ни от чего.
I>>Это в С++ ты можешь объявить переменную и переприсвоить, поэтому f(x) != f(x), но это говорит не о том, что функция не чистая, а о том, что твой код не имеет никакого отношения к лямбда-счислению. Чистота функции это растет из лямбда счисления. Нет лямбда-счисления -> чистота не имеет никакого смысла.
_>Вооот, наконец то до тебя начинает доходить то, о чём я уже давно тут говорю.
Я это повторяю в разной форме уже второй месяц.
_>По сути определение чистых функций в D выглядит как своеобразное аналитическое продолжение определения из Хаскеля. Причём это всё выглядит очень естественно, т.к. продолжение выполнено на область по сути отсутствующую в Хаскеле и естественно полностью отсутствующую в лямбда-исчисление.
По сути чистота в D не имеет никакого отношения к чистоте в лямбда-счислении. Как только параметры становятся мутабельными, весь профит заканчивается.
И теперь совершенно не ясно, на кой ляд нужно такое вот понятие — чистота, если эффекта нет.
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Вообще говоря, если у компилятора есть полный исходный код, то ему вроде как и не нужен модификатор pure — он проанализирует тела всех функций и будет знать, какие чистые, а какие нет.
Собственно кроме оптимизации и корректности кода (про которую ниже) ещё возможно введение всяких забавных вкусностей в сам язык. Типа полноценной поддержки ленивости и т.п. К сожалению в D подобное ещё не сделано, так что это только теоретические рассуждения.
ARK>Получается, что pure нужен не только для дополнительных оптимизаций, а скорее для: ARK>1) облегчения чтения кода программистом (не надо анализировать груду кода, достаточно взглянуть на сигнатуру функции); ARK>2) облегчения модификации кода программистом (не получим — случайно — побочных эффектов там, где это не ожидается); ARK>3) создания модульных систем, когда у нас исходников соседнего модуля нет, а есть только бинарник (правда, к D это не факт, что имеет отношение).
Да, согласен, в данный момент как раз в этом основные фичи и заключаются.
ARK>Очевидно, что для пунктов 1 и 2 нужны только "по-настоящему чистые" функции, допускающие только иммутабельные аргументы. ARK>Иначе мы можем не просто потерять необязательную оптимизацию, но и случайно изменить поведение системы нежелательным образом. ARK>
ARK>int pure OuterFunc<T>(T param) where T : IMyInterface
ARK>{
ARK> param.Modify(); // можно ли вызывать? а черт его знает
ARK> var result = InnerFunc(param); // InnerFunc тоже "чистая"
ARK> ...
ARK>}
ARK>
А что здесь не так то? Если Modify не является чистой, то этот код не скомпилируется и всё.
ARK>То есть модификатор pure в D далеко не так полезен, как мог бы быть.
Это да... Там ещё много чего можно улучшать.
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Покажи мне, где я утверждаю, что ссылки и указатели это лямбда-счисление
Ок, покажи в другом разделе математики. )))
I>Точнее — отсутствие гарантий. Твой хвалёный D даже хвостовую рекурсию толком не умеет
Причём тут иммутабельность и хвостовая рекурсия? )
I>Ты изобрёл понятие чистоты, выбросив из него основную вещь, которая следует из базовых принципов лябда счисления
Я изобрёл? ))) Ты считаешь меня автором языка D? )
I>Пример уже был, про модификатор pure. Ты правда стесняешься это признать и строишь теории навроде "нужны объекты значения, иммутабельность это внешний факт" и тд
Примера нарушения гарантий не было. )
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>По сути чистота в D не имеет никакого отношения к чистоте в лямбда-счислении. Как только параметры становятся мутабельными, весь профит заканчивается.
I>И теперь совершенно не ясно, на кой ляд нужно такое вот понятие — чистота, если эффекта нет.
Не "не имеет никакого отношения", а определение из лямбда-исчисления является точным подмножеством определения из D. Т.е. по сути является его частным случаем. И соответственно для иммутабельных данных мы будем иметь в точности все законы лямбда-исчисления. А для мутабельных будет уже что-то другое, посложнее... Кстати, тут уже обсуждалось, что и там кое-какие интересные оптимизации возможны.
Ну и наконец, прочитай уже внимательно, что тут пишут (не в первый раз и не только я). Бонусы идут не только в виде некой оптимизации кода, но и в виде гарантий. Так вот, эти гарантии одинаково полезны и в случае иммутабельных параметров и в случае мутабельных. Думаю именно по этой причине авторы D решили ввести именно такое определение чистых функций.
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>По сути чистота в D не имеет никакого отношения к чистоте в лямбда-счислении. Как только параметры становятся мутабельными, весь профит заканчивается. I>>И теперь совершенно не ясно, на кой ляд нужно такое вот понятие — чистота, если эффекта нет.
_>Не "не имеет никакого отношения", а определение из лямбда-исчисления является точным подмножеством определения из D.
И смысла в этом никакого.
>Т.е. по сути является его частным случаем. И соответственно для иммутабельных данных мы будем иметь в точности все законы лямбда-исчисления. А для мутабельных будет уже что-то другое, посложнее... Кстати, тут уже обсуждалось, что и там кое-какие интересные оптимизации возможны.
Компилятор не сможет узнать по иммутабельность, так что профита не будет.
_>Ну и наконец, прочитай уже внимательно, что тут пишут (не в первый раз и не только я). Бонусы идут не только в виде некой оптимизации кода, но и в виде гарантий. Так вот, эти гарантии одинаково полезны и в случае иммутабельных параметров и в случае мутабельных. Думаю именно по этой причине авторы D решили ввести именно такое определение чистых функций.
Ты слово гарантии понимаешь как то по особому: " для иммутабельных данных мы будем иметь в точности все законы лямбда-исчисления. А для мутабельных будет уже что-то другое, посложнее..."
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Покажи мне, где я утверждаю, что ссылки и указатели это лямбда-счисление
_>Ок, покажи в другом разделе математики. )))
Уже показывали. Правда оказалось, что у тебя свой взгляд и на то, что считать математикой.
I>>Точнее — отсутствие гарантий. Твой хвалёный D даже хвостовую рекурсию толком не умеет
_>Причём тут иммутабельность и хвостовая рекурсия? )
Просто пример, чего может и чего не может компилятор. С иммутабельностью уже был пример, его достаточно.
I>>Ты изобрёл понятие чистоты, выбросив из него основную вещь, которая следует из базовых принципов лябда счисления
_>Я изобрёл? ))) Ты считаешь меня автором языка D? )
У тебя уникальное понимание функциональщины. Именно ты хочешь применять часть оптимизаций для части кода и игнорируешь любые аргументы, почему это работать не может и не работает. Именно по этой причине тебе нравится D — в нем реализован подход, с которым ты согласен. Собственно дело не в D, а твоих уникальных взглядах на любую из обсуждавшихся областей.
I>>Пример уже был, про модификатор pure. Ты правда стесняешься это признать и строишь теории навроде "нужны объекты значения, иммутабельность это внешний факт" и тд
_>Примера нарушения гарантий не было. )
Было. Ты увильнул на особый оператор сравнения, а тот факт, что оптимизация внезапно становится неприменимой ты проигнорировал.
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А что здесь не так то? Если Modify не является чистой, то этот код не скомпилируется и всё.
Да, я тут лажанул. Имелось в виду — не вызов param.Modify, а что-то типа "param.field = 23;" — так же ведь можно сделать, если T мутабельный?
Правда, в таком случае параметр уже не может быть шаблонного типа, тип явно будет мутабельным. Поэтому вопрос отпадает.
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Да, я тут лажанул. Имелось в виду — не вызов param.Modify, а что-то типа "param.field = 23;" — так же ведь можно сделать, если T мутабельный? ARK>Правда, в таком случае параметр уже не может быть шаблонного типа, тип явно будет мутабельным. Поэтому вопрос отпадает.
Проблема не в том, можно ли менять унутре, а что будет, если менять снаружи. Т.е. насколько легко можно комбинировать чистый код с сайд-эффектами.
Компилер видит, что функция pure, но самостоятельно установить, что значение иммутабельное, он не сможет. Т.е. pure это для дизайна, а не для фп.
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Проблема не в том, можно ли менять унутре, а что будет, если менять снаружи. Т.е. насколько легко можно комбинировать чистый код с сайд-эффектами. I>Компилер видит, что функция pure, но самостоятельно установить, что значение иммутабельное, он не сможет. Т.е. pure это для дизайна, а не для фп.
Прошу прощения, не понял.
Для какого значения компилер не сможет установить, что оно иммутабельное?
Можно коротенький псевдокод?
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Прошу прощения, не понял. ARK>Для какого значения компилер не сможет установить, что оно иммутабельное? ARK>Можно коротенький псевдокод?
x = f(a)
...
y = f(a)
Компилятор должен установить, как вариант, что a иммутабельное, что бы выяснить, что x эквивалентно y
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
I>Компилятор должен установить, как вариант, что a иммутабельное, что бы выяснить, что x эквивалентно y
А разве компилятору неизвестен тип "a"? Если это мутабельный тип, и если сигнатура f ожидает мутабельный аргумент, то очевидно, что в данном случае нельзя сказать, что "x эквивалентно y" (во всяком случае, не заглядывая в тело f).
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
I>>Компилятор должен установить, как вариант, что a иммутабельное, что бы выяснить, что x эквивалентно y
ARK>А разве компилятору неизвестен тип "a"? Если это мутабельный тип, и если сигнатура f ожидает мутабельный аргумент, то очевидно, что в данном случае нельзя сказать, что "x эквивалентно y" (во всяком случае, не заглядывая в тело f).
Как узнать что тип мутабельный ?
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Компилятор не сможет узнать по иммутабельность, так что профита не будет.
С чего это не сможет? А модификатор типов immutable на что?
I>Ты слово гарантии понимаешь как то по особому: " для иммутабельных данных мы будем иметь в точности все законы лямбда-исчисления. А для мутабельных будет уже что-то другое, посложнее..."
Я же вроде ясно написал, что здесь нет разницы. Она есть как раз для оптимизации (типа кэширования и т.п.). А для гарантий на отсутствие побочных эффектов не важно мутабельные параметры или нет.
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Уже показывали. Правда оказалось, что у тебя свой взгляд и на то, что считать математикой.
Ты покажи не математическое моделирование ссылок и указателей, а покажи наличие их самих в математике. )
I>Просто пример, чего может и чего не может компилятор. С иммутабельностью уже был пример, его достаточно.
Не было никаких примеров, показывающих наличие каких-либо проблем с иммутабельностью.
I>У тебя уникальное понимание функциональщины. Именно ты хочешь применять часть оптимизаций для части кода и игнорируешь любые аргументы, почему это работать не может и не работает. Именно по этой причине тебе нравится D — в нем реализован подход, с которым ты согласен. Собственно дело не в D, а твоих уникальных взглядах на любую из обсуждавшихся областей.
Хы, да просто ты пока ещё думаешь, что в мире есть только действительные числа, а я уже оперирую комплексными.
Кстати, ещё один довод в пользу мультипарадигменных языков. Ведь подобное расширение произошло именно из-за сочетания возможностей императивной и функциональной парадигмы внутри одного языках.
I>Было. Ты увильнул на особый оператор сравнения, а тот факт, что оптимизация внезапно становится неприменимой ты проигнорировал.
Чего чего? ) Я же первый везде писал, что для не иммутабельных параметров оптимизацию не применяем (точнее на самом деле тоже кое-что можно, но это уже заметно более сложных вопрос — пока для простоты считаем что ничего не возможно).
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Как узнать что тип мутабельный ?
Насколько я понимаю, тип точно иммутабелен, если он либо помечен ключевым словом immutable, либо является одним из примитивных типов, либо все члены у него — чистые функции. Если ничего из этого нет, то тип мутабелен.
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Компилятор не сможет узнать по иммутабельность, так что профита не будет.
_>С чего это не сможет? А модификатор типов immutable на что?
Это ручной контроль, неинтересно.
I>>Ты слово гарантии понимаешь как то по особому: " для иммутабельных данных мы будем иметь в точности все законы лямбда-исчисления. А для мутабельных будет уже что-то другое, посложнее..."
_>Я же вроде ясно написал, что здесь нет разницы. Она есть как раз для оптимизации (типа кэширования и т.п.). А для гарантий на отсутствие побочных эффектов не важно мутабельные параметры или нет.
Немного не понял. Ты показал разницу — для иммутабельных одно, для остальных другое. И внезапно оказывается, что разницы нет
Мы говорим про чистоту, а не гарантии отсутствия побочных эффектов. Чистота это отсутствие побочных эффектов + детерминизм. pure означает первое, а pure + параметры immutable — второе.
Re[83]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
I>>Как узнать что тип мутабельный ?
ARK>Насколько я понимаю, тип точно иммутабелен, если он либо помечен ключевым словом immutable, либо является одним из примитивных типов, либо все члены у него — чистые функции. Если ничего из этого нет, то тип мутабелен.
То есть, всё сводится к ручному контролю. А раз так, то чистая функция это не pure, а pure у которой аргументы immutable, то есть, те самые значения про которые говорит alex_public.
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Уже показывали. Правда оказалось, что у тебя свой взгляд и на то, что считать математикой.
_>Ты покажи не математическое моделирование ссылок и указателей, а покажи наличие их самих в математике. )
Тебе именно это и показали. Computer sciense и information science это математика в чистом виде. Просто тебе удобно называть это "математическое моделирование"
I>>У тебя уникальное понимание функциональщины. Именно ты хочешь применять часть оптимизаций для части кода и игнорируешь любые аргументы, почему это работать не может и не работает. Именно по этой причине тебе нравится D — в нем реализован подход, с которым ты согласен. Собственно дело не в D, а твоих уникальных взглядах на любую из обсуждавшихся областей.
_>Хы, да просто ты пока ещё думаешь, что в мире есть только действительные числа, а я уже оперирую комплексными.
Мне кажется, ты давно сам запутался в своих аналогиях. Если мы говорим про чистоту функций, то надо смотреть откуда она растет. В D она не сводится к pure, как ты хочешь доказать. D — это ручной контроль чистоты за счет pure и иммутабельных параметров.
I>>Было. Ты увильнул на особый оператор сравнения, а тот факт, что оптимизация внезапно становится неприменимой ты проигнорировал.
_>Чего чего? ) Я же первый везде писал, что для не иммутабельных параметров оптимизацию не применяем (точнее на самом деле тоже кое-что можно, но это уже заметно более сложных вопрос — пока для простоты считаем что ничего не возможно).
Нет, ты везде писал что чистота это просто отсутствие побочных эффектов и начал придумывать про объекты значения. Когда я тебе намекнул про иммутабельность, тебя всего порвало
Re[84]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А раз так, то чистая функция это не pure, а pure у которой аргументы immutable, то есть, те самые значения про которые говорит alex_public.
Да, получается так. "Реально чистая" функция должна быть объявлена не только pure, но и с иммутабельными типами параметров. Я, честно говоря, пока для себя так и не понял, почему в компиляторе нет запрета на модификацию параметров pure функций. То есть — в каком случае и что именно — такая возможность дает.
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В том то и дело, что я не знаю как должен выглядеть подобный инструмент для Хаскеля, т.к. не видел вообще ни одного реального примера.
Все еще непонятно почему для хаскеля нужны какие-то радикально иные инструменты.
_>Нет языка удобного сразу во всех областях. Каждый (из популярных) хорош в своей специфической области. А вот насчёт Хаскеля я что-то не могу представить себе эту область...
У языков программирования общего назначения не бывает никаких "специфических областей". Вот какие специфические области у C++, например?
K>>Смотрим какой-нибудь langpop
_>Хы, данный рейтинг вообще ни о чём, т.к. на гитхабе живёт весьма специфическая аудитория.
Ну так что? А на stackoverflow совсем другая специфическая аудитория, тем не менее, по графику видно что где-то после 0.1% корреляция между популярностями в таких разных и специфических аудиториях достаточно хорошая. Т.е. этот рейтинг сам себя проверяет.
_>Лучше смотреть например здесь http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
А вот tiobe как раз эталон плохого рейтинга, который то меряет гуглибельность букв английского алфавита, то не встречающихся в природе словосочетаний.
_>Но в любом случае, даже если бы они были в точности равны, то это всё подтверждает мою мысль — достаточно взглянуть на дату рождения Хаскеля и Го...
Ну давайте взглянем: Go мог бы быть таким, какой он сейчас и в 1968-м году, а хаскель хорошо если к 2028-му доделают.
(Если серьезно, то популярность хаскеля начала расти с нуля примерно тогда же, когда и популярность Го, а "дата рождения хаскеля" вообще вопрос нетривиальный)
_>А что не так с тем примером? Он позволяет функции иметь побочные эффекты? )
Да, конечно.
_>Ну так никто не против контроля эффектов.
Например вы против.
_>Просто не надо делать это обязательным,
А вот и подтверждение.
_>т.к. из этого тогда следует куча проблем.
Например? Одну ужасную проблему мы обнаружили: вместо $ приходится <$> писать. А какие еще проблемы есть?
_>Если есть сомнения в быстродействие работы с иммутабельными данными в D, то можем сравнить на каком-нибудь тесте...
Особого сомнения нет, скорее есть — наоборот — уверенность. Если для уменьшения лишних копирований иммутабельных массивов там еще можно что-то сделать (и я подозреваю, что это даже сделано), то с деревьями/списками с таким-то сборщиком мусора D вообще ничего не светит.
_>Ничего подобного. С иммутабельными данными тоже всё нормально.
Причем, как мы выяснили, под "все нормально" подразумевается, что их можно и даже нужно не использовать.
_>Не нужны именно оптимизации, позволяющие Хаскелю работать с иммутабельными данными в стиле мутабельных — в таком случае в D используем нормальные мутабельные.
Ну я про то и говорю — иммутабельные структуры объявляются ненужными — значит и оптимизации не нужны — все логично. Не понятно только, зачем нужен контроль эффектов, если нет ничего из того, для чего контроль эффектов как раз и нужен.
_>И не надо думать, что если что-то использовать необязательно, то это не будут использовать.
Если что-то использовать не нужно, но зато можно — это, конечно, будут использовать. А вот если что-то использовать по факту нельзя — то это использолвать не будут. А если ничего для поддержки иммутабельности нет — то и пользоваться ей нельзя, ну, можно пользоваться для того, чтоб показывать какая это бесполезная вещь.
_>К примеру const в C++ можно не использовать вообще. Но весь нормальный код кругом в этих const'ах и т.п.
K>>Да ничего плохого, как нет ничего плохого в том, чтоб использовать в 2014-ом году калькулятор HP-35 и ездить на Ford Falcon, например. _>Ага, ага... Вот теорема Пифагора тоже в общем то устарела — не учитывает искривление пространства. Но что-то большинство народа по прежнему использует именно её, а не продвинутый вариант.
Это потому, что теорема Пифагора вовсе не устарела. А вот HP-35 — наоборот — устарел.
_>Это всего лишь вопрос области видимости.
Всего лишь!
_>Скажем вариант на C++/Java/C# опять же покажет другое.
Нет, штатные sequence comprehension из C# сделают как раз то, что делает код на haskell и F# выше. И что собственно и ожидает увидеть человек знакомый с языками, в которых вопрос области видимости уже не стоит (таких языков большинство). В плюсах и яве такой фичи нет, там все зависит от того, что считать аналогичным кодом, но в целом там с областями видимости все в порядке, это не питон.
В питоне такие милые детали, кстати, еще и от версии зависят.
_>Хыхы, википедию пишут Д'Артаньяны? ) Типа каждому выделяется по статье и больше никто на свете не способен её править? )))
Как и кто пишут википедию (конкретную ее часть) я уже объяснил выше. Не говоря уже о том, что не каждый может править все что угодно в вики, то что там будет написано большую часть времени будет результатом правки человеков, которым больше всего не все равно. А даже в этой теме можно наблюдать, как неравнодушный человек может про любой X на голубом глазу утверждать одновременно, что X есть, X не нужно и что отсутствие X равно наличию X.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это ручной контроль, неинтересно.
А как ты ещё хочешь, если в языке есть и мутабельные и иммутабельные данные? И кстати чёткое разделение по типу как раз отлично работает. Оно даже проще чем const, т.к. это именно отдельный тип и соответственно компилятор всегда укажет, если его где-то забыть.
I>Немного не понял. Ты показал разницу — для иммутабельных одно, для остальных другое. И внезапно оказывается, что разницы нет
I>Мы говорим про чистоту, а не гарантии отсутствия побочных эффектов. Чистота это отсутствие побочных эффектов + детерминизм. pure означает первое, а pure + параметры immutable — второе.
Бррр, устал повторять по 10 раз одно и тоже — раньше ты вроде не был таким непонятливым. Повторюсь последний раз.
Понятие чистоты как в языке D (модификатор pure) даёт бонусы в нескольких областях:
1. В области оптимизации (вызова функции):
— для вызовов с иммутабельными параметрами (т.е. имеющими тип immutable T) — полный аналог классического лямбда-исчисления со всеми вытекающими последствиями (кэширование, ленивость и т.п.)
— для вызовов с мутабельными параметрами — теоретически тоже возможны определённые оптимизации (например для локальных переменных без ссылок компилятор вполне способен чётко отслеживать их области изменения и соответственно внутри них возможно проведение аналогичных оптимизаций), но это уже всё гораздо сложнее, менее формализовано и не факт что где-то реализовано.
2. В области дизайна. Позволяет давать гарантии на отсутствие побочных эффектов у функции (т.е. польза как скажем от const, только на другом уровне абстракции). Данная возможность не зависит от того мутабельные параметры передаются функции или иммутабельные.
Re[82]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А как ты ещё хочешь, если в языке есть и мутабельные и иммутабельные данные? И кстати чёткое разделение по типу как раз отлично работает. Оно даже проще чем const, т.к. это именно отдельный тип и соответственно компилятор всегда укажет, если его где-то забыть.
Ручной контроль эффектов это неинтересно. Мулька навроде checked exceptions — в одном месте поменял, повлияло на все возможные случаи вызова. То есть, надо вдруг думать, "кака унутре неонка", то есть, очевидное нарушение инкапсуляции на ровном месте.
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Тебе именно это и показали. Computer sciense и information science это математика в чистом виде. Просто тебе удобно называть это "математическое моделирование"
Это математика описывающая компьютерные процессы. А я говорю о наличие чего-то типа указателей в самой математике. Но не думаю, что ты сумеешь найти что-то подобное. Соответственно поэтому классическое лямбда-исчисление является ограниченной вещью и требует адаптации и расширения при переносе в практическое программирование. А то, что в Хаскеле этого не сделали и взяли именно голый математический вариант, в итоге сильно ограничило сам язык — теперь в нём с трудом делаются самые обычные для классического программирования вещи.
I>Мне кажется, ты давно сам запутался в своих аналогиях. Если мы говорим про чистоту функций, то надо смотреть откуда она растет. В D она не сводится к pure, как ты хочешь доказать. D — это ручной контроль чистоты за счет pure и иммутабельных параметров.
Что значит ручной? То, что надо указывать у функций этот модификатор и т.п? ) Безусловно. А иначе не получится выделить этот вид функций. Иначе придётся считаться все функции не чистыми (как в C++) или все чистыми (как в Хаскеле). Конечно же был бы совсем приятен некий третий вариант, в котором компилятор сам мог определять вид функции и т.п. без всяких модификаторов, но боюсь такое уже далеко за пределами современных возможностей и уже восходит к проблеме остановки, про которую тут говорил gandjustas.
Re[85]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
ARK>Да, получается так. "Реально чистая" функция должна быть объявлена не только pure, но и с иммутабельными типами параметров. Я, честно говоря, пока для себя так и не понял, почему в компиляторе нет запрета на модификацию параметров pure функций. То есть — в каком случае и что именно — такая возможность дает.
Так обсуждали же это уже. Возможность давать гарантии на отсутствие побочных эффектов не зависит от типа параметров. И кстати я подозреваю что именно подобная задача была основной причиной для введения этой фичи в язык, а не возможности дополнительной оптимизации кода.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Было бы по твоему, то без малого все бы умели программировать хоть чуть-чуть. EP>>Тем не менее, непосредственно программирование тоже встречается в повседневной жизни — разве трудно составить рецепт, или например описание маршрута? I>И где здесь вычислитель навроде машины тьюринга или регистровой машины ?
Сам человек — ему дают команды, условные переходы, а он их выполняет. Точно также он может составить "программу" для другого человека: "едь пока не увидишь памятник и дерево, после 20:00 можно прямо, иначе сверни направо — в объезд".
I>>>Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи. EP>>Ему не нужна модель вычислителя — у него вычислитель уже есть в голове. I>Машина тьюринга или регистровая машина ? Жжош !
Тьюринг-полный вычислитель как минимум.
EP>>Итеративную версию чисел Фибоначчи можно элементарно объяснить ребёнку даже если он не умеет складывать числа — с помощью линейки и циркуля. I>Для ребенка в этом возрасте это будут просто линии и квадраты, а не фибоначчи.
Алгоритм ребёнок выполнит, даже может запомнит, количество отрезков посчитает и скажет результат. Что ещё нужно?
EP>>Попробуй объяснить вот этот "идиоматичный ФП" код ребёнку: EP>>
Или даже не ребёнку, а своему коллеге, который с ФП не сталкивался. I>В этом примере ты предлагаешь объяснять оптимизации хаскеля и хвостовую рекурсию, то есть, конкретный вариант а не фибоначчи. То есть, проблема в том что явно привязался к вычислителю
Я предлагаю объяснить то, что в этом топике называют "идиоматичным ФП".
I>Нужно объяснять вот такой или классический рекурсивный I>
I>Теперь скажи, что здесь будет непонятно школьнику 10 класса который никогда не пробовал программировать ?
Всё будет понятно, но:
1. Для ручного вычисления этого выражения он будет применять те же итеративные алгоритмы, которым он научился в первых классах.
2. Используется относительно современная символьная нотация, хотя первоначально/исторически выражения записывались в словесной, то есть императивной форме, вплоть до XV века — потому что она естественней и легче для понимания.
3. Как сказали выше, идиоматичный ФП это комбинирование комбинаторов — ничего этого в этом выражении нет.
Re[82]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Тебе именно это и показали. Computer sciense и information science это математика в чистом виде. Просто тебе удобно называть это "математическое моделирование"
_>Это математика описывающая компьютерные процессы.
Да, вот так новость !
>А я говорю о наличие чего-то типа указателей в самой математике.
"Computer sciense и information science" @
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Итеративную версию чисел Фибоначчи можно элементарно объяснить ребёнку даже если он не умеет складывать числа — с помощью линейки и циркуля. I>>Для ребенка в этом возрасте это будут просто линии и квадраты, а не фибоначчи.
EP>Алгоритм ребёнок выполнит, даже может запомнит, количество отрезков посчитает и скажет результат. Что ещё нужно?
Не сможет выполнить, например потому, что считает он еле-еле, раз числа складывать не умеет, а отрезки может считать как ему нравится, и циркулем-линейкой скорее будет играться и рисовать свои кружочки-линии.
I>>В этом примере ты предлагаешь объяснять оптимизации хаскеля и хвостовую рекурсию, то есть, конкретный вариант а не фибоначчи. То есть, проблема в том что явно привязался к вычислителю
EP>Я предлагаю объяснить то, что в этом топике называют "идиоматичным ФП".
Ты думаешь идиоматичное императивное программирование или ОО будет легче ?
I>>Теперь скажи, что здесь будет непонятно школьнику 10 класса который никогда не пробовал программировать ?
EP>Всё будет понятно, но: EP>1. Для ручного вычисления этого выражения он будет применять те же итеративные алгоритмы, которым он научился в первых классах.
Нет в первых классах никаких итеративных алгоритмов.
EP>2. Используется относительно современная символьная нотация, хотя первоначально/исторически выражения записывались в словесной, то есть императивной форме, вплоть до XV века — потому что она естественней и легче для понимания.
Императивный != словесный
EP>3. Как сказали выше, идиоматичный ФП это комбинирование комбинаторов — ничего этого в этом выражении нет.
А его и не надо объяснять школьнику. Школьники почти до конца школы не понимают или плохо понимают даже идиомы родного языка, не говоря про язык программирования.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>Итеративную версию чисел Фибоначчи можно элементарно объяснить ребёнку даже если он не умеет складывать числа — с помощью линейки и циркуля. I>>>Для ребенка в этом возрасте это будут просто линии и квадраты, а не фибоначчи. EP>>Алгоритм ребёнок выполнит, даже может запомнит, количество отрезков посчитает и скажет результат. Что ещё нужно? I>Не сможет выполнить, например потому, что считает он еле-еле, раз числа складывать не умеет, I>а отрезки может считать как ему нравится, и циркулем-линейкой скорее будет играться и рисовать свои кружочки-линии.
Не проблема, даже считать не обязательно. Главное сделать циркулем несколько шагов и ткнуть пальцем в клетку с готовым числом — алгоритм выполнен. Что может быть проще?
I>>>В этом примере ты предлагаешь объяснять оптимизации хаскеля и хвостовую рекурсию, то есть, конкретный вариант а не фибоначчи. То есть, проблема в том что явно привязался к вычислителю EP>>Я предлагаю объяснить то, что в этом топике называют "идиоматичным ФП". I>Ты думаешь идиоматичное императивное программирование или ОО будет легче ?
Идиоматичное ИП на порядок легче объяснить.
EP>>1. Для ручного вычисления этого выражения он будет применять те же итеративные алгоритмы, которым он научился в первых классах. I>Нет в первых классах никаких итеративных алгоритмов.
Сложение, вычитание, умножение, деление
EP>>2. Используется относительно современная символьная нотация, хотя первоначально/исторически выражения записывались в словесной, то есть императивной форме, вплоть до XV века — потому что она естественней и легче для понимания. I>Императивный != словесный
"Три пучка хорошей зелени, прибавить два пучка средней зелени, прибавить один пучок плохой зелени" — вот так описывались полиномы в математических книгах до нашей эры.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Не проблема, даже считать не обязательно. Главное сделать циркулем несколько шагов и ткнуть пальцем в клетку с готовым числом — алгоритм выполнен. Что может быть проще?
Нужно осмысление. Как это в твою идею вписать — не ясно.
EP>>>Я предлагаю объяснить то, что в этом топике называют "идиоматичным ФП". I>>Ты думаешь идиоматичное императивное программирование или ОО будет легче ?
EP>Идиоматичное ИП на порядок легче объяснить.
Ну не знаю, многие неплохо решают задачи по математике, а вот простецкий алгоритм на ассемблере не могут осилить за целых два семестра И собтсвенно не надо тому удивляться. Гораздо интереснее, как ты собираешься одни идиомы сопоставить с другим и сравнить. "монады в сто раз сложнее сортировки"
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Не проблема, даже считать не обязательно. Главное сделать циркулем несколько шагов и ткнуть пальцем в клетку с готовым числом — алгоритм выполнен. Что может быть проще? I>Нужно осмысление. Как это в твою идею вписать — не ясно.
Осмысление чего и зачем?
EP>>Идиоматичное ИП на порядок легче объяснить. I>Ну не знаю, многие неплохо решают задачи по математике, а вот простецкий алгоритм на ассемблере не могут осилить за целых два семестра И собтсвенно не надо тому удивляться.
Это элементарное отсутствие желания/мотивации.
I>Гораздо интереснее, как ты собираешься одни идиомы сопоставить с другим и сравнить. "монады в сто раз сложнее сортировки"
Просто посмотреть на идиоматичное решение одной и той же задачи, например генерацию чисел Фибоначчи итерационным методом vs функциональное комбинирование комбинаторов.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Все еще непонятно почему для хаскеля нужны какие-то радикально иные инструменты.
Видимо потому, что существующие заточены под императивный стиль или ООП, а не под чистое ФП, о чём фанаты последнего и говорят в приведённых мною ссылках.
K>У языков программирования общего назначения не бывает никаких "специфических областей". Вот какие специфические области у C++, например?
Ага, ага) Ассемблер и Питон ну совсем не имеют специфических областей и применяются абсолютно везде.)
K>Ну так что? А на stackoverflow совсем другая специфическая аудитория, тем не менее, по графику видно что где-то после 0.1% корреляция между популярностями в таких разных и специфических аудиториях достаточно хорошая. Т.е. этот рейтинг сам себя проверяет.
Это типа юмор такой? )))
Смотрим например C#: SO — 624 930, GH — 1 873 009 420.
И к примеру C: SO — 135 602, GH — 5 975 490 485.
Явно полностью противоречащие друг другу тенденции.
Более того, эти товарищи похоже ещё и вообще считать не умеют. Т.к. они там заявляют, что считают общий рейтинг (который в процентах) как среднее от результатов на SO и GH. Но по факту там явно считается просто процент от SO, т.к. скажем тот же JS имеет чуть меньший процент чем C#, но при этом имеет в 13 раз больше строк на GH и чуть меньшее количество (чем C#) тем на SO.
Т.е. всё это — полная неадекватность, очевидная каждому вменяемому человеку даже после самого поверхностного взгляда. По сути их рейтинг — это чистый рейтинг SO, а рейтинг SO=популярность_языка*проблемность_языка. Т.е. даже реально самый популярный язык, будет в далеко не во главе рейтинга, если он при этом ещё и простой. Ну в общем то мне понятно почему фанаты Хаскеля любят данный неадекватный рейтинг...
K>А вот tiobe как раз эталон плохого рейтинга, который то меряет гуглибельность букв английского алфавита, то не встречающихся в природе словосочетаний.
Угу, tiobe далеко не идеален. Только вот ничего лучше мне пока никто не показывал...
K>Ну давайте взглянем: Go мог бы быть таким, какой он сейчас и в 1968-м году, а хаскель хорошо если к 2028-му доделают.
K>(Если серьезно, то популярность хаскеля начала расти с нуля примерно тогда же, когда и популярность Го, а "дата рождения хаскеля" вообще вопрос нетривиальный)
Какие дохленькие отмазки. )
_>>А что не так с тем примером? Он позволяет функции иметь побочные эффекты? ) K>Да, конечно.
Каким образом? Продемонстрируйте... )
K>Особого сомнения нет, скорее есть — наоборот — уверенность. Если для уменьшения лишних копирований иммутабельных массивов там еще можно что-то сделать (и я подозреваю, что это даже сделано), то с деревьями/списками с таким-то сборщиком мусора D вообще ничего не светит.
Ну так давайте замерим, в чём проблема?
K>Причем, как мы выяснили, под "все нормально" подразумевается, что их можно и даже нужно не использовать.
Да, их можно и нужно не использовать там, где по условию задачи данные реально мутабельные.
K>Ну я про то и говорю — иммутабельные структуры объявляются ненужными — значит и оптимизации не нужны — все логично. Не понятно только, зачем нужен контроль эффектов, если нет ничего из того, для чего контроль эффектов как раз и нужен.
Почему не нужными то? ) Если мы взглянем скажем на какой-нибудь нормальный C++ код, то увидим, что даже при написание в чисто императивном стиле там кругом стоят const, хотя никто этого не требует силой. Т.е. использование чего-то типа иммутабельных данных (всё же const в C++ это не 100% гарантия, в отличие от immutable в D) является стандартной практикой во многих императивных языках.
K>Если что-то использовать не нужно, но зато можно — это, конечно, будут использовать. А вот если что-то использовать по факту нельзя — то это использолвать не будут. А если ничего для поддержки иммутабельности нет — то и пользоваться ей нельзя, ну, можно пользоваться для того, чтоб показывать какая это бесполезная вещь.
Ну вот в C++ и D различные виды иммутабельные данных используются повсеместно.
K>Как и кто пишут википедию (конкретную ее часть) я уже объяснил выше. Не говоря уже о том, что не каждый может править все что угодно в вики, то что там будет написано большую часть времени будет результатом правки человеков, которым больше всего не все равно. А даже в этой теме можно наблюдать, как неравнодушный человек может про любой X на голубом глазу утверждать одновременно, что X есть, X не нужно и что отсутствие X равно наличию X.
Ну да, ну да, какая жалось что те, немногие избранные, которые посвящены в истину, являются лишь пассивными наблюдателями. А человечество в итоге ведут вперёд активные невежды. Знаем такую точку зрения... )))
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Нужно осмысление. Как это в твою идею вписать — не ясно.
EP>Осмысление чего и зачем?
вычисления последовательности Фибоначчи. Затем, что бы знание можно было применить повторно, тем самым ребенком которому ты собираешься чего то объяснять.
EP>>>Идиоматичное ИП на порядок легче объяснить. I>>Ну не знаю, многие неплохо решают задачи по математике, а вот простецкий алгоритм на ассемблере не могут осилить за целых два семестра И собтсвенно не надо тому удивляться.
EP>Это элементарное отсутствие желания/мотивации.
Ога, а мотивация это такой орган, навроде желудка — наполнил его и сразу прёт желание чтото делать, неважно в какой области.
В первую очередь это особенности мышления, у одних мышление более абстрактно, у других более конкретно. Отсюда растет и нежелание долбить неудобный предмет. У одних это будет математика, у других это будет ассемблер, микроконтролеры и прочие вещи.
Скажем, люди которые занимаются в основном математикой, программированием вообще зачастую не интересуются.
EP>Просто посмотреть на идиоматичное решение одной и той же задачи, например генерацию чисел Фибоначчи итерационным методом vs функциональное комбинирование комбинаторов.
Не ясно, почему ты выбрал комбинаторы, по какому принципу ? Почему не монады, не реактивный код, не асинхронщина, а именно комбинаторы ? И почему надо сравнивать с простым итерационным методом, а не брать модный MVC-фремворк с серверным бакэндом ?
По моему нужно сравнивать в одинаковых условиях — взять простейшее решение в обоих подходах и сравнить. Проверяем понимание не по умению рисовать круги циркулем, а по умению применить полученое знание.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>У языков программирования общего назначения не бывает никаких "специфических областей". Вот какие специфические области у C++, например?
_>Ага, ага) Ассемблер и Питон ну совсем не имеют специфических областей и применяются абсолютно везде.)
Ассемблер это не язык общего назначения, а Питон применяется везде.
_>Угу, tiobe далеко не идеален. Только вот ничего лучше мне пока никто не показывал...
JS знает почти каждый первый, а Tiobe показывает его неизвестно где внизу, хотя он должен быть на первых строчках
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Все еще непонятно почему для хаскеля нужны какие-то радикально иные инструменты. _>Видимо потому, что существующие заточены под императивный стиль или ООП, а не под чистое ФП,
Ну, можно сказать, что sequence diagram под императивный стиль заточена (причем для них применения найти как раз можно — для описания взаимодействия легких потоков, например, которые в ФЯ достаточно популярный инструмент). Но остальные-то? По поводу заточенности на ООП, на той же диаграмме классов отношения это: ассоциация, композиция, агрегация, обобщение, имплементация и зависимость. Тут под ООП-специфику разве что "имплементацию" можно попробовать подтянуть, да и то соответствующие отношения и в тайпклассах хаскеля и параметрических модулях ML-ей есть.
_> о чём фанаты последнего и говорят в приведённых мною ссылках.
Они там пишут, в основном, что в принципе не любители таких диаграмм. Я и сам не любитель, вот я и интересуюсь — в чем же должно быть отличие? Вы сами говорите, что не знаете, но при этом почему-то уверены, что оно должно быть.
_> Ассемблер и Питон ну совсем не имеют специфических областей и применяются абсолютно везде.)
Ассемблеры — это не языки программирования, да и Питон не язык общего назначения, а скрипт. Но даже для него проще перечислить ниши где его применять из-за особенностей реализации нельзя, чем те, где в принципе можно. В случае настоящих языков общего назначения — тем более.
_>Смотрим например C#: SO — 624 930, GH — 1 873 009 420. _>И к примеру C: SO — 135 602, GH — 5 975 490 485. _>Явно полностью противоречащие друг другу тенденции.
С чего бы это? Там разница между языками по этим показателям в десятичные порядки. И на графике хорошо видна как корреляция между результатами гитхаба/СО так и раздел между мейнстримом и экзотикой (раздел между более-менее ходовой экзотикой и совсем не встречающейся провести уже сложнее), ну так нам большего и не надо.
_>Т.е. всё это — полная неадекватность, очевидная каждому вменяемому человеку даже после самого поверхностного взгляда.
Никакой "очевидной неадекватности" там точно нет.
_>По сути их рейтинг — это чистый рейтинг SO, а рейтинг SO=популярность_языка*проблемность_языка.
А рейтинг на гитхабе это популярность_языка*многословность_языка.
_>Т.е. даже реально самый популярный язык, будет в далеко не во главе рейтинга, если он при этом ещё и простой.
Ну так если вам не нравится какой-то из рейтингов либо их агрегат — вы можете посмотреть на график, который хорошо позволяет популярность оценить.
_> Ну в общем то мне понятно почему фанаты Хаскеля любят данный неадекватный рейтинг...
Сильно в этом сомневаюсь. Особенно, если учесть, что фанаты хаскеля достаточно массово страдают гитофобией.
Но тут намек, видимо, на то, что в этом рейтинге у хаскеля незаслуженно (по вашему мнению) высокая популярность. Это только предположение, конечно. Потому, что сделать такой вывод можно только в том случае, если не заметить, что шкалы на осях графика логарифмические. Т.е. рейтинг показывает, что популярность хаскеля ниже плинтуса, что хорошо согласуется с интуитивными ожиданиями.
_>Угу, tiobe далеко не идеален.
Это показанный мной рейтинг не идеален, а tiobe — полностью непригоден. Недавно заглянул туда и обнаружил, что F# у них внезапно прыгнул с 60-какого-то места чуть ли не в десятку. Чудеса адекватности, короче говоря. Я помню, там как-то раз, несколько лет назад, популярность D подскакивала из за индексации его багтрекера.
Впрочем, выбор рейтинга ничего не решает, значимой разницы в популярности между го и хаскелем и на tiobe нет.
_>Только вот ничего лучше мне пока никто не показывал...
Да вот я буквально вчера показал.
K>>(Если серьезно, то популярность хаскеля начала расти с нуля примерно тогда же, когда и популярность Го, а "дата рождения хаскеля" вообще вопрос нетривиальный) _>Какие дохленькие отмазки. )
Это констатация факта. Идея о том, что можно оказывается использовать хаскель для написания программ, а не статей — совсем новая. (кстати, tex-исходник статьи со вставками кода на хаскеле — это компилирующаяся программа на хаскеле, что символизирует)
_>Каким образом? Продемонстрируйте... )
Так тот пример это уже демонстрирует.
_>Ну так давайте замерим
Ну давайте. Допустим, нужно оценить производительность нескольких ходовых персистентных структур данных: списка (от хаскеля Data.List), иммутабельного массива (Data.Vector), бинарного дерева (Data.Map), finger tree (Data.Sequence), patricia tree (Data.IntMap), HAMT (Data.HashMap). Делать это лучше для x86 и x64, с дефолтными и подобранными настройками сборщика.
_> в чём проблема?
На данном этапе проблема уже очевидна. Во-первых, подозреваю, что имплементаций ряда структур для D просто нет (писать тормозные нет смысла, а быстрые на D не напишешь). Во-вторых, тут потребуется слишком много труда. Конечно, существуют готовые бенчмарки для всего этого, но они ведь для хаскеля и D будут разными, т.е. понадобится какое-то согласование. К тому же, эти готовые бенчмарки в основном однопоточные, что в наше суровое время уже не особенно интересно.
_>Да, их можно и нужно не использовать там, где по условию задачи данные реально мутабельные.
"данные реально мутабельные" — это на условия задач совсем не похоже.
_>Почему не нужными то?
Я же говорю, некоторую пользу всегда можно найти, проблема в том, что это малое подмножество той пользы, которую можно получить.
_>Ну вот в C++ и D различные виды иммутабельные данных используются повсеместно.
Это если называть константные ссылки иммутабельностью (непонятно, почему плюсисты так делают, впрочем они мастера придумывать специфические значения для общеупотребительных терминов). Более реальный пример массового использования иммутабельности — это строки в C#/Java.
_>Ну да, ну да, какая жалось что те, немногие избранные, которые посвящены в истину, являются лишь пассивными наблюдателями. А человечество в итоге ведут вперёд активные невежды. Знаем такую точку зрения... )))
Да нет, наоборот. Многие знают такие парадигмы как императивное/декларативное программирование. Еще больше людей знают более детальную классификацию ООП/ФП/ЛП. А вот остальные 253 парадигмы — это как раз удел "немногих избранных", "посвященных" в разработанную в узком кругу "истину", у которых много свободного времени для ведения войн правок в википедии.
Не хочу показаться "невеждой", но предлагаю не страдать ерундой и ограничиться тремя парадигмами, а поддержку оценивать на более-менее реальных примерах, а не по евангилистским фантазиям.
Кстати, вы, похоже, поскипали просьбу продемонстрировать страшные проблемы, про которые упоминали в прошлом посте. (Впрочем, это уже не первый раз происходит, так что я не удивлен).
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну, можно сказать, что sequence diagram под императивный стиль заточена (причем для них применения найти как раз можно — для описания взаимодействия легких потоков, например, которые в ФЯ достаточно популярный инструмент). Но остальные-то? По поводу заточенности на ООП, на той же диаграмме классов отношения это: ассоциация, композиция, агрегация, обобщение, имплементация и зависимость. Тут под ООП-специфику разве что "имплементацию" можно попробовать подтянуть, да и то соответствующие отношения и в тайпклассах хаскеля и параметрических модулях ML-ей есть.
Угу с последовательностью плохо. Но и чуть ли не самая классическая в программирование диаграммка (деятельности) тоже не особо ложится (если конечно не ограничиваться кодом внутри одной монады). Натягивание же диаграмм классов/объектов на Хаскель вообще забавно — они имеет смысл не отображения набора типов, а представления всего приложения или его части (я на функции намекаю, не говоря уже о нюансах инкапсуляции). Что остаётся то в итоге из реально используемых? Только диаграммки пакетов/компонентов — вот их действительно можно использоваться в ФП. Но это очень бедненький инструмент выходит...
K>Они там пишут, в основном, что в принципе не любители таких диаграмм. Я и сам не любитель, вот я и интересуюсь — в чем же должно быть отличие? Вы сами говорите, что не знаете, но при этом почему-то уверены, что оно должно быть.
Я говорю, что не знаю чем заменить uml для чистого ФП. А почему большая часть uml не подходит для чистого ФП я прекрасно вижу.
K>Ассемблеры — это не языки программирования, да и Питон не язык общего назначения, а скрипт. Но даже для него проще перечислить ниши где его применять из-за особенностей реализации нельзя, чем те, где в принципе можно. В случае настоящих языков общего назначения — тем более.
Оу) Если ассемблер и питон — это не языки общего назначения, то какое тогда вы дадите определение (очередное оригинальное видимо) для самого этого понятия? )
K>С чего бы это? Там разница между языками по этим показателям в десятичные порядки. И на графике хорошо видна как корреляция между результатами гитхаба/СО так и раздел между мейнстримом и экзотикой (раздел между более-менее ходовой экзотикой и совсем не встречающейся провести уже сложнее), ну так нам большего и не надо.
Совсем уже не видим очевидного в приступе спора? ) Если у нас один язык (причём смотрим на мейнстрим) имеет на SO в 5 раз больший результат чем другой, а на GH в 5 раз меньше того же другого, то о какой "корреляции" и "самопроверки" данных можно вообще говорить?
K>А рейтинг на гитхабе это популярность_языка*многословность_языка.
Вот вот, а ещё есть стили оформления и т.п., так что и этот параметр весьма сомнителен. Однако в данном случае они похоже всё равно его вообще не используют в своём рейтинге.
K>Сильно в этом сомневаюсь. Особенно, если учесть, что фанаты хаскеля достаточно массово страдают гитофобией. K>Но тут намек, видимо, на то, что в этом рейтинге у хаскеля незаслуженно (по вашему мнению) высокая популярность. Это только предположение, конечно. Потому, что сделать такой вывод можно только в том случае, если не заметить, что шкалы на осях графика логарифмические. Т.е. рейтинг показывает, что популярность хаскеля ниже плинтуса, что хорошо согласуется с интуитивными ожиданиями.
Причём тут вообще оси графика? Их рейтинг отображается на графике при наведение мышки на язык в процентах. И плюс в соответствие с данным рейтингом отсортированы языки в списке справа (от большего к меньшему). И похоже, что отображают эти проценты исключительно данные SO, хотя по их же описанию рейтинга внизу страницы, там должно быть SO и GH вместе. Ну и соответственно, т.к. Хаскель является у нас одним из самых вызывающих вопросы языков, то его рейтинг по данной системе будет иметь некое приличное значение.
K>Это показанный мной рейтинг не идеален, а tiobe — полностью непригоден. Недавно заглянул туда и обнаружил, что F# у них внезапно прыгнул с 60-какого-то места чуть ли не в десятку. Чудеса адекватности, короче говоря. Я помню, там как-то раз, несколько лет назад, популярность D подскакивала из за индексации его багтрекера.
Интенсивные прыжки для языков с рейтингом меньше 1% — это абсолютно нормально. )))
K>Впрочем, выбор рейтинга ничего не решает, значимой разницы в популярности между го и хаскелем и на tiobe нет.
На tiobe нет и это похоже на правду, а вот в том сомнительном месте Хаскель даже опережает в 3 раз Го. ))) Хотя на гитхабе кода на Го больше, чем на Хаскеле. И это при с учётом разницы в дате рождения...
K>Так тот пример это уже демонстрирует.
Тот пример ничего такого не демонстрирует — функция целиком зависит от передаваемых ей параметров и не меняет никаких глобальных/статических данных.
K>Ну давайте. Допустим, нужно оценить производительность нескольких ходовых персистентных структур данных: списка (от хаскеля Data.List), иммутабельного массива (Data.Vector), бинарного дерева (Data.Map), finger tree (Data.Sequence), patricia tree (Data.IntMap), HAMT (Data.HashMap). Делать это лучше для x86 и x64, с дефолтными и подобранными настройками сборщика.
Это общие слова. Нужна конкретная задачка, решение которой можно записать в одну страничку кода (большее лень для форумного спора).
K>На данном этапе проблема уже очевидна. Во-первых, подозреваю, что имплементаций ряда структур для D просто нет (писать тормозные нет смысла, а быстрые на D не напишешь). Во-вторых, тут потребуется слишком много труда. Конечно, существуют готовые бенчмарки для всего этого, но они ведь для хаскеля и D будут разными, т.е. понадобится какое-то согласование. К тому же, эти готовые бенчмарки в основном однопоточные, что в наше суровое время уже не особенно интересно.
А не надо претендовать на проведение полноценного исследования, с написанием статьи после этого — можно просто померить некоторые задачки в рамках форумного спора. А то кругом одни отмазки...
K>"данные реально мутабельные" — это на условия задач совсем не похоже.
Похоже, похоже. Вот тот мой пример с обработкой видео в реальном времени — это прямо оно и есть.
K>Это если называть константные ссылки иммутабельностью (непонятно, почему плюсисты так делают, впрочем они мастера придумывать специфические значения для общеупотребительных терминов). Более реальный пример массового использования иммутабельности — это строки в C#/Java.
и?
K>Кстати, вы, похоже, поскипали просьбу продемонстрировать страшные проблемы, про которые упоминали в прошлом посте. (Впрочем, это уже не первый раз происходит, так что я не удивлен).
На этот вопрос уже были ответы в данной теме, причём не один раз и на разных примерах. Не вижу смысла повторяться.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Кстати, вы, похоже, поскипали просьбу продемонстрировать страшные проблемы, про которые упоминали в прошлом посте. (Впрочем, это уже не первый раз происходит, так что я не удивлен).
_>На этот вопрос уже были ответы в данной теме, причём не один раз и на разных примерах. Не вижу смысла повторяться.
Не было демонстрации, ты привел или специально переусложненный код, или просто код с другим синтаксисом, не таким как в С++
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Угу с последовательностью плохо.
Да нет, я же говорю — нормально: "для описания взаимодействия легких потоков, например, которые в ФЯ достаточно популярный инструмент"
_>Но и чуть ли не самая классическая в программирование диаграммка (деятельности) тоже не особо ложится
Речь про activity diagram? Ну, она представляет control-flow, которым в декларативном программировании действительно можно не заморачиваться.
_>(если конечно не ограничиваться кодом внутри одной монады).
Что бы это значило?
_>Натягивание же диаграмм классов/объектов на Хаскель вообще забавно —
В чем "натягивание"-то заключается?
_>они имеет смысл не отображения набора типов, а представления всего приложения или его части (я на функции намекаю, не говоря уже о нюансах инкапсуляции).
Ничего не понял.
_>А почему большая часть uml не подходит для чистого ФП я прекрасно вижу.
Я понял, это виденье, как и виденье страшных проблем "монадного кода" вы оставите при себе, никто с ним так и не сможет ознакомится.
_>Оу) Если ассемблер и питон — это не языки общего назначения, то какое тогда вы дадите определение (очередное оригинальное видимо) для самого этого понятия? )
"Оригинальными" определениями я не пользуюсь. Тут определение вполне общепризнанное: язык, хорошо подходящий для решения широкого круга задач. Питон — это все-таки glue language, хотя серьезные претензии на общее назначение имеются.
Тут интереснее, что вы недавно отрицали существование языков общего назначения как класса: "Нет языка удобного сразу во всех областях. Каждый (из популярных) хорош в своей специфической области.", а теперь удивляетесь, что что-то языком общего назначения не посчитали. Как-то непоследовательно.
_>Совсем уже не видим очевидного в приступе спора? ) Если у нас один язык (причём смотрим на мейнстрим) имеет на SO в 5 раз больший результат чем другой, а на GH в 5 раз меньше того же другого, то о какой "корреляции" и "самопроверки" данных можно вообще говорить?
Напоминаю, что lg 5 ~ 0.7 крайне впечатляющая разница, что тут скажешь.
_>Причём тут вообще оси графика? Их рейтинг отображается на графике при наведение мышки на язык в процентах. И плюс в соответствие с данным рейтингом отсортированы языки в списке справа (от большего к меньшему). И похоже, что отображают эти проценты исключительно данные SO, хотя по их же описанию рейтинга внизу страницы, там должно быть SO и GH вместе.
При том. Смотрите на график и мысленно рисуете линию тренда (в оригинальном анализе популярности, на базе которого рейтинг и разработан, ничего воображать не нужно было — там линия была) и двигаетесь вдоль нее. Популярные языки будут в верхней правой части графика, а непопулярные — в левой нижней. Удаление от этой линии позволяет прикинуть точность оценки популярности (предсказуемо, что для совсем непопулярных языков точной оценки нет).
Список и проценты, который они там считают, дадут примерно тот же результат, но нужно понимать, что относительное положение соседей в нем достаточно произвольно из-за точности определения популярности. На графике это четко видно — так что он подходит для оценки лучше списка.
Понятно, что относительную популярность С++ и JavaScript или Haskell и Go по этой методике не оценить, Но можно сказать, что внутри этих двух групп разница незначительна, а между ними наоборот — очень существенна.
_>Интенсивные прыжки для языков с рейтингом меньше 1% — это абсолютно нормально. )))
Ну так это проблема tiobe, которой langpop полностью лишен. Даже для языков с популярностью уровня F# там подвижность будет крайне низкой, а "внезапный" прыжок в мейнстрим группу и вовсе исключен. Все что там может прыгать — неизвестные языки из левого хвоста, причем внутри своей группы. Строки на гитхабе и вопросы на СО нужно кому-то написать, а рейтинг на tiobe, как мы знаем, может радикально изменится в одночасье после индексации багтрекера поисковиком.
_>На tiobe нет и это похоже на правду, а вот в том сомнительном месте Хаскель даже опережает в 3 раз Го. ))) Хотя на гитхабе кода на Го больше, чем на Хаскеле.
Еще раз: 3 раза на этом рейтинге — это ничто. Вот 100 раз — это да, заметная разница.
_>И это при с учётом разницы в дате рождения...
И какая же дата рождения у хаскеля? И при чем тут дата рождения, если рост популярности у хаскеля в то же самое время, что и у го начался.
_>Тот пример ничего такого не демонстрирует — функция целиком зависит от передаваемых ей параметров
Она деструктивно меняет передаваемый класс, так что одного параметра не хватает.
_>и не меняет никаких глобальных/статических данных.
Замечательно, но для контроля эффектов этого недостаточно.
_>Это общие слова. Нужна конкретная задачка, решение которой можно записать в одну страничку кода (большее лень для форумного спора).
ОК. Вот микробенчмарк, который проверяет как раз то, что мы обсуждали:
1) Тест дает заметную и при этом характерную для ФП кода нагрузку на ГЦ. Она выделяет за время работы 16 гигов в памяти (2 Гб в секунду) при этом выживаемость объектов в куче меньше половины процента.
2) Использует иммутабельную структуру данных — односвязный список — у которого рантайм "за кадром" переписывает хвосты. В коде же, никаких переписываний нет.
3) Предыдущий пункт обеспечивается эффективной реализацией ленивости.
4) Тест дает возможность продемонстрировать качество оптимизатора (по крайней мере, с выключенной оптимизацией код работает в 30 раз медленнее)
primes = 2:3:filter' isPrime [5,7..] :: [Int]
isPrime x = all' (/= 0) . map (x `rem`) . takeWhile' ((<= x) . (^2)) $ primes
main = print . length . takeWhile' (<= 2^24) $ primes
-- (*)
step p res x | p x = (x:) | otherwise = res
takeWhile' p = foldr (step p $ const []) []
-- здесь раннее завершение, хотя специально ничего для этого в коде не написано.
all' f = foldr (&&) True . map f
filter' p = foldr (step p id) []
-- результат:
--1077871
(*) Собственная реализация стандартных комбинаторов на базе других комбинаторов как раз демонстрирует качество оптимизатора при работе с типичным ФП кодом.
В игрушечных ФЯ производительность сильно зависит от использования готовых библиотечных функций, написанных в рекурсивно-лапшевом стиле либо даже с использованием хаков, функции получаемые комбинированием комбинаторов, как правило, сильно тормозят. Хороший ФЯ-компилятор как раз заточен на оптимизацию такого кода, и эти определения не только не медленнее библиотечных функций, а еще и быстрее: библиотечный takeWhile рекурсивно-лапшевой, оптимизировать его нельзя, так что с ним тест работает на ~ 20% дольше.
Впрочем, я подозреваю, что в D такой иммутабельной структуры данных нет, да и возможности по реализации одних комбинаторов на беза других ограничены, так что сравнить ничего не получится. Вы в ответе перечислите доступные в D персистентные структуры данных, чтоб хоть знать, что там доступно для сравнения.
K>>"данные реально мутабельные" — это на условия задач совсем не похоже. _>Похоже, похоже. Вот тот мой пример с обработкой видео в реальном времени — это прямо оно и есть.
В условиях там будет задано приемлемое быстродействие, а какие используются структуры данных — это детали реализации.
_>и?
И то, что декларируемого вами "широкого использования иммутабельности" в C++ на деле нет.
_>На этот вопрос уже были ответы в данной теме, причём не один раз и на разных примерах. Не вижу смысла повторяться.
Чтоб повториться, нужно что-то сделать в первый раз. А примеров ужасного в сравнении с C++ монадического кода как не было, так и нет. В единственном параллельном сравнении кода (с массивами) код на плюсах лучше не выглядел.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[63]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Речь про activity diagram? Ну, она представляет control-flow, которым в декларативном программировании действительно можно не заморачиваться.
Ага, ага... Правда это базовый способ для записи алгоритмов, но вам не нужен понятное дело)))
K>Ничего не понял.
Я говорю о том, что даже если мы попытаемся нарисовать диаграммку классов (уже смешно звучит) для программы на Хаскеле, то максимум что мы получим, это описание используемых в этой программке типов и всё. В то время как рисование подобной диаграммы для ООП программки часто полностью задаёт всю её архитектуру. Так понятна мысль или надо продолжить разжёвывание про инкапсуляцию и т.п? )
K>Я понял, это виденье, как и виденье страшных проблем "монадного кода" вы оставите при себе, никто с ним так и не сможет ознакомится.
Я уже давно понял, что всё не укладывающееся в ваше мировоззрение, не воспринимается в принципе, даже если оно полностью очевидно. Причём даже повторы не помогают — просто идёт отрицание реальности. Так что в данной дискуссии я уже давно не стараюсь убедить вас, а пишу скорее для зрителей. )))
K>"Оригинальными" определениями я не пользуюсь. Тут определение вполне общепризнанное: язык, хорошо подходящий для решения широкого круга задач. Питон — это все-таки glue language, хотя серьезные претензии на общее назначение имеются. K>Тут интереснее, что вы недавно отрицали существование языков общего назначения как класса: "Нет языка удобного сразу во всех областях. Каждый (из популярных) хорош в своей специфической области.", а теперь удивляетесь, что что-то языком общего назначения не посчитали. Как-то непоследовательно.
Абсолютно нормальная и очевидная логика. И только у вас она почему-то вызывает противоречия.
И Ассемблер и Питон (хотя тут есть нюансы, ну да ладно) в общем то являются языками общего назначения, потому как на них можно написать произвольное приложение. Но "можно" не означает что "нужно". В моей выше процитированной фразе про специфические области очень чётко сказано про "удобство"! Т.е. на любом языке общего назначения можно написать софт в любой области, но не в любой это будет делать максимально удобно на этом языке.
K>Напоминаю, что lg 5 ~ 0.7 крайне впечатляющая разница, что тут скажешь.
1. А причём тут логарифм? С чего вы взяли, что сравнение должно быть в логарифмах?
2. Даже если и в логарифмах и считать что разница в 0,7 раз, то фокус в том что по одному параметру она в 0,7 больше, а по другому в 0,7 раз меньше — и какая же у нас тут "корреляция" и "самопроверка"?
K>При том. Смотрите на график и мысленно рисуете линию тренда (в оригинальном анализе популярности, на базе которого рейтинг и разработан, ничего воображать не нужно было — там линия была) и двигаетесь вдоль нее. Популярные языки будут в верхней правой части графика, а непопулярные — в левой нижней. Удаление от этой линии позволяет прикинуть точность оценки популярности (предсказуемо, что для совсем непопулярных языков точной оценки нет).
О, кстати, а вот на этом графике уже гораздо более адекватные результаты видны (правда сам он конечно ужасно построен). Хотя они конечно тоже не адекватны реальности индустрии, но это уже скорее по причине специфики источников (например на GH практические нет представителей целых огромных областей). Но уже как-то ближе к реальности, чем там нелепая первая ссылка.
K>Список и проценты, который они там считают, дадут примерно тот же результат, но нужно понимать, что относительное положение соседей в нем достаточно произвольно из-за точности определения популярности. На графике это четко видно — так что он подходит для оценки лучше списка.
Вот в том то и дело, что даже приблизительно не такие же. У тех товарищей на первом месте стоит вообще C# (самому то было не смешно давать ссылку с таким результатом?) в то время как здесь он явно далёк от "правого верхнего угла".
K>Понятно, что относительную популярность С++ и JavaScript или Haskell и Go по этой методике не оценить, Но можно сказать, что внутри этих двух групп разница незначительна, а между ними наоборот — очень существенна.
Для разделения всех языков на мейнстрим и маргинальные вовсе не нужны такие сложные и подробные попытки анализа.
K>Еще раз: 3 раза на этом рейтинге — это ничто. Вот 100 раз — это да, заметная разница.
Что за бред? Там рейтинг в процентах со значениями от 0 до 15.
K>Она деструктивно меняет передаваемый класс, так что одного параметра не хватает.
И? Кстати, если надо, то это очевидным образом запрещается тоже (immutable параметр и всё). Но мне больше нравится как раз такое решение, т.к. оно позволяет использовать некоторые бонусы чистых функций и для полностью императивного кода.
_>>и не меняет никаких глобальных/статических данных. K>Замечательно, но для контроля эффектов этого недостаточно.
Если не уметь думать, то конечно нет. )
K>ОК. Вот микробенчмарк, который проверяет как раз то, что мы обсуждали:
Ну так можно увидеть описание самой задачки, а не решение на Хаскеле? ) А то мне лень ковыряться в его плохо читаемом синтаксисе...
K>Впрочем, я подозреваю, что в D такой иммутабельной структуры данных нет, да и возможности по реализации одних комбинаторов на беза других ограничены, так что сравнить ничего не получится. Вы в ответе перечислите доступные в D персистентные структуры данных, чтоб хоть знать, что там доступно для сравнения.
Я пока вообще не понял что там собственно происходит) Кстати, а это компилируемый код или надо ещё что-то добавить?
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>ОК. Вот микробенчмарк, который проверяет как раз то, что мы обсуждали: _>Ну так можно увидеть описание самой задачки, а не решение на Хаскеле? ) А то мне лень ковыряться в его плохо читаемом синтаксисе...
Задача — найти количество простых чисел, не превышающих 16777216.
Предложенный вариант строит список простых чисел, тестируя на простоту все нечетные числа, начиная с 5, причем чтобы решить, является ли очередное число простым, он использует в качестве делителей значения из самого строящегося списка. Список пополняется, пока очередное число не окажется больше 2^24, после чего возвращается его длина.
Полагаю, идиоматическое решение на D вообще не будет использовать списки (хватит и одного массива) и не будет иметь гигабайты аллокаций, но вряд ли Клапауций сочтет его интересным.
Re[64]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ага, ага... Правда это базовый способ для записи алгоритмов, но вам не нужен понятное дело)))
Базовый способ записи алгоритмов — (псевдо)код. Не сталкивался с записыванием алгоритмов с помощью диаграмм даже самыми яростными фанатами UML. По моему, такой ерундой только школьные учителя лет 20 назад страдали.
_>Я говорю о том, что даже если мы попытаемся нарисовать диаграммку классов (уже смешно звучит) для программы на Хаскеле
Почему это звучит смешно?
_>то максимум что мы получим, это описание используемых в этой программке типов и всё. В то время как рисование подобной диаграммы для ООП программки часто полностью задаёт всю её архитектуру.
Во-первых, непонятно, почему только типов и все. В ФЯ бывают системы модулей, например.
Во-вторых, мне непонятно противопоставление "всего-навсего типов" и "ого-го всей архитектуры".
_>Так понятна мысль или надо продолжить разжёвывание про инкапсуляцию и т.п? )
Надо продолжать, ничего не понятно. Что не так с инкапсуляцией, например?
_>Я уже давно понял, что всё не укладывающееся в ваше мировоззрение, не воспринимается в принципе, даже если оно полностью очевидно.
Как мы знаем из книги "Физики шутят", "очевидно, что ..." означает "я этого не проверял, но ...".
_>Причём даже повторы не помогают
Ваши повторы не помогают потому, что они состоят сначала из анонсов: "вот скоро покажу", "вот сейчас", "близится демонстрация ужасов ужасных"
Потом происходит резкий переход к воспоминаниям: "как мы уже видели", "не раз показано", "повторяю и повторяю".
При этом самое главное звено — собственно демонстрация — обычно вовсе выпадает.
Справедливости ради, один раз вы все-таки попытались продемонстрировать конкретные ужасы, только это не удалось, теперь остается только уверять, что они там были.
_>- просто идёт отрицание реальности.
Дело в том, что мы воспринимаем реально по разному. Для меня реальность — это что-то наблюдаемое и демонстрируемое. Реальность достаточно просто показать, описать, сослаться на нее. И эти демонстрации и ссылки очень важны для смыслового наполнения дискуссии.
Вы же, по всей видимости, воспринимаете реальность как что-то постыдное и табуированное. По полгода стесняетесь привести пример, и вообще что-то конкретное, вместо этого ограничиваясь какими-то намеками, недомолвками, улыбочками и подмигиваниями, мол "мы-то с вами понимаем...", вот только озвучить это понимание — явно моветон, а лучше даже не только ничего не демонстрировать, но игнорировать и скипать в цитатах просьбы эту реальность продемонстрировать. Неприлично же!
_>Так что в данной дискуссии я уже давно не стараюсь убедить вас, а пишу скорее для зрителей. )))
Не понимаю, зачем это отдельно уточнять — это типично для публичной дискуссии.
K>>Тут интереснее, что вы недавно отрицали существование языков общего назначения как класса: "Нет языка удобного сразу во всех областях. Каждый (из популярных) хорош в своей специфической области.", а теперь удивляетесь, что что-то языком общего назначения не посчитали. Как-то непоследовательно. _>Абсолютно нормальная и очевидная логика. И только у вас она почему-то вызывает противоречия.
Я согласен с тем, что вы не единственный носитель такого парадоксального подхода. Логика же тут явно неочевидна, потому, что язык для определенной области это не GPL, а DSL.
Также ваши воззрения не связаны с реальностью (пардон май френч) в которой языки программирования общего назначения существуют и применяются в широком спектре несхожих областей, часто очень далеких от области с которой началось распространение.
_>И Ассемблер и Питон (хотя тут есть нюансы, ну да ладно) в общем то являются языками общего назначения, потому как на них можно написать произвольное приложение. Но "можно" не означает что "нужно". В моей выше процитированной фразе про специфические области очень чётко сказано про "удобство"! Т.е. на любом языке общего назначения можно написать софт в любой области, но не в любой это будет делать максимально удобно на этом языке.
Так я так и сказал, что есть некоторые области где по техническим причинам применение будет затруднено, хотя это обычно свойство имплементации, а не языка. Вы же пишете "Каждый (из популярных) хорош в своей специфической области". На вопрос о конкретной области C++ вы, что характерно, не ответили.
_>1. А причём тут логарифм? С чего вы взяли, что сравнение должно быть в логарифмах?
Обратите внимание на шкалы графика. Видите там 1e+0, 1e+1, 1e+2 ?
_>2. Даже если и в логарифмах и считать что разница в 0,7 раз, то фокус в том что по одному параметру она в 0,7 больше, а по другому в 0,7 раз меньше — и какая же у нас тут "корреляция" и "самопроверка"?
Хорошая корреляция. В современном рейтинге ее не считают, но это же по графику видно, что хорошая. Впрочем, создается ощущение, что вы просматриваете страницу в текстовом браузере и графика не видите вовсе. Это объясняет и ваши загадочные утверждения о том, что они видимо что-то неверно посчитали, потому что у них процентный рейтинг только от СО зависит, хотя если посмотреть на график причина очевидна.
Для тех, кто заказывает интернет страницы по телетайпу, я даже могу пересказать в общих чертах: дело в том, что на оси гитхаба мы видим в правой части шкалы 1e+10, а в верхней части шкалы СО — только 1e+5. Это означает, что строки на гитхабе растут гораздо быстрее вопросов на СО. Рассмотрим простой пример: На языке Сартр написана одна строчка на гитхабе, а на языке Антракс 10000 строк. При этом про Сартр спросили на СО 1 раз, а про Антракс — 100 раз. Получается, что доля Сартра на гитхабе примерно 1e-3%, а доля Антракса на гитхабе примерно 99.99%. Зато на СО у Сартра примерно 0.99%, а у Антракса только примерно 99.01%. Посчитаем среднее: для Сартра это ~ 0.5%, а для Антракса ~ 99.5%. Легко видеть, что рейтинг по такому агрегату будет существенно сильнее похож на более медленно растущий СО-рейтинг, чем на быстрый гитхаб-рейтинг. По хорошему говоря, агрегировать такие рейтинги нужно с соответствующим поправочным к-том, хотя посчитано все правильно (но зря). К счастью, есть график и процентный агрегированный рейтинг не нужен.
_>Вот в том то и дело, что даже приблизительно не такие же.
Между этими графиками много лет прошло.
_>У тех товарищей на первом месте стоит вообще C# (самому то было не смешно давать ссылку с таким результатом?) в то время как здесь он явно далёк от "правого верхнего угла".
В обновленном графике по той же технике http://redmonk.com/sogrady/2014/01/22/language-rankings-1-14/ C# продвинулся в сторону линии тренда.
Про СО-эффект агрегата уже написано.
_>Для разделения всех языков на мейнстрим и маргинальные вовсе не нужны такие сложные и подробные попытки анализа.
Вы видимо забыли, с чего начался разговор о рейтинге. Вы противопоставили популярности хаскеля и го, а из рейтингов следует, что это маргинальные языки с неотличимой популярностью (точнее, без оной).
_>Там рейтинг в процентах со значениями от 0 до 15.
Не смотрите на рейтинг, смотрите на график.
_>И? Кстати, если надо, то это очевидным образом запрещается тоже (immutable параметр и всё).
Ну так компилятор позволяет проаннотировать функцию pure не аннотируя входные данные как immutable. Т.е. то, что он проверяет к чистоте никакого отношения не имеет. Это некоторое свойство, придуманное авторами D непонятно что значащее.
_>оно позволяет использовать некоторые бонусы чистых функций и для полностью императивного кода.
Например?
K>>Замечательно, но для контроля эффектов этого недостаточно. _>Если не уметь думать, то конечно нет. )
А если уметь думать — тем более.
_>Ну так можно увидеть описание самой задачки, а не решение на Хаскеле? ) А то мне лень ковыряться в его плохо читаемом синтаксисе...
Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет. Т.е. есть работа как для компилятора (устраняющего ненужные промежуточные значения), так и рантайма, которому есть что быстро размещать в памяти и, к примеру, переписывать по месту.
Решается эта задача, вычислением простых чисел тупым методом.
primes — иммутабельный односвязный список простых чисел (помещающихся в Int32 для простоты реализации в D), упорядоченный по возрастанию, которые получаются из списка нечетных чисел начиная с 5, отфильтрованных функцией isPrime и присоединенных к этому списку в начале чисел 2 и 3
isPrime — функция, проверяющая, является ли число простым проверкой его делимости на простые числа из списка primes, квадраты которых меньше либо равны проверяемому числу.
main — основная функция, которая отбирает из списка простых чисел те, что меньше 2 в 24-ой степени, считает их количество и выводит его в консоль.
дальше следуют реализации аналогов стандартных функций для работы со списками, реализованных через другие функции для работы со списками.
От вас я ожидаю решения той же задачи на D максимально приближенным способом, чтоб оценивать одно и то же, и/или какие-то поправки для моего кода, которые позволили бы приблизится к чему-то среднему между нашими вариантами, если мой нельзя воспроизвести на D.
_>Я пока вообще не понял что там собственно происходит)
Вообще говоря, это никак не должно было помешать вам перечислить доступные в D персистентные структуры данных, чтоб знать, что там доступно для сравнения.
_>Кстати, а это компилируемый код или надо ещё что-то добавить?
Да, компилируемый, проверялся на GHC 7.4.2 и 7.6.3 (x86)
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Полагаю, идиоматическое решение на D вообще не будет использовать списки (хватит и одного массива)
Охотно верю. Но при чем тут декларируемая моим оппонентом "хорошая поддержка иммутабельности"?
DM>и не будет иметь гигабайты аллокаций, но вряд ли Клапауций сочтет его интересным.
Ну правильно, потому что никакого смысла кроме создания гигабайтов аллокаций в этом коде нет (не думаю, что тут надо что-то пояснять, потому что этот бенчмарк я позаимствовал прямо из вашего блогпоста про Clean). Сам-то я понимаю, что в этом случае результат сравнения консервативного и точного сборщиков немного предсказуем, но мой оппонент настаивает.
Вообще, идиоматическое решение на D может быть интересно в более широком контексте сравнения возможностей и удобства построения конвейеров. К примеру, идиоматический код на F#, максимально приближенный к обсуждаемому (ну, с сохранением потенциальной бесконечности списка простых чисел) и не использующий иммутабельных структуры вовсе, а использующий итераторы и мутабельные массивы для кеширования, у меня получился на десятичный порядок медленнее (впрочем, сомневаюсь, что доказательства (и без того очевидной) убогости F# в аспекте ФП кому-то интересны).
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Это никакой не Tree Sort, это именно пародия на quick sort. K>Не понятно, какой смысл вы вкладываете в слова "пародия на quick sort", но это совершенно точно tree sort.
Смысл следующий: за безусловным внешнем сходством скрываются серьёзные концептуальные отличия от того, что было заложено в оригинальной статье Тони Хоара, кардинальным образом влияющие на область применимости.
K>Называть это quicksort, конечно, неправильно.
Об этом и речь, даже Erik Meijer сделал соответствующую оговорку в своих видео-лекциях.
K>То, что это tree sort в глаза сразу не бросается потому, что он дефористирован вручную. Т.е. функция построения дерева (несбалансированного)
Ок, я думал Tree Sort предполагает только сбалансированные деревья. А так получается что нет ни inplace, ни нормального worst case performance (как для out-of-place)
EP>>Quick Sort делит массив на две части (вырезая середину), и продолжает рекурсивно в каждой из частей. Начиная с определённой глубины текущий Range полностью поместится в L3, ещё глубже — L2, потом в L1 и так далее.
K>Ну, не каждый divide-and-conquer алгоритм считается cache-oblivious. Почитайте про какой-нибудь funnel-sort там разница хорошо понятна.
Cache-oblivious — означает эффективное использование иерархии памяти, без привязки к конкретным характеристикам железа, т.е. противоположность cache-aware.
Funnel-sort это optimal cache-oblivious out-of-place алгоритм, основанный на merge sort. В то время, как quicksort — in-place. Подозреваю что как и у merge sort, при переходе к in-place, сложность funnel-sort возрастёт до O(N ln^2 N), если такой переход вообще возможен.
K>Да и как divide-and-conquer quick sort — не фонтан. Потому, что качество деления у него от данных зависит (во отличие от той же сортировки слияниями).
Оно хоть и зависит от данных, но в подавляющем большинстве случаев даёт прекрасный результат. Например, если получится каждый уровень разбивать как 1 к 10, то всё-равно получаем сложность O(N ln N).
Да и вообще, quicksort до сих пор считается одним из самых многосторонне-быстрых алгоритмов сортировки, поэтому непонятно про какую тормознутость идёт речь.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Нужно осмысление. Как это в твою идею вписать — не ясно. EP>>Осмысление чего и зачем? I>вычисления последовательности Фибоначчи.
А как ты её осмысляешь?
I>Затем, что бы знание можно было применить повторно, тем самым ребенком которому ты собираешься чего то объяснять.
Для повторного применения, никакое осмысление не нужно.
EP>>Просто посмотреть на идиоматичное решение одной и той же задачи, например генерацию чисел Фибоначчи итерационным методом vs функциональное комбинирование комбинаторов. I>Не ясно, почему ты выбрал комбинаторы, по какому принципу ? Почему не монады, не реактивный код, не асинхронщина, а именно комбинаторы?
Потому что выше именно комбинаторы назвали идиоматичным ФП.
I>И почему надо сравнивать с простым итерационным методом, а не брать модный MVC-фремворк с серверным бакэндом ?
Потому что просто, эффективно и идиоматично.
I>По моему нужно сравнивать в одинаковых условиях — взять простейшее решение в обоих подходах и сравнить. Проверяем понимание не по умению рисовать круги циркулем, а по умению применить полученое знание.
А ты о чём вообще споришь? О том что "идиоматичный ФП":
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>>>Нужно осмысление. Как это в твою идею вписать — не ясно. EP>>>Осмысление чего и зачем? I>>вычисления последовательности Фибоначчи.
EP>А как ты её осмысляешь?
По всякому, разные представления, свойства и тд.
По всякому. I>>Затем, что бы знание можно было применить повторно, тем самым ребенком которому ты собираешься чего то объяснять.
EP>Для повторного применения, никакое осмысление не нужно.
Без осмысления ты не сможешь понять, что вон то нечто, это последовательность, и не просто последовательность, а её можно свести к фибоначчи или, например, заменить на фибоначчи.
Вот смотри, простой пример — есть 10 яблок, по 10 рублей, всего это стоит 10*10, 11 яблок по 10 рублей — 11*10, 12 яблок по 10 рублей — 12*10.
Осмысление требуется уже для того, что бы
1 абстрагироваться от количества яблок и выдать формулу x*10
2 применить конкретное значение к формуле и получить нужный результат, то есть, 3 яблока по 10р, это вместо x в формуле x*10 подставить 3
Все это нужно уметь делать в уме, если ты хочешь применять повторно, иначе тебе ничего кроме как продавать яблоки на рынке, не светит.
Фибоначчи это последовательность с кучей свойств, скажем, есть последовательность, которая может быть и не похожа на фибоначчи, но может быть сведена к ней. И здесь точно так же будет и абстрагирование и применение.
EP>>>Просто посмотреть на идиоматичное решение одной и той же задачи, например генерацию чисел Фибоначчи итерационным методом vs функциональное комбинирование комбинаторов. I>>Не ясно, почему ты выбрал комбинаторы, по какому принципу ? Почему не монады, не реактивный код, не асинхронщина, а именно комбинаторы?
EP>Потому что выше именно комбинаторы назвали идиоматичным ФП.
То есть, от балды. Ты мог бы сэкономить время, поскольку любой идиоматичный код сложен, то и идиоматичный функциоинальный код так же сложен.
I>>И почему надо сравнивать с простым итерационным методом, а не брать модный MVC-фремворк с серверным бакэндом ?
EP>Потому что просто, эффективно и идиоматично.
А я щетаю, что MVC-фремворк с серверным бакендом это проще простого, да еще и намного эффективнее — кроме простого вычисления получаешь внятный результат которым можно пользоваться.
I>>По моему нужно сравнивать в одинаковых условиях — взять простейшее решение в обоих подходах и сравнить. Проверяем понимание не по умению рисовать круги циркулем, а по умению применить полученое знание.
EP>А ты о чём вообще споришь?
Не я, а ты. Например ты, внезапно, решил что думать не надо.
Здравствуйте, Ikemefula, Вы писали:
I>>>Затем, что бы знание можно было применить повторно, тем самым ребенком которому ты собираешься чего то объяснять. EP>>Для повторного применения, никакое осмысление не нужно. I>Без осмысления ты не сможешь понять, что вон то нечто, это последовательность, и не просто последовательность, а её можно свести к фибоначчи или, например, заменить на фибоначчи. [...] I>Фибоначчи это последовательность с кучей свойств, скажем, есть последовательность, которая может быть и не похожа на фибоначчи, но может быть сведена к ней. И здесь точно так же будет и абстрагирование и применение.
Речь шла про вычислитель в голове:
I>Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи.
Такой вычислитель, как мы выяснили, естественен для человека.
Умение же абстрагироваться от задачи, её осмысление до такой степени, при которой получается применять те же знания совершенно в другой плоскости — это ортогонально наличию вычислителя. Компьютеры, например, так не умеют, но вычислителем от этого быть не перестают
EP>>Потому что выше именно комбинаторы назвали идиоматичным ФП. I>То есть, от балды. Ты мог бы сэкономить время, поскольку любой идиоматичный код сложен, то и идиоматичный функциоинальный код так же сложен. [...] I>Это конкретный вариант. Он сложен не потому, что хаскель и фп, а потому что идиоматический код сложен просто потому что он идиоматический.
Это почему ещё идиоматический код обязательно является сложным для понимания?
Re[43]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
EP>>>>>>Да и вообще, как только у нас есть while или аналог — то "можно делать плохие вещи". S>>>>>И далеко не всякий аналог while даёт нам возможность "делать плохие вещи". EP>>>>Если нет возможности сделать вечный цикл — то это не аналог while. S>>>А для чего вам вечный цикл? EP>>Для полноты по Тьюрингу. S>А для чего вам полнота по Тьюрингу?
Видимо для реализации любой вычислимой функции.
Но согласен, не для каждой задачи нужна полнота — тем не менее, аналог while есть практически в каждом современном языке, а соответственно "можно делать плохие вещи".
Re[31]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Опять 25. Почему они не работающие? Они работают даже для ресурсов в отличии от. I>Не работают. Это обеспечивается _руками_. Что будет, я объявлю свой враппер, где не буду переопределять никакие операторы, а деструкторе тупо грохну ресурс через метод навроде ::Close() ?
И не уберёшь конструктор копирования? — тогда нарушишь семантику определённую стандартом. Создал кривой враппер — ССЗБ.
Re[53]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Речь шла про вычислитель в голове: EP>
I>>Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи.
EP>Такой вычислитель, как мы выяснили, естественен для человека.
Нет, он НЕ естественен для человека. Что бы использовать такой вычислитель, нужно иметь хорошее абстрактное мышление. Люди учатся этому десятками лет, а многие никогда не смогут осилить этот подход.
EP>Умение же абстрагироваться от задачи, её осмысление до такой степени, при которой получается применять те же знания совершенно в другой плоскости — это ортогонально наличию вычислителя. Компьютеры, например, так не умеют, но вычислителем от этого быть не перестают
Компьютер пока что ничего не умеет в той области, про которую мы говорим. Если ты явно не опишешь проблему и метод решения, компьютер ни за что не догадается, что там можно применить последовательность фибоначчи. Как раз потому, что нет у него никакого осмысления — все связи между понятиями захардкожены и компьютер не умеет образовывать новые по ходу работы.
I>>Это конкретный вариант. Он сложен не потому, что хаскель и фп, а потому что идиоматический код сложен просто потому что он идиоматический.
EP>Это почему ещё идиоматический код обязательно является сложным для понимания?
Потому что для понимания, изучения нужно сделать больше умственных затрат. Сначала изучаешь базовые вещи, а у же потом раскладываешь идиомы на базовые, а далее строишь идиомы из базовых. Просто из воздуха нахватать идиом не получится.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Опять 25. Почему они не работающие? Они работают даже для ресурсов в отличии от. I>>Не работают. Это обеспечивается _руками_. Что будет, я объявлю свой враппер, где не буду переопределять никакие операторы, а деструкторе тупо грохну ресурс через метод навроде ::Close() ?
EP>И не уберёшь конструктор копирования? — тогда нарушишь семантику определённую стандартом. Создал кривой враппер — ССЗБ.
То есть, ты согласен, что гарантии нужно обеспечивать руками, но почему то стесняешься это признать и приплетаешь сюда понятия навроде ССЗБ.
Re[33]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>Опять 25. Почему они не работающие? Они работают даже для ресурсов в отличии от. I>>>Не работают. Это обеспечивается _руками_. Что будет, я объявлю свой враппер, где не буду переопределять никакие операторы, а деструкторе тупо грохну ресурс через метод навроде ::Close() ? EP>>И не уберёшь конструктор копирования? — тогда нарушишь семантику определённую стандартом. Создал кривой враппер — ССЗБ. I>То есть, ты согласен, что гарантии нужно обеспечивать руками, но почему то стесняешься это признать и приплетаешь сюда понятия навроде ССЗБ.
1. Конкретно в этом месте — грабли языка, конструктор копирования и оператор присваивания просто не должны генерироваться автоматом при наличии ручного деструктора — также как и конструктор перемещения (если же нужен автоматический, то есть =default).
2. В общем случае, работа с памятью в C++ требует больше усилий и знаний, чем в управляемых языках, но тем не менее в большинстве случаев достаточно автоматизирована.
3. Абсолютно тот же самый механизм, что и для работы с памятью, применим и ко всем остальным ресурсам. Добавление одного ресурса в широко используемый объект, не влечёт за собой транзитивный каскад правок всех тех мест, которые напрямую или косвенно зависят от этого объекта, в отличии от управляемых языков. Или, например, можно создать замыкание с ресурсом внутри, в отличии от.
Re[54]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Речь шла про вычислитель в голове: EP>>
I>>>Для того, что бы понять твою итерационную версию, надо освоить простейший вычислитель. У ребенка нет в голове модели этого вычислителя. Когда появится, вот тогда можно будет начать объяснять итерационную версию фибоначчи.
EP>>Такой вычислитель, как мы выяснили, естественен для человека. I>Нет, он НЕ естественен для человека. Что бы использовать такой вычислитель, нужно иметь хорошее абстрактное мышление. Люди учатся этому десятками лет, а многие никогда не смогут осилить этот подход.
, которые ты проигнорировал.
EP>>Умение же абстрагироваться от задачи, её осмысление до такой степени, при которой получается применять те же знания совершенно в другой плоскости — это ортогонально наличию вычислителя. Компьютеры, например, так не умеют, но вычислителем от этого быть не перестают I>Компьютер пока что ничего не умеет в той области, про которую мы говорим. Если ты явно не опишешь проблему и метод решения, компьютер ни за что не догадается, что там можно применить последовательность фибоначчи. Как раз потому, что нет у него никакого осмысления — все связи между понятиями захардкожены и компьютер не умеет образовывать новые по ходу работы.
То есть получается:
* Дети и компьютеры не могут осмыслить последовательность Фибоначчи.
* Дети и компьютеры могут вычислить её итерационным методом.
Так?
I>>>Это конкретный вариант. Он сложен не потому, что хаскель и фп, а потому что идиоматический код сложен просто потому что он идиоматический. EP>>Это почему ещё идиоматический код обязательно является сложным для понимания? I>Потому что для понимания, изучения нужно сделать больше умственных затрат. Сначала изучаешь базовые вещи, а у же потом раскладываешь идиомы на базовые, а далее строишь идиомы из базовых. Просто из воздуха нахватать идиом не получится.
Я могу согласится, что для создания идиоматического кода, нужно много знаний и опыта. Но категорически не согласен с тем, что идиоматический код обязан быть сложным для понимания.
Re[55]: Есть ли вещи, которые вы прницпиально не понимаете...
Наоборот, я показал что у всех примеров есть один и тот же дефект
I>>Компьютер пока что ничего не умеет в той области, про которую мы говорим. Если ты явно не опишешь проблему и метод решения, компьютер ни за что не догадается, что там можно применить последовательность фибоначчи. Как раз потому, что нет у него никакого осмысления — все связи между понятиями захардкожены и компьютер не умеет образовывать новые по ходу работы.
EP>То есть получается: EP>* Дети и компьютеры не могут осмыслить последовательность Фибоначчи. EP>* Дети и компьютеры могут вычислить её итерационным методом. EP>Так?
Да, они могут повторить какую то последовательность без осмысления. Абстрагирование не включается, то есть, формула или просто какое то знание в компактной форме у них не появися и даже если им сообщить его явно, они не смогут его использовать.
EP>Я могу согласится, что для создания идиоматического кода, нужно много знаний и опыта. Но категорически не согласен с тем, что идиоматический код обязан быть сложным для понимания.
Я не в курсе как ты сложность понимаешь. Вот до того, как люди узнают про производные и интегралы им надо много трудозатрат что бы решить задачу. Пока производные и интегралы не знают, методы решения на них основаные, будут сложными.
Более того, пока они руками не построят N графиков, не решат K Задач на площади и тд, сами производные и интегралы будут сложны.
А вот как освоили, внезапно, все это становится простым и дело исключительно в трудозатратах на запись решения.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>3. Абсолютно тот же самый механизм, что и для работы с памятью, применим и ко всем остальным ресурсам. Добавление одного ресурса в широко используемый объект, не влечёт за собой транзитивный каскад правок всех тех мест, которые напрямую или косвенно зависят от этого объекта, в отличии от управляемых языков. Или, например, можно создать замыкание с ресурсом внутри, в отличии от.
Время жизни ресурса должно совпадать со временем жизни объекта. Если это не так, придется расставлять нужные вызовы -> транзитивный каскад правок или же часто приходится пользоваться нужными врапперами и смартпоинтерами -> транзитивный каскад правок.
В менеджед, если объект уже ресурс, то не надо никаких транзитивных правок. Далее, если объект не ресурс, нужно правильно расставить вызовы Dispose -> транзитивный каскад правок.
Вобщем, ситуация примерно одинаковая.
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>3. Абсолютно тот же самый механизм, что и для работы с памятью, применим и ко всем остальным ресурсам. Добавление одного ресурса в широко используемый объект, не влечёт за собой транзитивный каскад правок всех тех мест, которые напрямую или косвенно зависят от этого объекта, в отличии от управляемых языков. Или, например, можно создать замыкание с ресурсом внутри, в отличии от. I>Время жизни ресурса должно совпадать со временем жизни объекта.
Практически основной use-case. Посмотри хотя бы на типичную реализацию Dispose.
I>Если это не так, придется расставлять нужные вызовы -> транзитивный каскад правок или же часто приходится пользоваться нужными врапперами и смартпоинтерами -> транзитивный каскад правок. I>В менеджед, если объект уже ресурс, то не надо никаких транзитивных правок.
Согласен.
I>Далее, если объект не ресурс, нужно правильно расставить вызовы Dispose -> транзитивный каскад правок.
Да, Dispose + using'и.
I>Вобщем, ситуация примерно одинаковая.
Нет.
1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть.
2. Редкий use case — ресурс нужно освободить до начала смерти объекта, в соответствии с некоторой хитрой логикой, которая не просто задаётся в одном блоке кода (без каскадных правок), а ещё требует правок всех зависимых объектов: нужны правки и в C++ и в C#.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Видимо для реализации любой вычислимой функции. EP>Но согласен, не для каждой задачи нужна полнота — тем не менее, аналог while есть практически в каждом современном языке, а соответственно "можно делать плохие вещи".
Повторюсь: далеко не всякий аналог while даёт нам возможность "делать плохие вещи".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Время жизни ресурса должно совпадать со временем жизни объекта.
EP>Практически основной use-case. Посмотри хотя бы на типичную реализацию Dispose.
Что я должен там увидеть ?
I>>Вобщем, ситуация примерно одинаковая.
EP>Нет. EP>1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть.
Не так — в C# каскадные правки нужны только тогда, когда добавляется интерфейс. В С++ если объект становится ресурсом, далеко не факт, что использовать его можно точно так же , как и раньше.
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>>>Время жизни ресурса должно совпадать со временем жизни объекта. EP>>Практически основной use-case. Посмотри хотя бы на типичную реализацию Dispose. I>Что я должен там увидеть ?
Совпадение времени жизни ресурса с временем жизни объекта.
I>>>Вобщем, ситуация примерно одинаковая. EP>>Нет. EP>>1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть. I>Не так — в C# каскадные правки нужны только тогда, когда добавляется интерфейс.
И что это меняет?
I>В С++ если объект становится ресурсом, далеко не факт, что использовать его можно точно так же , как и раньше.
Это не факт только в особо маргинальных случаях, часто и так являющимися undefined behavior.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
EP>>Видимо для реализации любой вычислимой функции. EP>>Но согласен, не для каждой задачи нужна полнота — тем не менее, аналог while есть практически в каждом современном языке, а соответственно "можно делать плохие вещи". S>Повторюсь: далеко не всякий аналог while даёт нам возможность "делать плохие вещи".
Тогда это не полный аналог while, а замена только для некоторых его аспектов.
И если в языке нет возможности "делать плохие вещи" — то он не будет являться полным по Тьюрингу. Безусловно такие языки(например) имеют свои области применения, но это далеко не мэйнстрим.
Re[38]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Практически основной use-case. Посмотри хотя бы на типичную реализацию Dispose. I>>Что я должен там увидеть ?
EP>Совпадение времени жизни ресурса с временем жизни объекта.
Там точно этого не увидишь
EP>>>1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть. I>>Не так — в C# каскадные правки нужны только тогда, когда добавляется интерфейс.
EP>И что это меняет?
Буквально всё — и в С++ и в С# каскадные правки в основном вылазят там, где класс меняет обязанности. Как правило новый класс нужно использовать немного иначе, что очевидно, а часто радикально иначе, например нужно выбрать правильный момент открытия ресурса а бывает еще и с закрытием надо постараться.
I>>В С++ если объект становится ресурсом, далеко не факт, что использовать его можно точно так же , как и раньше.
EP>Это не факт только в особо маргинальных случаях, часто и так являющимися undefined behavior.
Вот бы узнать, что это за особо маргинальные случаи
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>>>1. Основной use case — scoped lifetime: в C++ нет каскада правок, в C# — есть. I>>>Не так — в C# каскадные правки нужны только тогда, когда добавляется интерфейс. EP>>И что это меняет? I>Буквально всё — и в С++ и в С# каскадные правки в основном вылазят там, где класс меняет обязанности.
Обязанности те же самые — изменилась только реализация, private секция.
I>Как правило новый класс нужно использовать немного иначе, что очевидно, а часто радикально иначе, например нужно выбрать правильный момент открытия ресурса а бывает еще и с закрытием надо постараться.
Подавляющее большинство ресурсов успешно вписывается в схему constructor-acquire destructor-release.
I>>>В С++ если объект становится ресурсом, далеко не факт, что использовать его можно точно так же , как и раньше. EP>>Это не факт только в особо маргинальных случаях, часто и так являющимися undefined behavior. I>Вот бы узнать, что это за особо маргинальные случаи
Например, если при удалении всего pool'а не вызывается каждый деструктор, а просто освобождается вся память, с расчётом на то, что там нет ресурсов кроме памяти.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Буквально всё — и в С++ и в С# каскадные правки в основном вылазят там, где класс меняет обязанности.
EP>Обязанности те же самые — изменилась только реализация, private секция.
Правильно понимаю, запись в файл и её отсутствие это одно и то же ? Непонятно.
I>>Как правило новый класс нужно использовать немного иначе, что очевидно, а часто радикально иначе, например нужно выбрать правильный момент открытия ресурса а бывает еще и с закрытием надо постараться.
EP>Подавляющее большинство ресурсов успешно вписывается в схему constructor-acquire destructor-release.
А большинство не-ресурсов используется как попало. Вот вставил ты файловый ресурс в такой объект и вот фокус — объект инстанцируется в изолированом контексе и файловые операции будут фейлиться если только не вызваны в определенный момент времени. Опаньки ! Все такие вызовы
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Тогда это не полный аналог while, а замена только для некоторых его аспектов. EP>И если в языке нет возможности "делать плохие вещи" — то он не будет являться полным по Тьюрингу. Безусловно такие языки(например) имеют свои области применения, но это далеко не мэйнстрим.
Снова повторюсь: какая конкретно полезная функциональность недоступна вам при отсутствии полноты по Тьюрингу (или при отсутствии бесконечных циклов)?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Базовый способ записи алгоритмов — (псевдо)код. Не сталкивался с записыванием алгоритмов с помощью диаграмм даже самыми яростными фанатами UML. По моему, такой ерундой только школьные учителя лет 20 назад страдали.
Ну да, ну да) И гугл вот тоже выдаёт исключительно псевдокод по запросу на "алгоритм". )))
K>Во-первых, непонятно, почему только типов и все. В ФЯ бывают системы модулей, например.
Модули — это уже другая uml диаграммка, как раз та, про которую я сказал, что чуть ли не единственная нормально применимая в чистом ФП. И это инструмент совсем другого уровня детализации.
K>Во-вторых, мне непонятно противопоставление "всего-навсего типов" и "ого-го всей архитектуры".
Намекаю: где на диаграмме можно увидеть полный набор функций проектируемой программы и их взаимодействие между собой?
K>Надо продолжать, ничего не понятно. Что не так с инкапсуляцией, например?
Нууу её в Хаскеле просто нет. )))
K>Как мы знаем из книги "Физики шутят", "очевидно, что ..." означает "я этого не проверял, но ...".
И тем не менее физики обычно знают о чём говорят, в отличие от вас. )
K>Ваши повторы не помогают потому, что они состоят сначала из анонсов: "вот скоро покажу", "вот сейчас", "близится демонстрация ужасов ужасных" K>Потом происходит резкий переход к воспоминаниям: "как мы уже видели", "не раз показано", "повторяю и повторяю". K>При этом самое главное звено — собственно демонстрация — обычно вовсе выпадает. K>Справедливости ради, один раз вы все-таки попытались продемонстрировать конкретные ужасы, только это не удалось, теперь остается только уверять, что они там были.
Я вот всё думал, что мне напоминает эта наша дискуссия... Так это же в точности диалоги с киевлянами с политической ветки в последние месяцы. Прямо идеальное соответствие наблюдается:
— а у вас там нацики! (а в Хаскеле код становится ужасным на императивных задачах!)
— ничего подобного (...)
— а вот же ролики на ютубе с ними (вот же примеры кода с ужасом)
— да это не нацики; а даже если и нацики, их мало и они не во власти; а даже если и много и во власти, то значит так надо, чтобы победить бандитов и защититься от агрессии соседей. (да нет там ужасов в монадном коде; а даже если если и есть, то совсем немного и в редких случаях; а даже если и не в редких, то всё равно это всё компенсируется красотой кода в других местах).
В политической ветки все подобные дискуссии естественно ничем полезным не кончались. И я почем-то не сомневаюсь, что данная наша дискуссия завершится точно так же. )))
K>Я согласен с тем, что вы не единственный носитель такого парадоксального подхода. Логика же тут явно неочевидна, потому, что язык для определенной области это не GPL, а DSL.
И снова прямое передёргивание. Я говорил, что языки "хороши в какой-то определённой области", а не созданы исключительно для неё.
K>Также ваши воззрения не связаны с реальностью (пардон май френч) в которой языки программирования общего назначения существуют и применяются в широком спектре несхожих областей, часто очень далеких от области с которой началось распространение.
Не вижу никаких противоречий с моими высказываниями (оригинальными, а не "доработанными")...
_>>1. А причём тут логарифм? С чего вы взяли, что сравнение должно быть в логарифмах? K>Обратите внимание на шкалы графика. Видите там 1e+0, 1e+1, 1e+2 ?
Причём тут вообще график то? Я говорю про данные для него, которые там везде указаны.
K>Хорошая корреляция. В современном рейтинге ее не считают, но это же по графику видно, что хорошая. Впрочем, создается ощущение, что вы просматриваете страницу в текстовом браузере и графика не видите вовсе. Это объясняет и ваши загадочные утверждения о том, что они видимо что-то неверно посчитали, потому что у них процентный рейтинг только от СО зависит, хотя если посмотреть на график причина очевидна. K>Для тех, кто заказывает интернет страницы по телетайпу, я даже могу пересказать в общих чертах: дело в том, что на оси гитхаба мы видим в правой части шкалы 1e+10, а в верхней части шкалы СО — только 1e+5. Это означает, что строки на гитхабе растут гораздо быстрее вопросов на СО. Рассмотрим простой пример: На языке Сартр написана одна строчка на гитхабе, а на языке Антракс 10000 строк. При этом про Сартр спросили на СО 1 раз, а про Антракс — 100 раз. Получается, что доля Сартра на гитхабе примерно 1e-3%, а доля Антракса на гитхабе примерно 99.99%. Зато на СО у Сартра примерно 0.99%, а у Антракса только примерно 99.01%. Посчитаем среднее: для Сартра это ~ 0.5%, а для Антракса ~ 99.5%. Легко видеть, что рейтинг по такому агрегату будет существенно сильнее похож на более медленно растущий СО-рейтинг, чем на быстрый гитхаб-рейтинг. По хорошему говоря, агрегировать такие рейтинги нужно с соответствующим поправочным к-том, хотя посчитано все правильно (но зря). К счастью, есть график и процентный агрегированный рейтинг не нужен.
Очаровательные рассуждения) Только проведены они совсем не для тех данных, которые вызывают сомнения... В данном случае то проблем нет. А вот что у нас получается для расклада: Сартр написана одна строчка на гитхабе и 100 вопросов на СО, а на языке Антракс 10000 строк на гитхабе и 1 вопрос на СО? Если посчитано честное среднее, то оба языка будут рядом в рейтинге. Однако рейтинг данных товарищей для подобных случаев однозначно показывает преимущество Сартра...
K>Вы видимо забыли, с чего начался разговор о рейтинге. Вы противопоставили популярности хаскеля и го, а из рейтингов следует, что это маргинальные языки с неотличимой популярностью (точнее, без оной).
С этим никто и не спорит. Дискуссия о рейтингах является отдельной темой, а не попыткой назвать язык Го популярным (кстати, лично мне данный язык не особо симпатичен).
K>Ну так компилятор позволяет проаннотировать функцию pure не аннотируя входные данные как immutable. Т.е. то, что он проверяет к чистоте никакого отношения не имеет. Это некоторое свойство, придуманное авторами D непонятно что значащее.
Совершенно верно. И данной свойство является чем-то вроде аналитического продолжения классического понятия чистоты на мутабельные данные. Т.к. в случае иммутабельных данных имеем полное соответствие с чистотой из Хаскеля.
_>>оно позволяет использовать некоторые бонусы чистых функций и для полностью императивного кода. K>Например?
Гарантию отсутствия побочных эффектов. Т.е. помощь на уровне дизайна. Что-то вроде модификатора const из C++, только на другом уровне абстракции.
K>Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет. Т.е. есть работа как для компилятора (устраняющего ненужные промежуточные значения), так и рантайма, которому есть что быстро размещать в памяти и, к примеру, переписывать по месту.
Ну так это получается тест не на поддержку иммутабельности, а на скорость GC и т.п. Т.е. я не вижу разницы в подобном тесте для мутабельных и для иммутабельных данных, т.к. непонятно какие оптимизации может тут добавить компилятор для иммутабельных данных — пересоздание структур будет происходить в любом случае и будет занимать основное время.
K>Решается эта задача, вычислением простых чисел тупым методом. K>primes — иммутабельный односвязный список простых чисел (помещающихся в Int32 для простоты реализации в D), упорядоченный по возрастанию, которые получаются из списка нечетных чисел начиная с 5, отфильтрованных функцией isPrime и присоединенных к этому списку в начале чисел 2 и 3 K>isPrime — функция, проверяющая, является ли число простым проверкой его делимости на простые числа из списка primes, квадраты которых меньше либо равны проверяемому числу. K>main — основная функция, которая отбирает из списка простых чисел те, что меньше 2 в 24-ой степени, считает их количество и выводит его в консоль. K>дальше следуют реализации аналогов стандартных функций для работы со списками, реализованных через другие функции для работы со списками.
Задачка понятна, но не ясно где в ней логично использовать иммутабельные данные. Очевидно же, что тут как раз явный пример задачи оптимально решаемой с мутабельными данными. Собственно сам факт захвата 16 гигов оперативки однозначно свидетельствует о чудовищной не оптимальности подхода с иммутабельными данными.
K>От вас я ожидаю решения той же задачи на D максимально приближенным способом, чтоб оценивать одно и то же, и/или какие-то поправки для моего кода, которые позволили бы приблизится к чему-то среднему между нашими вариантами, если мой нельзя воспроизвести на D.
Нечто отдалённо похожее записывается на D вообще в одну строчку:
Этот код не отжирает память вообще и при этом работает несколько секунд. Но это работа с мутабельными данными.
Если же очень хочется устроить тестирование GC в D, то для этого достаточно заменить "~=" на "~" в коде выше — получим постоянные создания новых структур. Но, т.к. реализация GC в D совсем другая, то и последствия другие — память опять же не будет отжираться, а вот быстродействие существенно упадёт.
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И гугл вот тоже выдаёт исключительно псевдокод по запросу на "алгоритм". )))
Гугл, разумеется, много чего выдаст на эту тему, но на практике я никогда не сталкивался со сколько-нибудь масштабным использованием UML-диаграмм для записи алгоритмов, что не может не радовать.
_>Модули — это уже другая uml диаграммка, как раз та, про которую я сказал, что чуть ли не единственная нормально применимая в чистом ФП. И это инструмент совсем другого уровня детализации.
Нет, модули в ФЯ это инструмент как раз того же уровня детализации, как и классы в ООЯ. На вашу "уже другую UML диаграмму" они не ложатся.
K>>Во-вторых, мне непонятно противопоставление "всего-навсего типов" и "ого-го всей архитектуры". _>Намекаю: где на диаграмме можно увидеть полный набор функций проектируемой программы и их взаимодействие между собой?
Не понял намека. Вы не намекайте, а прямо скажите, в чем в данном случае разница.
_>Нууу её в Хаскеле просто нет. )))
Правда что-ли? В вашем воображаемом хаскеле чего не возьми — ничего нет.
Но в реально существующем хаскеле ситуация другая.
_>И тем не менее физики обычно знают о чём говорят, в отличие от вас. )
А при чем тут я? Очевидными-то сейчас вы называете всякие потусторонние вещи, которые процитировать нельзя, на которые сослаться нельзя. Про них можно только подмигивать и улыбаться.
_>Я вот всё думал, что мне напоминает эта наша дискуссия...
Вы, конечно, искрометно спародировали сейчас ход нашей дискуссии.
— Покажите монадные ужасы.
— Дискутировал я как-то про Украину...
Смех смехом, но вы обычно, конечно, съезжаете с темы не так далеко.
Впрочем, есть идея: если в разговоре про мифические монадные ужасы вы про Украину пишете — не исключено, что когда с вами про Украину дискутируют — вы приводите кучу ссылок на монадные ужасы и множество примеров кода. Надо будет проверить ваши посты в политике, заодно и недоумевающих оттуда сюда перенаправлю. А то они бедняжки, наверняка, никак не могут понять — при чем же тут монады.
_>И снова прямое передёргивание. Я говорил, что языки "хороши в какой-то определённой области", а не созданы исключительно для неё.
Тут как раз разница минимальна. "хороши" / "созданы для". Принципиальная разница между вашей "определенной областью" и моим "широким спектром областей с кое-какими исключениями". У языков общего назначения "определенной области" нет. Не удивительно, что на мой вопрос об "определенной области" для C++ вы ничего не ответили.
_>Причём тут вообще график то? Я говорю про данные для него, которые там везде указаны.
ОК, посмотрите на данные (кол-ва измененных строк и заданных вопросов) и посмотрите сколько их у одних языков и у других. И представьте их в виде точек на графике у которого шкалы не логарифмические. Теперь понятно причём тут логарифм?
_>Очаровательные рассуждения) Только проведены они совсем не для тех данных, которые вызывают сомнения...
Да какая разница, действие эффекта от этого не изменится.
_>В данном случае то проблем нет.
Отлично.
_>А вот что у нас получается для расклада: Сартр написана одна строчка на гитхабе и 100 вопросов на СО, а на языке Антракс 10000 строк на гитхабе и 1 вопрос на СО? Если посчитано честное среднее, то оба языка будут рядом в рейтинге.
Но они не окажутся рядом на графике. И вообще вблизи линии тренда. Т.е. по одному взгляду на график будет видно: с ними что-то не то, это "выбросы". Впрочем, на том же графике видно, что такое случается либо с совсем уже редкими языками — это облако точек в нижней левой части, либо вообще не языками программирования вроде XML — один из немногих "выбросов" в верхней правой части графика.
_>Однако рейтинг данных товарищей для подобных случаев однозначно показывает преимущество Сартра...
Ну так и даже понятно почему. Поэтому я уже в 256 предыдущих сообщениях писал — рейтинг с процентами не нужен — смотрите на график.
_>Совершенно верно. И данной свойство является чем-то вроде аналитического продолжения классического понятия чистоты на мутабельные данные.
А смысл в этом какой? Ну "продолжили" мы чистоту до ее отсутствия, теперь проверяем что-то чистотой функции не являющееся. Дальше-то что? В чем отличие от ситуации, когда мы это странное "продолжение" не проверяем?
_>Т.к. в случае иммутабельных данных имеем полное соответствие с чистотой из Хаскеля.
Ну да. Только компилятор позволяет аннотировать pure и в тех случаях, когда данные мутабельны. Или нет?
_>Гарантию отсутствия побочных эффектов.
Но ведь этой гарантии нет. Если бы проверялась иммутабельность — она бы была. Но иммутабельность не проверяется.
_>Ну так это получается тест не на поддержку иммутабельности, а на скорость GC и т.п.
Ну, правильно. Поддержка иммутабельности заключается в:
1) Проверки компилятора. (как уже выяснилось, что-то проверяется, да только не то)
2) Поддержка рантайма. А это процентов на 90% скорость GC, остальное — всякая экзотика.
3) Оптимизации компилятора — т.е. выкидывание ненужных аллокаций, для которых мы можем статическим анализом ненужность определить.
Поэтому тест на поддержку иммутабельности — это "на скорость GC и т.п.". А что он по-вашему должен проверять?
_>Т.е. я не вижу разницы в подобном тесте для мутабельных и для иммутабельных данных, т.к. непонятно какие оптимизации может тут добавить компилятор для иммутабельных данных — пересоздание структур будет происходить в любом случае и будет занимать основное время.
Оптимизации компилятор может добавить — это например дефорестация и эскейп-анализ. Я же говорю, при выключенных оптимизациях и при включенных время работы и объемы аллокаций отличаются в десятки раз.
_>Задачка понятна, но не ясно где в ней логично использовать иммутабельные данные.
Иммутабельные данные в ней логично использовать везде. Потому, что мы проверяем поддержку иммутабельных данных. Было бы странно испытывать поддержку иммутабельных, а использовать мутабельные, нес па?
_>Собственно сам факт захвата 16 гигов оперативки однозначно свидетельствует о чудовищной не оптимальности подхода с иммутабельными данными.
Нет никакого захвата 16 гигов оперативки. Есть размещение 16 Гб объектов в куче. Не одновременно, а последовательно. Одновременно в памяти не больше 16 Мб.
_>Нечто отдалённо похожее записывается на D вообще в одну строчку: _>
У вас тут смешивается "библиотечная" часть, которая простые числа считает и "пользовательская", которая знает что вам нужны только те, что не больше 2^^24
_>Этот код не отжирает память вообще
В астрале что-ли простые числа хранит?
_>и при этом работает несколько секунд.
Нормально. И мой пример несколько секунд работает.
_>Но это работа с мутабельными данными.
Ну так сделайте такой, который работает с иммутабельными данными.
_>для этого достаточно заменить "~=" на "~" в коде выше
Сильно сомневаюсь в этом. Что, диапазоны/итераторы/или что там в D, которые тут для организации конвейера использованы — иммутабельные?
_>Но, т.к. реализация GC в D совсем другая, то и последствия другие — память опять же не будет отжираться,а вот быстродействие существенно упадёт.
Ну, то есть иммутабельность в D не поддерживается. Что и требовалось доказать.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[66]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Этот код не отжирает память вообще и при этом работает несколько секунд. Но это работа с мутабельными данными.
Этот вариант выдает неверный ответ — на 1 меньше, т.к. забыл простое число "2". Я добавил двойку к тройке (скорость заметно упала при этом, т.к. больше ненужных делений делается), сравнил:
Glasgow Haskell Compiler, Version 7.6.3, stage 2 booted by GHC version 7.6.3
$ ghc prs.hs -o prs -O2
$ time ./prs
1077871
real 0m16.089s
user 0m15.980s
sys 0m0.076s
-------------------------------------------------------------------------------
DMD64 D Compiler v2.065
$ dmd prs.d -ofprsd -O -release -inline
$ time ./prsd
1077871
real 0m9.370s
user 0m9.352s
sys 0m0.000s
Сперва в DMD забыл указать -inline, получилось 19 с лишним секунд — медленнее однопоточного хаскеля.
Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Если в хаскельном варианте заменить самописные filter, all, takeWhile на стандартные библиотечные, работает 18.5 секунд, т.е. процентов на 10 медленнее.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Гугл, разумеется, много чего выдаст на эту тему, но на практике я никогда не сталкивался со сколько-нибудь масштабным использованием UML-диаграмм для записи алгоритмов, что не может не радовать.
Подчёркиваю: запрос был не на слово "диаграмма", а на слово "алгоритм"...
K>Нет, модули в ФЯ это инструмент как раз того же уровня детализации, как и классы в ООЯ. На вашу "уже другую UML диаграмму" они не ложатся.
Ну так это в ФЯ, а в uml диаграмма пакетов выглядит совсем по другому и служит для других целей. Т.е. собственно как я и говорил, для ФЯ uml подходит слабо.
K>Не понял намека. Вы не намекайте, а прямо скажите, в чем в данном случае разница.
Я вроде бы достаточно точно сформулировал: где на диаграмме можно увидеть полный набор функций и их взаимодействие между собой? Ведь в ФП именно это во многом задаёт архитектуру приложения.
K>Правда что-ли? В вашем воображаемом хаскеле чего не возьми — ничего нет. K>Но в реально существующем хаскеле ситуация другая.
Ну так тогда наверное можно посмотреть на примеры инкапсуляции? )
K>Тут как раз разница минимальна. "хороши" / "созданы для". Принципиальная разница между вашей "определенной областью" и моим "широким спектром областей с кое-какими исключениями". У языков общего назначения "определенной области" нет. Не удивительно, что на мой вопрос об "определенной области" для C++ вы ничего не ответили.
Повторюсь ещё раз. У C++ (как и у других ему подобных), есть область, в которой он очевидный лидер. Плюс его можно вполне эффективно использовать во многих других областях, но там у него будут сильные конкуренты, использование которых часто более оправдано.
K>ОК, посмотрите на данные (кол-ва измененных строк и заданных вопросов) и посмотрите сколько их у одних языков и у других. И представьте их в виде точек на графике у которого шкалы не логарифмические. Теперь понятно причём тут логарифм?
Мне всегда было очевидно почему так построен график — для удобства просмотра. Но мне не понятно с каких это оснований мы должны в анализе использовать логарифмы.
K>Но они не окажутся рядом на графике. И вообще вблизи линии тренда. Т.е. по одному взгляду на график будет видно: с ними что-то не то, это "выбросы". Впрочем, на том же графике видно, что такое случается либо с совсем уже редкими языками — это облако точек в нижней левой части, либо вообще не языками программирования вроде XML — один из немногих "выбросов" в верхней правой части графика.
C и скажем C# как раз являются примером подобных данных, разве что не настолько контрастных (хотя на мой взгляд "в 5 раз" — это очень не слабо). Совсем не редкие или ненормальные языки.
K>Ну так и даже понятно почему. Поэтому я уже в 256 предыдущих сообщениях писал — рейтинг с процентами не нужен — смотрите на график.
Ну хотя бы в одном мы пришли к общему мнению: рейтинг языков от данных товарищей является фуфлом.
K>А смысл в этом какой? Ну "продолжили" мы чистоту до ее отсутствия, теперь проверяем что-то чистотой функции не являющееся. Дальше-то что? В чем отличие от ситуации, когда мы это странное "продолжение" не проверяем?
Я ответил на это ещё в предыдущем сообщение (чуть ниже цитируемого).
K>Ну да. Только компилятор позволяет аннотировать pure и в тех случаях, когда данные мутабельны. Или нет?
Естественно позволяет, иначе не получилось бы продолжение. ) Но и хаскелевскую чистоту мы получаем в D одним движением руки.
K>Но ведь этой гарантии нет. Если бы проверялась иммутабельность — она бы была. Но иммутабельность не проверяется.
А какие побочные эффекты возможны с мутабельными параметрами? )
K>Ну, правильно. Поддержка иммутабельности заключается в: K>1) Проверки компилятора. (как уже выяснилось, что-то проверяется, да только не то)
Ээээм, вроде как претензии были к модификатору pure, а не к модификатору immutable. Или уже и к нему что-то нашлось? )))
K>2) Поддержка рантайма. А это процентов на 90% скорость GC, остальное — всякая экзотика.
Ну скорость GC конечно тоже можно померять (хотя лично я, кодируя в стиле C++, обычно не особо использую GC и в D)... Только тогда это прямо так и надо называть. А не говорить про "тестирование иммутабельности". Потому как последнее означает сравнение скорости с данным модификатором или без него (но в любом случае с GC), а не сравнение насилования GC против нормального кода.
K>3) Оптимизации компилятора — т.е. выкидывание ненужных аллокаций, для которых мы можем статическим анализом ненужность определить.
Работа в статике у D думаю одна из самых сильных вообще. Хотя это сделано для несколько других целей. )
K>Поэтому тест на поддержку иммутабельности — это "на скорость GC и т.п.". А что он по-вашему должен проверять?
В случае D это должно быть что-то связанное именно с этим модификатором. Потому как GC используется и с мутабельными данными.
K>Иммутабельные данные в ней логично использовать везде. Потому, что мы проверяем поддержку иммутабельных данных. Было бы странно испытывать поддержку иммутабельных, а использовать мутабельные, нес па?
Да, но тестовый пример же мы сами выбираем и логично выбрать такой, в котором использование иммутабельных данных будет не искусственно введённой ересью, а чем-то приносящим реальную пользу. В данном случае на код насилующий память попусту просто противно смотреть.
K>Нет никакого захвата 16 гигов оперативки. Есть размещение 16 Гб объектов в куче. Не одновременно, а последовательно. Одновременно в памяти не больше 16 Мб.
А, ну значит я неправильно понял. Собственно я так и думал, что не может быть настолько всё плохо и где-то нестыковка.
_>>для этого достаточно заменить "~=" на "~" в коде выше K>Сильно сомневаюсь в этом. Что, диапазоны/итераторы/или что там в D, которые тут для организации конвейера использованы — иммутабельные?
Нет, не иммутабельные, хотя это тоже тривиально добавляется (просто модификатор к начальному списку, а остальное всё автоматом через шаблоны). Просто здесь мы включаем насилие над GC (постоянное пересоздание структур), в то время как код с "~=" производит модификацию одной начальной структуры и соответственно GC практически не напрягается.
K>Ну, то есть иммутабельность в D не поддерживается. Что и требовалось доказать.
Хы, т.е. не поддерживается — это означает что код насилующий GC отстаёт от кода не делающего этого? ) Ну так в таком случае в Хаскеле иммутабельность тоже не поддерживается, т.к. его код тоже отстаёт от варианта не насилующего GC.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Этот вариант выдает неверный ответ — на 1 меньше, т.к. забыл простое число "2". Я добавил двойку к тройке (скорость заметно упала при этом, т.к. больше ненужных делений делается), сравнил:
1. Ну с двойкой — это я просто не люблю писать очевидно неэффективный код. )))
2. Вообще то это совсем не самый быстрый код. Изначально я написал тупой императивный вариант в лоб:
Так вот у меня он работает приблизительно в 2 раза быстрее варианта через reduce. Но его нельзя одним движением превратить в вариант насилующий GC, так что я переписал его в более функциональном стиле, который и показал здесь.
DM>Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
Кстати, здесь должен SIMD рулить ещё. Но я его в D не умею (только в C++), а сам dmd похоже тоже не умеет. Вот очень интересно было бы сравнить результаты на компиляторе gdc — тот же умеет simd автоматический (если правильные ключи указать).
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>По идее, он в плане насилия над GC ничем не должен отличаться, вся разница в скорости из-за плохого инлайнера и оптимизатора, код с рэнджами тормозит.
Ну да, здесь всё дело в оптимизаторе (поэтому опять же интересно было бы взглянуть на результаты работы gdc). А насилие над GC включается, если мы меняем "~=" на "~" — это как раз получается по сути некий тест GC, как в коде на Хаскеле.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>(поэтому опять же интересно было бы взглянуть на результаты работы gdc)
Поставил gdc-4.8, длинный вариант с isPrime ускорился с 2.9 до 2.5 сек. Короткий вариант на рэнджах не скомпилился, жалуется
/usr/include/d/4.8/std/functional.d:184: Error: function prs.main.__lambda3!(int[], int).__lambda3.not!(__lambda7).not!(int).not is a nested function and cannot be accessed from find
Завтра попробую еще поиграться.
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Поставил gdc-4.8, длинный вариант с isPrime ускорился с 2.9 до 2.5 сек. Короткий вариант на рэнджах не скомпилился, жалуется DM>/usr/include/d/4.8/std/functional.d:184: Error: function prs.main.__lambda3!(int[], int).__lambda3.not!(__lambda7).not!(int).not is a nested function and cannot be accessed from find
DM>Завтра попробую еще поиграться.
Не знаю какие там опции нормально подходят. Но если он полностью проглотит опции от gcc, то я бы попробовал что-то вроде: -march=native -O2 -finline-functions -ftree-vectorize -flto
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>1. Ну с двойкой — это я просто не люблю писать очевидно неэффективный код. )))
И при этом ты написал очевидно неэффективный алгоритм. Простые числа больше 3х могут быть найдены исключительно в 6*N +- 1, например 19 это 6*3 + 1, 29 это 6*5 — 1
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Подчёркиваю: запрос был не на слово "диаграмма", а на слово "алгоритм"...
Это было понятно с самого начала. Ответ тот же.
_>Ну так это в ФЯ, а в uml диаграмма пакетов выглядит совсем по другому и служит для других целей.
Пакеты — это пакеты, а модули — это модули.
На что это:
signature OrdSig =
sig
type Item
val > : Item * Item -> bool
end;
structure IntItem =
struct
type Item = int
val op == = (op = : int * int -> bool)
val op > = (op > : int * int -> bool)
end;
больше похоже: на интерфейс и класс или на какие-то "пакеты"?
_>Т.е. собственно как я и говорил, для ФЯ uml подходит слабо.
Причем обосновываете вы это тем, что не знаете про средства организации кода в ФЯ. Это, конечно, ставит на них крест.
_>Я вроде бы достаточно точно сформулировал: где на диаграмме можно увидеть полный набор функций и их взаимодействие между собой? Ведь в ФП именно это во многом задаёт архитектуру приложения.
А где это можно на диаграмме в случае ООЯ увидеть? Вот там же и в случае ФЯ. В чем разница-то?
_>Ну так тогда наверное можно посмотреть на примеры инкапсуляции? )
Есть как самый обычный и привычный для любого ОО-программиста инструментарий в виде объявлений функций/конструкторов публичными или приватными, так и средства инкапсуляции менее привычные либо с ней у ОО-программиста вовсе не ассоциирующиеся вроде экзистенциальных типов/параметрического полиморфизма и замыканий/частичного применения.
_>Повторюсь ещё раз.
Видимо это означает, что вы опять не назовете "определенную область" C++
_>У C++ (как и у других ему подобных), есть область, в которой он очевидный лидер.
Так и вышло. "У нас есть конкретная область, но мы вам о ней не расскажем."
_>Мне всегда было очевидно почему так построен график — для удобства просмотра. Но мне не понятно с каких это оснований мы должны в анализе использовать логарифмы.
Тяжелый случай. Ладно, представьте, что вы стоите перед телевизором, подключенным к ресиверу. Вы поворачиваете ручку регулятора громкости и видите на индикаторе, как он меняется с -40 на -30 и вы слышите, как по телевизору говорят: "у восточного побережья Швамбрании произошло землетрясение магнитудой 7 с афтершоками магнитудой 5".
Почему на индикаторе было не 0.0001 и 0.001, а по телевизору не сказали "магнитудой 10000000 и 100000"? Никаких графиков же не было!
_>C и скажем C# как раз являются примером подобных данных
Конечно не являются.
_>разве что не настолько контрастных (хотя на мой взгляд "в 5 раз" — это очень не слабо).
Нет, 5 раз это очень слабо, когда разница бывает в 1000 раз и даже больше.
_>Ну хотя бы в одном мы пришли к общему мнению: рейтинг языков от данных товарищей является фуфлом.
"Фуфлом" является агрегат по процентам, а рейтинг в широком смысле "фуфлом" не является. С другой стороны TIOBE является "фуфлом" и в широком и в узком и в каком угодно другом смысле.
_>Я ответил на это ещё в предыдущем сообщение (чуть ниже цитируемого).
Этот ответ основывался на ложном утверждении, что какая-то гарантия есть.
_>Естественно позволяет, иначе не получилось бы продолжение. ) Но и хаскелевскую чистоту мы получаем в D одним движением руки.
Каким движением, если компилятор считает, что код, который чистым не является вовсе — чистый?
_>А какие побочные эффекты возможны с мутабельными параметрами? )
Любые, разумеется.
_>Ээээм, вроде как претензии были к модификатору pure, а не к модификатору immutable. Или уже и к нему что-то нашлось? )))
Так именно чистота, гарантируемая компилятором и нужна, а не какие-то "модификаторы". Вот есть у вас "модификатор" immutable и какой от него толк помимо упомянутых дрессировки программиста и чувства глубокого удовлетворения? Компилятор-то тут все равно бессилен, ничего интересного он не наоптимизирует.
_>Ну скорость GC конечно тоже можно померять (хотя лично я, кодируя в стиле C++, обычно не особо использую GC и в D)...
Ну так в том и дело, как обычно на D программируют. Вы декларируете некую "поддержку", а потом сами же заявляете о ее невостребованности. Широкое использование иммутабельных структур данных приводит к выделению памяти для зиллионов объектов в секунду и с этим нужно что-то делать, чтоб это работало с приемлемой скоростью. Если же иммутабельные структуры не использовать, а кодировать "в стиле C++" — то уже все равно по большей части какой там GC.
_>Только тогда это прямо так и надо называть. А не говорить про "тестирование иммутабельности". Потому как последнее означает сравнение скорости с данным модификатором или без него (но в любом случае с GC),
Ничего не понял. У вас все, похоже, сводится к тому, что можно какой-то модификатор где-то поставить. Ну вот есть у вас структура мутабельная, там вы все по месту переписываете, а есть структура иммутабельная и она персистентна, вы при каких-то операциях с ней возвращаете новую версию, а старая сохраняется. Вы же понимаете последствия этого и как с ними можно справляться? Вот именно возможности свести отрицательные последствия к минимуму я и называю поддержкой иммутабельности. Она позволяет пользоваться плюсами на практике сводя минусы к приемлемому уровню.
_>а не сравнение насилования GC против нормального кода.
Ну, не выдумывайте. Никакого насилия над сборщиком тут нет. В моем примере сборщик ~2% времени работает. Процент выживаемости-то низкий, работа в тепличных условиях. Так что любой точный, компактифицирующий сборщик на этом тесте себя нормально покажет, даже написанный школьником копирующий сборщик Чейни. Надо было, конечно, придумать тест потруднее, чтоб выгода от поколений была и т.д.
_>Работа в статике у D думаю одна из самых сильных вообще. Хотя это сделано для несколько других целей. )
Я очень рад за вас и за Уолта, но в данном случае, когда мы обсуждаем поддержку иммутабельности, имеет смысл продемонстрировать такую работу для обсуждаемых целей, а не каких-то "других".
_>В случае D это должно быть что-то связанное именно с этим модификатором. Потому как GC используется и с мутабельными данными.
Ну так что?
_>Да, но тестовый пример же мы сами выбираем и логично выбрать такой, в котором использование иммутабельных данных будет не искусственно введённой ересью, а чем-то приносящим реальную пользу.
А, ну конечно. Ненужность кода не позволяет адекватно оценить производительность, потому что если код нужный, то Боги Полезности наполнят вычислитель духовной силой Всеобщего Блага и тот, разогнавшись до 1024ГГц, все посчитает просто мгновенно!
_>В данном случае на код насилующий память попусту просто противно смотреть.
Мои соболезнования. И спасибо, что сами вы никакой с иммутабельными данными работающий код не продемонстрировали, пожалели меня. На него ведь так тяжело смотреть!
_>Просто здесь мы включаем насилие над GC (постоянное пересоздание структур), в то время как код с "~=" производит модификацию одной начальной структуры и соответственно GC практически не напрягается.
Обратите внимание, что почти все функции в моем примере принимают на вход иммутабельный список и возвращают иммутабельный список. Это никакие не итераторы-диапазоны. Это функции, работающие с неизменяемой структурой данных, что мы и проверяем. Не итераторы, а списки. Если вы просто сделаете одну единственную коллекцию с простыми числами иммутабельной — аналогом моего кода ваш не станет. Он станет если: 1) все функции в конвейере будут принимать и возвращает иммутабельные структуры данных и 2) количество "стадий" конвейера будет сопоставимо. Я старался их сделать побольше, вы же наоборот на них экономите, это цели теста не соответствует.
_>Хы, т.е. не поддерживается — это означает что код насилующий GC отстаёт от кода не делающего этого? ) Ну так в таком случае в Хаскеле иммутабельность тоже не поддерживается, т.к. его код тоже отстаёт от варианта не насилующего GC.
Нет, код, создающий новые экземпляры и выделяющий память, конечно, обычно медленнее, чем код, меняющий на месте. Речь идет о том, чтоб уменьшить эту разницу до более-менее приемлемой.
Попробуйте написать аналог моего кода, тогда и посмотрим.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
DM>Сперва в DMD забыл указать -inline, получилось 19 с лишним секунд — медленнее однопоточного хаскеля.
Неплохо! Заметно, что для авторов библиотеки не безразлично насколько быстро "конвейеры" работают (большая редкость, на самом деле).
И заметно, что компилятор что-то оптимизирует. Непонятно только, почему -O не подразумевает -inline.
DM>Убунта 64 бита, Core i3 2.4 GHz (2 cores * 2 threads) DM>Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
Что тут странного, многопоточность никак не используется, а оверхед многопоточный рантайм добавляет. Тут только странно, что с -N2 всего на секунду больше — обычно оверхед заметнее. Ну и в том, что при -N4 на двух ядрах тормоза — удивительного еще меньше. Лучшая производительность вообще обычно достигается если указывать n-1 для n-ядерного или n для n-ядерного с гипертредингом.
DM>Если в хаскельном варианте заменить самописные filter, all, takeWhile на стандартные библиотечные, работает 18.5 секунд, т.е. процентов на 10 медленнее.
Это упомянуто мной прямо в посте с кодом теста (у меня разница, впрочем, получилась больше). И даже написано почему так происходит.
А код на D быстрее заработает, если лапшевые имплементации функций заменить на комбинирование комбинаторов?
И не могли бы вы замерить, как быстродействие реагирует на увеличение числа "стадий" "конвейера"?
И не могли бы вы еще и написать более близкий аналог хаскельного примера — а то я подозреваю, что мой оппонент может еще 2-3 месяца легко разговор поддерживать прежде чем до такого кода дело дойдет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
DM>>Если вариант на хаскеле собрать с -threaded (многопоточный рантайм) и запустить с +RTS -N4 -RTS, работает вдвое дольше (32 с), а если с -N2, то всего на секунду дольше (17.3 с). Чудеса автопараллелизма!
K>Что тут странного, многопоточность никак не используется, а оверхед многопоточный рантайм добавляет.
В том примере активно насилуется сборщик мусора, а он в многопоточном варианте должен быть сильно быстрее однопоточного. А еще мог бы работать хотя бы отчасти параллельно основному потоку. Поэтому я все же ожидал увидеть ускорение. Попробую еще с -N3...
Или там особые ключи нужны для параллельной сборки мусора?
K>А код на D быстрее заработает, если лапшевые имплементации функций заменить на комбинирование комбинаторов? K>И не могли бы вы замерить, как быстродействие реагирует на увеличение числа "стадий" "конвейера"?
Позже попробую. Но в принципе уже сейчас по двум примерам видно, что код на рэнджевых комбинаторах втрое медленнее дубового на циклах. И чем больше комбинаторов наворачивать, тем оно обычно медленнее, а потом и вовсе инлайнер ломается (пару версий компилятора назад сталкивался на некоторых проектах).
K>И не могли бы вы еще и написать более близкий аналог хаскельного примера
С ленивым построением связного списка что-ли? Думаю, там в разы медленнее выйдет.
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>В том примере активно насилуется сборщик мусора, а он в многопоточном варианте должен быть сильно быстрее однопоточного.
Рассуждение было бы верным, если бы сборщик действительно работал заметное время. Но это не так. Можете сами посмотреть, запустив с +RTS -s
У меня вот что:
16,022,855,308 bytes allocated in the heap
56,525,316 bytes copied during GC
16,944,480 bytes maximum residency (7 sample(s))
1,360,536 bytes maximum slop
35 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 30624 colls, 0 par 0.08s 0.15s 0.0000s 0.0006s
Gen 1 7 colls, 0 par 0.03s 0.05s 0.0071s 0.0235s
INIT time 0.00s ( 0.00s elapsed)
MUT time 8.58s ( 8.52s elapsed)
GC time 0.11s ( 0.20s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 8.70s ( 8.72s elapsed)
%GC time 1.3% (2.2% elapsed)
Alloc rate 1,867,873,842 bytes per MUT second
Productivity 98.7% of total user, 98.5% of total elapsed
Ключевые данные выделены.
Никакого насилия. При проведении теста ни один сборщик не пострадал.
DM>А еще мог бы работать хотя бы отчасти параллельно основному потоку. Поэтому я все же ожидал увидеть ускорение.
Нет, он параллельно основному потоку не работает, он stop-the-world. Останавливает все потоки мутатора и собирает параллельно, загружая несколько ядер.
DM>Позже попробую. Но в принципе уже сейчас по двум примерам видно, что код на рэнджевых комбинаторах втрое медленнее дубового на циклах. И чем больше комбинаторов наворачивать, тем оно обычно медленнее, а потом и вовсе инлайнер ломается (пару версий компилятора назад сталкивался на некоторых проектах).
А что и где можно почитать про дишные диапазоны и оптимизацию кода с ними?
K>>И не могли бы вы еще и написать более близкий аналог хаскельного примера DM>С ленивым построением связного списка что-ли?
Да.
DM>Думаю, там в разы медленнее выйдет.
Ну, чего-то такого я и ожидаю, но интереснее получить замер, а не какие-то предположения строить.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[69]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Пакеты — это пакеты, а модули — это модули. K>На что это: K>... K>больше похоже: на интерфейс и класс или на какие-то "пакеты"?
Интерфейсы или классы должны иметь свои экземпляры. А если их нет, то это уже скорее просто некие пространства имён или же вообще пакеты.
Ну и главное: мы же обсуждаем не языки вообще, а в контексте uml. Так вот там есть строго определённые виды диаграмм (классов, пакетов и т.п.), наборы сущностей (классы, пакеты и т.п.) и виды взаимосвязей между ними. Т.е. в любом случае, если захочется пользоваться инструментарием uml (а он весьма развитый и удобный сейчас), то придётся как-то укладываться в эти правила, а не придумывать новые. Так вот у ФП с этим большие сложности...
K>Причем обосновываете вы это тем, что не знаете про средства организации кода в ФЯ. Это, конечно, ставит на них крест.
Пока эти средства не введены в uml, действительно имеем тут крест.
K>А где это можно на диаграмме в случае ООЯ увидеть? Вот там же и в случае ФЯ. В чем разница-то?
В ООП программе архитектуру приложения обычно задают классы/объекты (который отлично видны на диаграммке классов, вместо со всеми своими методами), а не глобальные функции...
K>Так вы уже посмотрели. Вот прямо в этом треде пример использования инкапсуляции приводится в объяснении устройства IO http://rsdn.ru/forum/philosophy/5384654.1
И кто нам помешает написать свою функцию, работающую как угодно с данными IO? )
K>Есть как самый обычный и привычный для любого ОО-программиста инструментарий в виде объявлений функций/конструкторов публичными или приватными, так и средства инкапсуляции менее привычные либо с ней у ОО-программиста вовсе не ассоциирующиеся вроде экзистенциальных типов/параметрического полиморфизма и замыканий/частичного применения.
Ничего подобного нет. Максимум что есть, это та самая структура модулей. В которой реализуется инкапсуляция уровня языка C (типа функции реализованной в .c файле, но не объявленной в .h файле).
Ну и конечно же замыкания (которые кстати везде есть) — не зря же их называют "объектами для бедных". )))
K>Видимо это означает, что вы опять не назовете "определенную область" C++
Вы не знаете области, в которых C++ является очевидным лидером? ) Это забавно для данного форума... )
K>Тяжелый случай. Ладно, представьте, что вы стоите перед телевизором, подключенным к ресиверу. Вы поворачиваете ручку регулятора громкости и видите на индикаторе, как он меняется с -40 на -30 и вы слышите, как по телевизору говорят: "у восточного побережья Швамбрании произошло землетрясение магнитудой 7 с афтершоками магнитудой 5". K>Почему на индикаторе было не 0.0001 и 0.001, а по телевизору не сказали "магнитудой 10000000 и 100000"? Никаких графиков же не было!
Причины измерения уровней подобных энергетических величин (типа громкости звука и т.п.) в децибелах имеет вполне определённую природную причину — восприятие этих величин человеческими чувствами. Так что тут всё нормально как раз, причём вне зависимости от порядка величины (измеряют в децибелах и при незначительном изменение мощности).
Но никто не употребляет логарифмы просто так везде или скажем просто для больших величин. Никто не говорит, что например солнце больше земли на 20 децибел.
Так какие у нас обоснования для применения логарифмов при обсуждение количества вопросов о данном языке на SO?
K>Нет, 5 раз это очень слабо, когда разница бывает в 1000 раз и даже больше.
Разница в 1000 раз есть только между мейнстримом и маргинальными языками. А внутри группы мейнстрима как раз наблюдается разница "в разы".
K>Каким движением, если компилятор считает, что код, который чистым не является вовсе — чистый?
Это уже просто вопрос терминологии. Компилятор прекрасно знает какая именно чистота подразумевается тут.
_>>А какие побочные эффекты возможны с мутабельными параметрами? ) K>Любые, разумеется.
Ждём демонстрацию)
K>Так именно чистота, гарантируемая компилятором и нужна, а не какие-то "модификаторы". Вот есть у вас "модификатор" immutable и какой от него толк помимо упомянутых дрессировки программиста и чувства глубокого удовлетворения? Компилятор-то тут все равно бессилен, ничего интересного он не наоптимизирует.
Ну это смотря в каком языке. ) Если мы говорим про D, то все величины без всяких модификаторов расположены в памяти конкретного потока (т.е. у каждого потока своя копия). Величины с модификатором share расположены в общей памяти (т.е. одна копия на все потоки), но при этом доступ к ним сопровождается соответствующми блокировками. А вот в случае модификатора immutable мы имеем естественно одну копию на всех, но с доступом без всяких блокировок.
K>Ну так в том и дело, как обычно на D программируют. Вы декларируете некую "поддержку", а потом сами же заявляете о ее невостребованности. Широкое использование иммутабельных структур данных приводит к выделению памяти для зиллионов объектов в секунду и с этим нужно что-то делать, чтоб это работало с приемлемой скоростью. Если же иммутабельные структуры не использовать, а кодировать "в стиле C++" — то уже все равно по большей части какой там GC.
Всё правильно. Только иммутабельные структуры весьма полезны и при кодирование в стиле C++. Ну а проработка возможности выделения "зиллионов объектов в секунду" для языка ориентированного на быстродействие весьма странно — в любом случае (даже с самым гениальным GC) такой код будет заметно медленнее работы со статическим выделением.
K>Ничего не понял. У вас все, похоже, сводится к тому, что можно какой-то модификатор где-то поставить. Ну вот есть у вас структура мутабельная, там вы все по месту переписываете, а есть структура иммутабельная и она персистентна, вы при каких-то операциях с ней возвращаете новую версию, а старая сохраняется. Вы же понимаете последствия этого и как с ними можно справляться? Вот именно возможности свести отрицательные последствия к минимуму я и называю поддержкой иммутабельности. Она позволяет пользоваться плюсами на практике сводя минусы к приемлемому уровню.
Приемлемым этот уровень пока что бывает только в теории. )
_>>В случае D это должно быть что-то связанное именно с этим модификатором. Потому как GC используется и с мутабельными данными. K>Ну так что?
Так вот я и не знаю что) У меня в коде широко используются иммутабельные данные, но я не особо представляю как померить "производительность" этого. Т.к. используются они таким образом, что замена их на мутабельные не приводит к увеличению быстродействия (а часто даже наоборот). Т.е. при таком использование вопрос о "поддержке иммутабельности" (подразумевая снижение цены за это) вообще не стоит, т.к. это наоборот выгоднее даже.
Да, вот в вашем примере переход на мутабельные данные вызывает ускорение на порядок — действительно есть большой простор для измерения цены поддержки. Но на мой вкус я лучше буду просто использовать мутабельные данные в такой задаче.
K>Обратите внимание, что почти все функции в моем примере принимают на вход иммутабельный список и возвращают иммутабельный список. Это никакие не итераторы-диапазоны. Это функции, работающие с неизменяемой структурой данных, что мы и проверяем. Не итераторы, а списки. Если вы просто сделаете одну единственную коллекцию с простыми числами иммутабельной — аналогом моего кода ваш не станет. Он станет если: 1) все функции в конвейере будут принимать и возвращает иммутабельные структуры данных и 2) количество "стадий" конвейера будет сопоставимо. Я старался их сделать побольше, вы же наоборот на них экономите, это цели теста не соответствует.
Как раз последовательность работающую с диапазонами в D можно делать произвольной длинны — разница будет не очень существенная. Заметное замедление происходит только в точке пересоздание списка чисел.
K>Нет, код, создающий новые экземпляры и выделяющий память, конечно, обычно медленнее, чем код, меняющий на месте. Речь идет о том, чтоб уменьшить эту разницу до более-менее приемлемой. K>Попробуйте написать аналог моего кода, тогда и посмотрим.
Так уже всё написали же и измерили. И результаты говорят сами за себя. Если взять код на D работающий по месту за приемлемое быстродействие (хотя думаю переписав его на C++ получим ещё более быстрый код), то:
— код на Хаскеле (естественно размножающий данные) работает в 6-7 раз медленнее.
— код на D размножающий данные работает раз в 15 медленнее. Причём это не зависит от того, используем мы immutable данные или нет.
Да, наверное если добавить специальную оптимизацию для работы с immutable данными, то соответствующий код на D догонит вариант на Хаскеле. Но фокус в том, что и такое быстродействие абсолютно не приемлемо по сравнению с вариантом модифицирующим данные.
Кстати, интересный нюанс. В D одинаково легко записываются оба вида кода (причём он получается практически одинаковый и в одну строку). А интересно как будет выглядеть код на Хаскеле, работающий по принципу модификации одного набора данных? )
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
DM>>Поставил gdc-4.8, длинный вариант с isPrime ускорился с 2.9 до 2.5 сек.
_>Не знаю какие там опции нормально подходят. Но если он полностью проглотит опции от gcc, то я бы попробовал что-то вроде: -march=native -O2 -finline-functions -ftree-vectorize -flto
C -flto он поперхнулся (lto1: internal compiler error: in streamer_get_pickled_tree, at tree-streamer-in.c:1050
Please submit a full bug report), а без -flto остальные опции принял молча, однако быстрее программа не стала. Те же 2.5 сек.
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
DM>>В том примере активно насилуется сборщик мусора, а он в многопоточном варианте должен быть сильно быстрее однопоточного.
K>Рассуждение было бы верным, если бы сборщик действительно работал заметное время. Но это не так. Можете сами посмотреть, запустив с +RTS -s K> %GC time 1.3% (2.2% elapsed)
Ага, спасибо. А если 98% времени работает лишь основной поток, чем объясняется такое сильное замедление при увеличении числа потоков (-N2-3-4) ?
K>А что и где можно почитать про дишные диапазоны и оптимизацию кода с ними?
Про оптимизацию где почитать не знаю, что-то выуживается из тонн обсуждений на дивном форуме, что-то подсказывает с++сный опыт и здравый смысл в сочетании с пониманием основных принципов. Собсно, рэнджи суть обычные шаблоны и структуры, специальная поддержка их в языке минимальна (foreach, оператор [], да и все, вроде).
Здравствуйте, D. Mon, Вы писали:
DM>C -flto он поперхнулся (lto1: internal compiler error: in streamer_get_pickled_tree, at tree-streamer-in.c:1050 DM>Please submit a full bug report), а без -flto остальные опции принял молча, однако быстрее программа не стала. Те же 2.5 сек.
Ну да, на подобном коде чудес и не должно быть. Автовекторизация разве что могла бы сработать, но видимо тот цикл всё же не по зубам. Т.е. дальнейшее ускорение уже только руками (simd+многопоточность), а это не имеет отношения к сравнению языков/компиляторов.
Жаль gdc не смог прожевать код в функциональном стиле. Кстати, как раз из-за его нестабильности я его и не использую. Хотя по слухам под линухом он работает стабильнее чем под виндой. )
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Ага, спасибо. А если 98% времени работает лишь основной поток, чем объясняется такое сильное замедление при увеличении числа потоков (-N2-3-4) ?
Сборщик и тормозит. Статистика, конечно, показывает и рост для мутатора, но если параллельный сборщик отключить ключем -qg — остается минимальный оверхед (который, видимо, создается планировщиком и балансировщиком нагрузки, который пытается найти в очереди единственной рабочей capability таски для n-1 простаивающих):
Причем для поддержания приемлемого оверхеда не нужно отключать параллельный сборщик вообще. Достаточно отключить его только для нулевого поколения ключем -qg1. Совсем не удивительно, что программа, в которой сборка мусора занимает относительно заметное время тоже быстрее работает с параллельной сборкой только для первого поколения:
для N4:
однопоточный сборщик
MUT: 5.45 GC: 8.86
параллельный сборщик 0 и 1-е поколения
MUT: 5.93 GC: 8.08
параллельная сборщик 1-е поколение
MUT: 5.29 GC: 6.70
Тут, скорее, удивительно, что они собираются выиграть, собирая параллельно 512K G0 и для чего вообще параллельная сборка включена по умолчанию для G0?
DM>Про оптимизацию где почитать не знаю, что-то выуживается из тонн обсуждений на дивном форуме, что-то подсказывает с++сный опыт и здравый смысл в сочетании с пониманием основных принципов. DM>Собсно, рэнджи суть обычные шаблоны и структуры, специальная поддержка их в языке минимальна (foreach, оператор [], да и все, вроде).
Тут я, похоже, невнятно выразился. Я имел в виду не "как писать быстрый код с диапазонами", а на какие оптимизации общего назначения полагается их библиотечная реализация.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Сборщик и тормозит. Статистика, конечно, показывает и рост для мутатора, но если параллельный сборщик отключить ключем -qg — остается минимальный оверхед (который, видимо, создается планировщиком и балансировщиком нагрузки, который пытается найти в очереди единственной рабочей capability таски для n-1 простаивающих) K>Причем для поддержания приемлемого оверхеда не нужно отключать параллельный сборщик вообще. Достаточно отключить его только для нулевого поколения ключем -qg1. Совсем не удивительно, что программа, в которой сборка мусора занимает относительно заметное время тоже быстрее работает с параллельной сборкой только для первого поколения:
Занятно, спасибо!
K>Тут я, похоже, невнятно выразился. Я имел в виду не "как писать быстрый код с диапазонами", а на какие оптимизации общего назначения полагается их библиотечная реализация.
Ключевой принцип там — все, что можно описать статически, в компайл-тайме, должно быть так описано. В частности, функции высшего порядка обычно передаются не как рантайм-значения (указатель на функцию либо делегат), а как компайл-тайм значения (параметр шаблона), так их легче инлайнить. Избегают классов с виртуальными методами, вместо этого строят на каждый чих шаблонами структуры, методы для которых получаются невиртуальными и в каждом вызове известными, такие тоже хорошо инлайнятся. Т.к. инлайнер — наше все.
Отдельная популярная тема — сохранение комбинаторами максимума статической информации. Если у исходного рэнджа статически известна длина или известно, что он бесконечный, или известно, что он умеет отдавать элементы по индексу и т.п., в типе результата это будет обычно отражено и в дальшейшем использовано для минимизации рантайм-проверок. Также есть практика у комбинаторов делиться статической информацией об их входных рэнджах (к которым они применены), за счет чего reverse.reverse превращается в id, например. Все вместе это позволяет считать нечто вроде last . take 10 . reverse . take 20 $ [1..] за О(1).
Re[70]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Интерфейсы или классы должны иметь свои экземпляры.
Что, одного экземпляра уже не достаточно — синглетон, например, не класс? Про статические классы я и не говорю.
_>А если их нет, то это уже скорее просто некие пространства имён или же вообще пакеты.
Вы, похоже, смутно себе представляете что такое модули во всяких мл-ях, где бывают первоклассные модули, модули высшего порядка и т.д. Где может быть список "пространств имен". И "пространства имен", принимающие другие "пространства имен" и возвращающих третьи, которые производят четвертые "пространства имен" из пятых и шестых. Конечно-конечно.
_>Ну и главное: мы же обсуждаем не языки вообще, а в контексте uml. Так вот там есть строго определённые виды диаграмм (классов, пакетов и т.п.), наборы сущностей (классы, пакеты и т.п.) и виды взаимосвязей между ними.
Так я вам даже перечислил эти виды взаимосвязей для диаграммы классов — там ничего ООП специфичного нет. Между модулями, классами типов, рекордами, функциями и много чем еще могут быть те же отношения.
_>Т.е. в любом случае, если захочется пользоваться инструментарием uml (а он весьма развитый и удобный сейчас), то придётся как-то укладываться в эти правила, а не придумывать новые. Так вот у ФП с этим большие сложности...
Которые, как и все прочие упомянутые вами сложности — сложности-которые-нельзя-называть.
_>Пока эти средства не введены в uml, действительно имеем тут крест.
Вот только вы никак не можете сказать — что же такое требуется в UML ввести для их поддержки. Потому, что ничего и не нужно вводить — там все уже есть.
_>В ООП программе архитектуру приложения обычно задают классы/объекты (который отлично видны на диаграммке классов, вместо со всеми своими методами), а не глобальные функции...
В ФП программе архитектуру приложения обычно задают модули/классы типов/АлгТД/функции (который отлично видны на диаграммке классов, вместо со всеми своими дочерними структурами), а не глобальные функции...
_>И кто нам помешает написать свою функцию, работающую как угодно с данными IO? )
Нам помешает то, что конструктор IO приватный.
_>Ничего подобного нет.
В выдуманных вами убогих ФЯ ничего нет до такой степени, что и самих их в реальности не существует — это нам уже известно.
Реально существующие, с другой стороны, отличаются от ваших фантазий.
_>Максимум что есть, это та самая структура модулей. В которой реализуется инкапсуляция уровня языка C (типа функции реализованной в .c файле, но не объявленной в .h файле).
Одна история увлекательнее другой — в C оказывается и модули уже появились.
_>Ну и конечно же замыкания (которые кстати везде есть)
Точно, и почти везде (кроме C++, как обычно) они даже работают.
_>не зря же их называют "объектами для бедных". )))
Да, а объекты — "замыканиями для бедных".
_>Вы не знаете области, в которых C++ является очевидным лидером? ) Это забавно для данного форума... )
Конечно знаю, и не одну. Более того, для любого N таких областей найдется такой пользователь этого форума, который назовет N+1-ю область. Об этом и речь.
_>Причины измерения уровней подобных энергетических величин (типа громкости звука и т.п.) в децибелах имеет вполне определённую природную причину — восприятие этих величин человеческими чувствами.
На самом деле основная причина — скорее восприятие чисел человеческим мозгом.
_>Но никто не употребляет логарифмы просто так везде или скажем просто для больших величин. Никто не говорит, что например солнце больше земли на 20 децибел.
Говорят, что у Солнца при наблюдении с Земли звездная величина −26.7, а у Земли при наблюдении с Солнца — −3.84
_>Так какие у нас обоснования для применения логарифмов при обсуждение количества вопросов о данном языке на SO?
Такие, что вещи, характеризующиеся числами растущими по экспоненте, часто удобно сравнивать и представлять "с применением логарифмов".
_>Разница в 1000 раз есть только между мейнстримом и маргинальными языками. А внутри группы мейнстрима как раз наблюдается разница "в разы".
Вот именно. Т.е. все работает как надо — чем вы недовольны-то?
_>Это уже просто вопрос терминологии. Компилятор прекрасно знает какая именно чистота подразумевается тут.
Конечно вопрос терминологии. У чистоты есть определение, а тут термин применяется со своим местечковым значением, ничего общего с общепринятым не имеющим.
_>Ждём демонстрацию)
В обсуждаемом примере изменяется значение переменной (семантически наблюдаемым образом) — какая вам еще демонстрация нужна? Что, какие-то сайд-эффекты каким-то другим способом достигаются?
_>Если мы говорим про D, то все величины без всяких модификаторов расположены в памяти конкретного потока (т.е. у каждого потока своя копия). Величины с модификатором share расположены в общей памяти (т.е. одна копия на все потоки), но при этом доступ к ним сопровождается соответствующми блокировками. А вот в случае модификатора immutable мы имеем естественно одну копию на всех, но с доступом без всяких блокировок.
Замечательно, значит какая-то смысловая нагрузка у "модификатора" все же есть!
_>иммутабельные структуры весьма полезны и при кодирование в стиле C++.
Конечно они полезны, но одновременно и вредны. И в рамках С++ c этим мало что можно сделать — получится в лучшем случае размен одной вредности на другую.
_>Ну а проработка возможности выделения "зиллионов объектов в секунду" для языка ориентированного на быстродействие весьма странно
Это вовсе не странно, а очень актуально практически для всех языков кроме C++ и C в том числе и более быстродействующих, чем D — вроде Явы.
_>в любом случае (даже с самым гениальным GC) такой код будет заметно медленнее работы со статическим выделением.
Вот только "работы со статическим выделением" — слишком существенное ограничение для любого языка с уровнем хоть немного выше самого низкого.
_>Приемлемым этот уровень пока что бывает только в теории. )
Конечно-конечно. Никто же не использует иммутабельные структуры на практике. Только "поддерживает".
_>Так вот я и не знаю что) У меня в коде широко используются иммутабельные данные, но я не особо представляю как померить "производительность" этого. Т.к. используются они таким образом, что замена их на мутабельные не приводит к увеличению быстродействия (а часто даже наоборот). Т.е. при таком использование вопрос о "поддержке иммутабельности" (подразумевая снижение цены за это) вообще не стоит, т.к. это наоборот выгоднее даже.
Судя по смыслу, которым наделяется слово "иммутабельный" в D, тут у вас противопоставление "с блокировками" — "без блокировок". Ну тут понятно, конечно, что без блокировок должно быть быстрее.
_>Да, вот в вашем примере переход на мутабельные данные вызывает ускорение на порядок
Вы, вообще-то мой пример еще не воспроизвели даже с переходом на мутабельные данные, а уже заявления о порядках выдаете.
_>Как раз последовательность работающую с диапазонами в D можно делать произвольной длинны — разница будет не очень существенная. Заметное замедление происходит только в точке пересоздание списка чисел.
Ну так смысл задачи — организовать множества таких "точек пересоздания", а не свести к одной.
K>>Попробуйте написать аналог моего кода, тогда и посмотрим. _>Так уже всё написали же и измерили.
Ну пошло-поехало. Нет, не написали.
Вы не написали даже аналог "на мутабельных данных", в котором было бы то же число стадий конвейера и реализация одних функций на базе других.
Я, впрочем, не настаиваю на этом, это типичный съезд с темы — мы сравниваем не скорость работы с иммутабельными данными со скоростью работы с мутабельными, и не обсуждаем полезность иммутабельности — мы оцениваем ее поддержку в языках.
Понятно, что когда вы обнаружили, что никакой поддержки нет — все свелось к обсуждению ненужности того, что якобы поддерживалось. Такое в данной ветке уже не первый раз происходит.
_>И результаты говорят сами за себя.
Результаты что-то скажут, когда вы более-менее воспроизведете пример.
_>код на Хаскеле (естественно размножающий данные) работает в 6-7 раз медленнее.
Вообще-то 16.09/9.370 ~ 1.717, а вовсе не 6-7. При этом стадий в конвейере у вас меньше, и если их добавить — код навряд ли заработает быстрее.
_>код на D размножающий данные работает раз в 15 медленнее.
Вот напишете аналог моего кода — тогда и измерим.
_>Кстати, интересный нюанс. В D одинаково легко записываются оба вида кода (причём он получается практически одинаковый и в одну строку).
Очевидно потому, что это почти один и тот же код, а не "оба вида" кода.
Вы вместо аналога моего кода написали что-то имеющее слабое отношение к теме разговора и теперь на голубом глазу декларируете какие-то "оба вида" и "6-7 раз". Организация конвейеров в D тема интересная, но я не готов ее обсуждать в ущерб основной. Ваш же план, похоже, заключается в заметании темы иммутабельности под ковер и накидывании каких-то нерелевантных примеров и заявлений о производительности примеров вовсе не представленных.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[71]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Что, одного экземпляра уже не достаточно — синглетон, например, не класс? Про статические классы я и не говорю.
Одного достаточно. Ключевое различие в способе обращений к данным — через обязательно требуемую переменную, а не через имя класса.
А вот статические классы действительно являются прямым аналогом пространств имён.
K>Вот только вы никак не можете сказать — что же такое требуется в UML ввести для их поддержки. Потому, что ничего и не нужно вводить — там все уже есть.
А ну, ОК. Тогда значит вас не затруднит назвать, на какой конкретно диаграмме uml (их виды чётко определены) и каким конкретно значком (их набор и свойства тоже чётко указаны в спецификации uml) можно отобразить например те самые модули из Хаскеля?
K>Нам помешает то, что конструктор IO приватный.
Это нам как-то мешает прочитать внутренние данные IO? )
K>Одна история увлекательнее другой — в C оказывается и модули уже появились.
В C их роль выполняют файлы. Если очень нервирует такой подход, то можно взять например Паскаль (без ООП) — его модули тоже реализуют "инкапсуляцию" того же уровня. )
_>>не зря же их называют "объектами для бедных". ))) K>Да, а объекты — "замыканиями для бедных".
Ага, и это отлично ложится на мою главную мысль, о том что будущее за мультипарадигменными языками (в которых есть полноценная поддержка и объектов и замыканий и всего остального).
K>На самом деле основная причина — скорее восприятие чисел человеческим мозгом.
Ерунда. Если взять например характерные линейные размеры различных космических объектов, то там тоже будут разницы на порядки. И если будет желание отобразить это всё на картинке, то безусловно надо будет использовать логарифмическую шкалу (иначе получится уродливо). Однако при этом никто не будет сравнивать вместо диаметра Земли и Марса их логарифмы — в этом не будет вообще никакого смысла.
K>Конечно вопрос терминологии. У чистоты есть определение, а тут термин применяется со своим местечковым значением, ничего общего с общепринятым не имеющим.
А вот это уже не так однозначно... Если мы будем брать именно программирование (а не абстрактные математические понятия), то пока что явное понятие чистоты есть всего в паре известных языков. Так что совсем не однозначно какое именно из них брать. Более того, т.к. определение из второго языке не противоречит первому, а всего лишь расширяет его на область вообще отсутствующую в первом, то картина становится ещё интереснее.
K>В обсуждаемом примере изменяется значение переменной (семантически наблюдаемым образом) — какая вам еще демонстрация нужна? Что, какие-то сайд-эффекты каким-то другим способом достигаются?
И что такого в этом, если это не глобальная/статическая переменная, а передаваемый параметр? )
==============
На всё дальнейшее я отвечу здесь целиком. Поскольку я заметил, что у нас тут наблюдается различие в самой базовой концепции. И пока не разберёмся с ним, обсуждать мелкие детали смысла нет — всё равно не поймём друг друга (точнее я то сомневаюсь в понимание в любом случае, но так хоть теоретический шанс есть).
Насколько я вижу, вы явно придерживаетесь точки зрения типа "иммутабельные данные — это абсолютное добро", и вследствие этого предпочитаете использовать их вообще везде. Даже если это абсолютно не ложится на задачу (как было во всех предыдущих примерах) и соответственно за это приходится платить существенную цену (в виде падения быстродействия). Естественно, что при такой идеологии возникает вопрос уровня "поддержки иммутабельности" и т.п., который в данном контексте означает попытки снижения этой цены. Хотя как мы видим по примерам в этой теме, на многих задачах даже приблизиться к производительности решений с мутабельными данными всё равно не выходит и с помощью всех ухищрений Хаскеля — отставание в разы.
У меня же подход совсем другой. Я использую иммутабельные данные там, где они такие по условию задачи. Соответственно при таком подходе не то что не возникает понятия "цены за использование иммутабельнных данных", а наоборот это частенько способствует увеличению быстродействия. В итоге, я даже не представляю, что предложить на предложение продемонстрировать эффективность поддержки иммутабельности в языке, т.к. при моём подходе она абсолютная.
P.S. А всё же хотелось бы увидеть решение задачки с простыми числами через мутабельные данные на Хаскеле и оценить его быстродействие и главное внешний вид. Последнее особенно интересно в контексте старой беседы о монадных ужасах.
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А вот ещё интересно бы попробовать с gdc такой функциональный вариант на мутабельных данных: _>int CountPrimes(int m, int v=5, int[] primes=[3]) _>Здесь вроде как всего один уровень вложенности лямбд — вдруг прожуёт. )
Не, не прожевал. Та же ошибка про вложенную лямбду.
_>На dmd этот вариант у меня работает точно так же, как и первый функциональный вариант (который в одну строчку).
А у меня чуток медленнее (9.7 vs. 9.4).
Re[72]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Одного достаточно. Ключевое различие в способе обращений к данным — через обязательно требуемую переменную, а не через имя класса.
Ну да, без этого обязательного требования диаграмму же построить нельзя... Так, погодите-ка. Можно!
_>А вот статические классы действительно являются прямым аналогом пространств имён.
Тем не менее статические классы попадают на диаграммы, даже если учесть что с отношениями у них все не очень интересно. Но даже у непервоклассных модулей отношения гораздо интереснее и представлять на диаграмме есть что.
_>А ну, ОК. Тогда значит вас не затруднит назвать, на какой конкретно диаграмме uml (их виды чётко определены) и каким конкретно значком (их набор и свойства тоже чётко указаны в спецификации uml) можно отобразить например те самые модули из Хаскеля?
Предлагаю для этого использовать элемент Class со стереотипом <<module>> на диаграмме классов.
K>>Нам помешает то, что конструктор IO приватный. _>Это нам как-то мешает прочитать внутренние данные IO? )
Да, потому что чтоб получить внутренние данные АлгТД его нужно деконструировать паттерн-матчингом. И если конструктор приватный — это невозможно, матчить не с чем.
_>В C их роль выполняют файлы.
Нет, не выполняют.
_>Если очень нервирует такой подход, то можно взять например Паскаль (без ООП) — его модули тоже реализуют "инкапсуляцию" того же уровня. )
Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?
_>>>не зря же их называют "объектами для бедных". ))) K>>Да, а объекты — "замыканиями для бедных". _>Ага, и это отлично ложится на мою главную мысль, о том что будущее за мультипарадигменными языками
Жаль только, что эти высказывания являются всего лишь специфическим юмором схема-комьюнити. И я не стал бы советовать строить какие-то теории и далеко идущие выводы на шутках лисперов.
_>в которых есть полноценная поддержка и объектов и замыканий и всего остального.
Как только такой язык появится — обязательно мне сообщите.
K>>На самом деле основная причина — скорее восприятие чисел человеческим мозгом. _>Нет, речь совсем не про числа, а именно про человеческие чувства
Одно с другим связано непосредственно. Человеческий мозг привыкает работать с теми датчиками, которые у него есть.
K>>Такие, что вещи, характеризующиеся числами растущими по экспоненте, часто удобно сравнивать и представлять "с применением логарифмов".
_>Если взять например характерные линейные размеры различных космических объектов, то там тоже будут разницы на порядки. И если будет желание отобразить это всё на картинке, то безусловно надо будет использовать логарифмическую шкалу (иначе получится уродливо). Однако при этом никто не будет сравнивать вместо диаметра Земли и Марса их логарифмы — в этом не будет вообще никакого смысла.
Абсолютно никакого. Потому, что диаметры Земли и Марса отличаются вовсе не на порядки. Параметры планет сходных типов вообще варьируются не сильно. Да и астрономы редко оперируют линейными размерами — это обычно сильно гипотетические величины, заметное кол-во исключений появилось, практически, в самое последнее время.
Классификация планет вообще только зарождается, в зрелой классификации звезд параметры и графики уже известны — диаграмма Герцшпрунга-Рассела с логарифмическими осями и логарифмическими же "рейтингами": спектральным классом и абсолютной звездной величиной.
_>Если мы будем брать именно программирование (а не абстрактные математические понятия), то пока что явное понятие чистоты есть всего в паре известных языков. Так что совсем не однозначно какое именно из них брать.
Брать математическое. Мозговые тараканы между мозгами переносятся плохо.
_>Более того, т.к. определение из второго языке не противоречит первому
Противоречит. То, что называется чистым в D в хаскеле не называется и наоборот.
_>И что такого в этом, если это не глобальная/статическая переменная, а передаваемый параметр? )
И то, что с точки зрения контроля за эффектами нет никакой разницы между тем, статическая это переменная или нет. С точки зрения разделения между потоками разница есть — ну так мы уже выяснили, что в ди все обсуждаемые идентификаторы именно для этого, а не для контроля за эффектами.
_>На всё дальнейшее я отвечу здесь целиком. Поскольку я заметил, что у нас тут наблюдается различие в самой базовой концепции. И пока не разберёмся с ним, обсуждать мелкие детали смысла нет — всё равно не поймём друг друга (точнее я то сомневаюсь в понимание в любом случае, но так хоть теоретический шанс есть).
Это различие заключается в том, что я всячески сопротивляюсь сходу дискуссиии с рельсов. И если обсуждается поддержка иммутабельности — то ее и обсуждаю. Вы же вместо этого вдруг начинаете говорить о нужности иммутабельности и других нерелевантных вещах.
_>Насколько я вижу, вы явно придерживаетесь точки зрения типа "иммутабельные данные — это абсолютное добро"
Нет, не придерживаюсь. Я просто выношу рассуждения об области применения иммутабельности за рамки спора, потому что в данном случае это оффтопик.
_>и вследствие этого предпочитаете использовать их вообще везде. Даже если это абсолютно не ложится на задачу (как было во всех предыдущих примерах)
Нет, я их использую в данном случае потому, что обсуждается поддержка их использования. И потому предлагаю примеры с их использованием: что обсуждаем то и демонстрируем на примерах. Вы же начали про поддержку иммутабельности в Ди, а предъявили пример, в котором ни одной иммутабельной структуры нет.
_>и соответственно за это приходится платить существенную цену (в виде падения быстродействия).
Для того, чтоб продемонстрировать поддержку иммутабельности нужно показать пример, где за нее приходится платить существенную цену. Потому, что если цена несущественная — степень поддержки измерить затруднительно.
_>Естественно, что при такой идеологии возникает вопрос уровня "поддержки иммутабельности" и т.п., который в данном контексте означает попытки снижения этой цены.
Вопрос поддержки X возникает при использовании X. Снижение цены X не имеет значения только если X не использовать.
_>Хотя как мы видим по примерам в этой теме, на многих задачах даже приблизиться к производительности решений с мутабельными данными всё равно не выходит и с помощью всех ухищрений Хаскеля — отставание в разы.
Отставание в 1.7 раз. Дальнейшее увеличение разрыва связано с "фортранизацией" кода, что ожидаемо. Правда у меня разница между максимальным аналогом вашего кода (см. ниже) и моим тестом больше (3.25 раз).
Но и такая разница вполне может быть приемлемой. Особенно по сравнению с тем, что мы получим в случае языка "без поддержки". К сожалению, вы упорно не хотите демонстрировать аналог моего кода и мы так и не узнаем, какая разница будет для Ди.
_>У меня же подход совсем другой. Я использую иммутабельные данные там, где они такие по условию задачи.
Да, да, это мы уже обсуждали. И боги "условий задачи" волшебным образом срезают накладные расходы.
Снижение накладных расходов означает расширение области применимости. Понятно, что даже в языках "без поддержки" есть маргинальные области, в которых использование может быть оправдано. Но масштабное использование возможно только в языке "с поддержкой".
_>P.S. А всё же хотелось бы увидеть решение задачки с простыми числами через мутабельные данные на Хаскеле и оценить его быстродействие и главное внешний вид. Последнее особенно интересно в контексте старой беседы о монадных ужасах.
Это отклонение от темы, но максимальный аналог вашего кода я продемонстрирую. Я бы мог, конечно, еще побороться за сохранение темы обсуждения, но раз уж вы окончательно переключились с демонстрации поддержки (вами же и заявленной) иммутабельности в D на обвинение меня в том, что я, якобы "считаю иммутабельность абсолютным добром", ждать демонстрации кода на D, работающего с иммутабельными данными, не приходится.
import Control.Applicative
import Control.Monad
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M
-- Я не смог вспомнить и сходу нагуглить библиотеку с "динамическим массивом",
-- для хаскеля это суровая экзотика, так что я просто релизовал его самостоятельно.
-- начальный буфер - 1000 элементов, при переполнении растет в 4 раза.data Buffer m a = Buffer { len :: !Int, buf :: !(M.MVector m a) }
over f (Buffer c b) = f . U.take c <$> U.unsafeFreeze b
(Buffer c b) <| a | M.length b > c = add b | otherwise = add =<< M.grow b (c*3) where
add nb = Buffer (c+1) nb <$ M.write nb c a
buffer l = flip (foldM (<|)) l . Buffer 0 =<< M.new 1000
-- конец реализации.
-- А вот и сам пример:
main = print . len =<< flip (U.foldM step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24)
=<< buffer [2, 3::Int] where
step primes x = do
t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes
if t then primes <| x else pure primes
Монадные ужасы в данном случае >>= либо <$> вместо $, foldM вместо foldl, и немного do-нотации (можно и без нее обойтись тем же >>=).
Работает это у меня 2.62 секунды на i5-3330 Win x64, GHC 7.6.3 x32, llvm 3.3. Мой пример работал 8.52 сек., так что разница 3.25 раз.
Следует заметить, впрочем, что если ренджи в D мутабельные (я пока не ознакомился с ними достаточно подробно, но судя по тому, что у них есть методы вроде moveFront() возвращающие элемент, но не возвращающие новый рендж), и, следовательно, вы используете в своем примере мутабельные структуры вообще везде, то векторы в моем примере иммутабельные (как и стримы, в которые они преобразуются оптимизатором), так что все промежуточные данные у меня наоборот иммутабельные, кроме единственного "динамического массива", однако, судя по разнице с "списочным" примером, работает мой код на хаскеле быстрее вашего приближенно аналогичного на D.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[73]: Есть ли вещи, которые вы прницпиально не понимаете...
_>>Одного достаточно. Ключевое различие в способе обращений к данным — через обязательно требуемую переменную, а не через имя класса. K>Ну да, без этого обязательного требования диаграмму же построить нельзя... Так, погодите-ка. Можно!
Причём тут диаграммы, если здесь шла речь про разницу между объектами и пространствами имён/пакетами?
K>Предлагаю для этого использовать элемент Class со стереотипом <<module>> на диаграмме классов.
Ага... Тогда автоматически появляются следующие вопросы... Какими значками будем обозначать классы/типы Хаскеля? И главное, каким образом мы разместим иерархию типов данного модуля внутри подобного значка модуля? )
_>>Это нам как-то мешает прочитать внутренние данные IO? ) K>Да, потому что чтоб получить внутренние данные АлгТД его нужно деконструировать паттерн-матчингом. И если конструктор приватный — это невозможно, матчить не с чем.
С чего это IO стал алгебраическим типом данных? )
K>Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?
А там есть какие-то принципиальные отличия по уровню инкапсуляции? ) Буквально тоже самое — банально реализуем функцию в коде модуля, но не описываем её в интерфейсе. Инкапсуляция уровня древнего Паскаля, когда он ещё без ООП был.
_>>в которых есть полноценная поддержка и объектов и замыканий и всего остального. K>Как только такой язык появится — обязательно мне сообщите.
Чем например D не подходит? )
K>Одно с другим связано непосредственно. Человеческий мозг привыкает работать с теми датчиками, которые у него есть.
При работе с формулами мы используем абстракции, а не ощущениями.
K>Абсолютно никакого. Потому, что диаметры Земли и Марса отличаются вовсе не на порядки. Параметры планет сходных типов вообще варьируются не сильно. Да и астрономы редко оперируют линейными размерами — это обычно сильно гипотетические величины, заметное кол-во исключений появилось, практически, в самое последнее время.
Ну добавим сюда Юпитер и получим разницу на порядок — от этого появятся логарифмы? ))) Я не говорю уже про то, что если взять не диаметры, а массы...
K>Классификация планет вообще только зарождается, в зрелой классификации звезд параметры и графики уже известны — диаграмма Герцшпрунга-Рассела с логарифмическими осями и логарифмическими же "рейтингами": спектральным классом и абсолютной звездной величиной.
Для начала логарифмическим там является только звёздная величина. Происхождение которой теряется где-то в древней Греции и опять же полностью основано на человеческих чувствах (зрение).
_>>Если мы будем брать именно программирование (а не абстрактные математические понятия), то пока что явное понятие чистоты есть всего в паре известных языков. Так что совсем не однозначно какое именно из них брать.
K>Брать математическое. Мозговые тараканы между мозгами переносятся плохо.
Во-первых программирование является самостоятельной дисциплиной, в которой есть своя терминология, частенько отличная от математической (взять хотя бы уже понятие функции).
Во-вторых "чистота" относится всё же к терминологии из программирования, а не из математики, т.к. в самой математике такое понятие просто не нужно (там собственно все функции такие по определению). Просто чистая функция в определения Хаскеля становится весьма похожа на нормальную функцию из математики, поэтому некоторые почему-то считают это "математическим" определением.
Могу предположить, что если бы D стал мейнстримным языком лет 10 назад (вполне реально, если бы его изначально поддержала какая-то из мегакорпораций), то именно его определение чистоты стало бы общепринятым в программирование. Ну а пока это вообще маргинальный термин. )
K>Противоречит. То, что называется чистым в D в хаскеле не называется и наоборот.
Не противоречит, т.к. в Хаскеле просто нет такой области, которая есть в D (и любых императивных языках) — функций работающих с мутабельными параметрами. Соответственно если сравнивать только по общим областями (по работе с функциями иммутабельных параметров), то определения полностью совпадают. Т.е. мы имеем классическое расширение определения на новую область.
K>И то, что с точки зрения контроля за эффектами нет никакой разницы между тем, статическая это переменная или нет. С точки зрения разделения между потоками разница есть — ну так мы уже выяснили, что в ди все обсуждаемые идентификаторы именно для этого, а не для контроля за эффектами.
С учётом наличия в языке удобных инструментов для контроля за параметрами функции (это же не только immutable, но и например модификаторы in/out/inout) мы можем очень чётко формулировать (причём всё это в объявление, а не в реализации) наши условия на эффекты от данной функции. Так что на мой взгляд у нас есть полный контроль эффектов, причём даже более тонкий, чем в Хаскеле.
K>Это различие заключается в том, что я всячески сопротивляюсь сходу дискуссиии с рельсов. И если обсуждается поддержка иммутабельности — то ее и обсуждаю. Вы же вместо этого вдруг начинаете говорить о нужности иммутабельности и других нерелевантных вещах.
Нет, речь не о нужности, а о адекватности примеров. Если мы будем рассматривать примеры кода, которые никто и никогда не напишет на D на практике (потому как они на порядок медленнее своих мутабельных аналогов при одинаковой внешности кода), то подобное тестирование выглядит очень глупо.
Причём на Хаскеле данный пример выглядит более логичным, т.к. на нём код с мутабельными данными выглядит дико. Соответственно в Хаскеле во многих случая есть смысл потерпеть потерю быстродействия ради отсутствия монадных ужасов.
K>Нет, я их использую в данном случае потому, что обсуждается поддержка их использования. И потому предлагаю примеры с их использованием: что обсуждаем то и демонстрируем на примерах. Вы же начали про поддержку иммутабельности в Ди, а предъявили пример, в котором ни одной иммутабельной структуры нет.
Так пример то предъявил не я. )
Ну а в ответ на ваш пример я показал уже 4 его реализации на D с разным быстродействием. В том числе и с иммутабельными данными. Причём все они реализуются тривиально и соответственно при программирование на D всегда будет использоваться один (самый быстрый) вариант. В отличие от Хаскеля, где быстрый вариант (для Хаскеля быстрый ) сопровождается ужасами.
K>Для того, чтоб продемонстрировать поддержку иммутабельности нужно показать пример, где за нее приходится платить существенную цену. Потому, что если цена несущественная — степень поддержки измерить затруднительно.
Вот и я про это. Зачем измерять поддержку того, что в реальности никогда не будет использоваться (т.к. за это придётся платить существенную цену)? Естественно речь про языки, где нет проблем с использованием мутабельных данных, а не про Хаскель.
K>Отставание в 1.7 раз. Дальнейшее увеличение разрыва связано с "фортранизацией" кода, что ожидаемо.
Какой очаровательный термин для нормального императивного кода. ))) Причём что самое забавное, именно такой код скорее всего и будет писаться на практике.
Да, но и и функциональный код на D можно довести до оптимального быстродействия, слегка подправив алгоритм. Например так:
K>Правда у меня разница между максимальным аналогом вашего кода (см. ниже) и моим тестом больше (3.25 раз). K>Но и такая разница вполне может быть приемлемой. Особенно по сравнению с тем, что мы получим в случае языка "без поддержки". К сожалению, вы упорно не хотите демонстрировать аналог моего кода и мы так и не узнаем, какая разница будет для Ди.
Всё показывали и измеряли. Просто вы в упор не хотите видеть. С учётом этого вашего последнего результата теперь получаем совсем законченную табличку:
— код на D с мутабельными данными (нормальный вид и даже не один вариант) — 1х
— код на Хаскеле с мутабельными данными (страшный вид) — 2x
— код на Хаскеле с иммутабельными данными (нормальный вид) — 6х
— код на D с иммутабельными данными (нормальный вид) — 15x.
Цифры естественно довольно приближённый, но порядок величины из них вполне понятен.
K>Да, да, это мы уже обсуждали. И боги "условий задачи" волшебным образом срезают накладные расходы.
K>Снижение накладных расходов означает расширение области применимости. Понятно, что даже в языках "без поддержки" есть маргинальные области, в которых использование может быть оправдано. Но масштабное использование возможно только в языке "с поддержкой".
Это просто разные подходы к проектированию вообще. У вас подход "всунуть иммутабельные данные везде, где только получится". А у меня подход "использовать иммутабельные данные там, где они такие по условию задачи". Соответственно при моём подходе область применимость никак не завязана на "поддержку в языке".
K>Это отклонение от темы, но максимальный аналог вашего кода я продемонстрирую. Я бы мог, конечно, еще побороться за сохранение темы обсуждения, но раз уж вы окончательно переключились с демонстрации поддержки (вами же и заявленной) иммутабельности в D на обвинение меня в том, что я, якобы "считаю иммутабельность абсолютным добром", ждать демонстрации кода на D, работающего с иммутабельными данными, не приходится.
Демонстрация была с самого начала.
K>... K>Монадные ужасы в данном случае >>= либо <$> вместо $, foldM вместо foldl, и немного do-нотации (можно и без нее обойтись тем же >>=).
Хыхы, ну я этот ужастик даже комментировать не буду. Вы то всё равно не согласитесь с моей оценкой, но зато любой вменяемый читатель сразу же оценит разницу между этим вашим кодом, вашим же кодом для иммутабельного случая и кодом на D. Так сказать очередное подтверждение моим словам. Но вы естественно будете и дальше утверждать, что ничего подобного в этой темке не было. )))
K>Следует заметить, впрочем, что если ренджи в D мутабельные (я пока не ознакомился с ними достаточно подробно, но судя по тому, что у них есть методы вроде moveFront() возвращающие элемент, но не возвращающие новый рендж), и, следовательно, вы используете в своем примере мутабельные структуры вообще везде, то векторы в моем примере иммутабельные (как и стримы, в которые они преобразуются оптимизатором), так что все промежуточные данные у меня наоборот иммутабельные, кроме единственного "динамического массива", однако, судя по разнице с "списочным" примером, работает мой код на хаскеле быстрее вашего приближенно аналогичного на D.
Иммутабельность данных в языках типа D или C++ зависят не от класса, а от объекта. Т.е. если мы пишем "const vector<int> data;", то мы не сможем модифицировать data, хотя у него есть метод push_back и т.п.
Что касается диапазонов в D, то я бы сказал что они чем-то напоминают IEnumerable в C# с поправкой на попытку делать всё в статике и не терять информацию о типе изначальной коллекции (например если она с произвольным доступом, то это может существенно оптимизировать многие алгоритмы и т.п.).
Re[74]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Причём тут диаграммы, если здесь шла речь про разницу между объектами и пространствами имён/пакетами?
Как причем диаграммы? Мы не про диаграммы разве говорили все это время? Вот статические классы — это, по вашему, "пространства имен", а их на диаграмме классов показывают. Так какие вопросы к модулям? _>Ага... Тогда автоматически появляются следующие вопросы... Какими значками будем обозначать классы/типы Хаскеля?
Аналогично, элементами Class с соответствующими стереотипами. _>И главное, каким образом мы разместим иерархию типов данного модуля внутри подобного значка модуля? )
С использованием инструментария для обозначения вложенных классов. Т.е. внутри элемента или соответствующим отношением (емнип, плюс в круге на конце линии), если инструмент поддерживает. _>С чего это IO стал алгебраическим типом данных? )
А чем он по-вашему должен быть? Сепулькарием что ли?
Prelude> :i IO
newtype IO a
= GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
-- Defined in `GHC.Types'instance Monad IO-- Defined in `GHC.Base'instance Functor IO-- Defined in `GHC.Base'
_>А там есть какие-то принципиальные отличия по уровню инкапсуляции? ) Буквально тоже самое — банально реализуем функцию в коде модуля, но не описываем её в интерфейсе. Инкапсуляция уровня древнего Паскаля, когда он ещё без ООП был.
Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете? _>Чем например D не подходит? )
Тем, что не мультипарадигменный. _>При работе с формулами мы используем абстракции, а не ощущениями.
Вы только что сами же и писали, что то, с какими формулами мы работаем — продиктовано ощущениями. _>Ну добавим сюда Юпитер и получим разницу на порядок — от этого появятся логарифмы? ))) Я не говорю уже про то, что если взять не диаметры, а массы...
Вполне возможно и появится. Сейчас, когда планеты сравнивают, на графиках в координатах период — масса, например, оси обычно логарифмические строят. Так что когда сформируется классификация планет вроде той, что уже для звезд есть — посмотрим какие там будут "рейтинги". _>Для начала логарифмическим там является только звёздная величина.
То, что соответствующие спектральным классам диапазоны температур меняются от сотен K до десятков тысяч вы предпочли не заметить. _>Происхождение которой теряется где-то в древней Греции и опять же полностью основано на человеческих чувствах (зрение).
Ну да, и что за нее держатся-то? Вы же, наверно, понимаете, что абсолютную болометрическую зв. величину никто "глазами" не воспринимает?
Может и энтропию человек каким-то органом ощущает тоже?
Вы правы в том смысле, что все это началось с человеческой физиологии. Но сейчас это просто инструментарий для работы с большими диапазонами чисел, не только "воспринимаемыми" какими-то органами чувств, но вообще любыми. И если с помощью инструментария можно построить объединение каких-то двух "рейтингов" — в обсуждаемом нами случае SO и github — да еще так, чтоб они друг друга проверяли, то это же хорошо. Без логарифмов, популярность всех языков, кроме, допустим "большой пятерки" была бы одинаковой, зато все члены этой самой большой пятерки отличались бы по популярности друг от друга и от всех остальных крайне существенно. При этом какой бы "измеряемый" показатель мы не брали бы, популярность на ресурсе X, ресурсе Y или число ссылок в поисковике Z — во всех этих случаев популярность внутри пятерки была бы существенно различной, ее никак нельзя было бы согласовать.
Неужели эта проблема не понятна? _>Во-первых программирование является самостоятельной дисциплиной, в которой есть своя терминология, частенько отличная от математической (взять хотя бы уже понятие функции).
Т.е. имеющиеся проблемы — это оправдание для создания еще больших проблем? _>Во-вторых "чистота" относится всё же к терминологии из программирования, а не из математики, т.к. в самой математике такое понятие просто не нужно (там собственно все функции такие по определению). Просто чистая функция в определения Хаскеля становится весьма похожа на нормальную функцию из математики, поэтому некоторые почему-то считают это "математическим" определением.
Вы же сами и объяснили, почему они так считают. _>Могу предположить, что если бы D стал мейнстримным языком лет 10 назад (вполне реально, если бы его изначально поддержала какая-то из мегакорпораций), то именно его определение чистоты стало бы общепринятым в программирование.
Если бы D стал мейнстримом 10 лет назад, обсуждаемых модификаторов в нем не было бы. _>Ну а пока это вообще маргинальный термин. )
Людей, знакомых с математическим определением функции, гораздо больше, чем программистов. _>Не противоречит, т.к. в Хаскеле просто нет такой области, которая есть в D (и любых императивных языках) — функций работающих с мутабельными параметрами.
С ума сойти. Функции, которые не то что я тут использовал в коде, вот буквально в посте, на который вы отвечаете, а вы же сами и использовали, когда писали пример с использованием пакета array — они, оказывается, не существуют. _>Соответственно если сравнивать только по общим областями (по работе с функциями иммутабельных параметров), то определения полностью совпадают. Т.е. мы имеем классическое расширение определения на новую область.
Проблема в том, что если вы множество чистых функций расширяете добавлением в него "нечистых" — то называть получившееся множество функций нечистыми нет никаких оснований. Вот есть у вас простые числа {2,3,7..} , вы их "расширили" добавлением всех остальных. ладно, не всех остальных, а, допустим, всех четных. Есть у вас теперь основания утверждать, что все четные числа — простые? _>С учётом наличия в языке удобных инструментов для контроля за параметрами функции (это же не только immutable, но и например модификаторы in/out/inout) мы можем очень чётко формулировать (причём всё это в объявление, а не в реализации) наши условия на эффекты от данной функции. Так что на мой взгляд у нас есть полный контроль эффектов, причём даже более тонкий, чем в Хаскеле.
Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось
map (p . q) = map p . map q
Скрытый текст
впереди 7 месяцев рассуждений про ненужность контроля эффектов, и почему его отсутствие в ди равняется наличию
_>Нет, речь не о нужности, а о адекватности примеров. Если мы будем рассматривать примеры кода, которые никто и никогда не напишет на D на практике (потому как они на порядок медленнее своих мутабельных аналогов при одинаковой внешности кода), то подобное тестирование выглядит очень глупо.
Ну так вроде бы разжевано, что именно он проверяет и понятно, что в коде, который реально пишут на более-менее высокоуровневых языках все это востребовано. Вы же сами предъявили требования к примеру: он должен быть небольшим и одним. Что удивительного в том, что он выглядит искусственным, если он должен проверять разные вещи?
И главное, как то, что пример "выглядит глупо" повлияет на оценку производительности тех случаев, которые глупо не выглядят? _>Так пример то предъявил не я. )
Что, кто-то захватил ваш аккаунт и оставил от вашего имени сообщение
в котором вместо иммутабельных структур используются мутабельные? Какое коварство! Ну, жду от вас теперь ваш пример, в котором используются иммутабельные структуры. _>Ну а в ответ на ваш пример я показал уже 4 его реализации на D с разным быстродействием. В том числе и с иммутабельными данными.
Нет, примера с иммутабельными данными не было. Промежуточные данные между стадиями конвейера в моем примере иммутабельные. В ваших мутабельные. Заменой мутабельных данных в одной точке вашего конвейера аналог моего примера не получить. Я об этом вам уже писал, но вы это полностью игнорируете, на голубом глазу заявляя, что аналог продемонстрирован.
Он не соответствует условию задачи. Смотрим:
Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет.
Вы же не только не создаете промежуточные иммутабельные данные — вы стараетесь не сделать их "как можно больше", а наоборот, сокращаете число стадий в конвейерах. Довольно странно в сравнении того, как быстро что-то делается представлять вариант, который это что-то не делает. _>Вот и я про это. Зачем измерять поддержку того, что в реальности никогда не будет использоваться (т.к. за это придётся платить существенную цену)? Естественно речь про языки, где нет проблем с использованием мутабельных данных
Ну, как я и предсказывал в самом начале, под "поддержкой иммутабельности" подразумевалась ее ненужность, тем более, что с "мутабельностью проблем нет" — ее и будут всегда использовать! _>Какой очаровательный термин для нормального императивного кода.
Т.е. переписывание конвейера в цикл — это нормальный императивный код. А зачем вообще все эти ренджи в ди есть? Можно же писать нормальный императивный код в виде циклов — повторное использование и декомпозиция переоценены, весь прогресс после фортрана — путь в никуда. _>))) Причём что самое забавное, именно такой код скорее всего и будет писаться на практике.
Что многое говорит о возможности писать высокоуровневый код на ди. Вы уже теперь доказываете ненужность конвейеров, хотя сами же перевели на них разговор с поддержки иммутабельности. Но оказалось, что они тормозят и все пошло по знакомой траектории. _>Да, но и и функциональный код на D можно довести до оптимального быстродействия, слегка подправив алгоритм. Например так: _>
Ну правильно, вы еще уменьшили число стадий конвейера. Но вы же, наверное, понимаете, что для всех случаев специальных функций не найдется, и надо будет пользоваться комбинациями функций между которыми как-то передаются данные? _>Всё показывали и измеряли. Просто вы в упор не хотите видеть.
Конечно, я не хочу принимать код, который не использует иммутабельные данные в качестве аналога моего примера. И я даже объяснил почему. И не один раз. _>- код на D с мутабельными данными (нормальный вид и даже не один вариант) — 1х
Речь про страшный фортранизированный код? _>- код на Хаскеле с мутабельными данными (страшный вид) — 2x
И что в нем страшного? Никакой фортранизации нет. _>- код на D с иммутабельными данными (нормальный вид) — 15x.
Этот код еще не написан. Код "с использованием иммутабельных данных для хранения простых чисел" за такой не посчитать.
Вот что у нас сейчас есть в порядке убывания производительности:
код с циклами на D a la фортран
код на хаскеле, использующий иммутабельные данные между всеми стадиями конвейера, кроме структуры, хранящей простые числа (он не совсем нерелевантный, но измеряет только способность компилятора выкидывать лишние аллокации).
код с конвейером на D, использующий мутабельные данные между всеми стадиями конвейера и для хранения простых чисел.
код на хаскеле, использующий только иммутабельные данные (единственный, соответствующий условию задачи полностью).
код на D использующий мутабельные данные между всеми стадиями конвейера, кроме структуры, хранящей простые числа. _>Это просто разные подходы к проектированию вообще. У вас подход "всунуть иммутабельные данные везде, где только получится".
Это не соответствует действительности. _>А у меня подход "использовать иммутабельные данные там, где они такие по условию задачи". Соответственно при моём подходе область применимость никак не завязана на "поддержку в языке".
Конечно связано. У вас "использовать иммутабельные данные там, где они такие по условию задачи" означает буквально следующее:
"По условию задачи тормозов быть не должно, значит используем мутабельные данные". Понятно, что применимость иммутабельных данных зависит от накладных расходов, с ними связанных напрямую. Потому, что именно от этого и зависит — подходят ли тут иммутабельные данные "по условию задачи". _>Демонстрация была с самого начала.
Я не понимаю, на что вы рассчитываете, когда это пишете. Ведь вы же не написали аналога моего кода, либо вообще хоть какого-нибудь кода, который соответствует условию задачи. Что, если вы будете повторять что он был, то он волшебным образом появится? Нет, пока вы его не напишете, он не появится. И какой-то произвольный код, который вычисляет простые числа условию задачи не соответствует. _>Хыхы, ну я этот ужастик даже комментировать не буду.
Конечно, вы вообще ни разу не сказали, что же конкретно не так с кодом, в котором "монадные ужасы".
main = print . len =<< flip (U.foldM step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24) =<< buffer [2, 3::Int] where
step primes x = do
t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes
if t then primes <| x else pure primes
-- если бы контроля за эффектами не было, код бы выглядел вот так:
main = print . len . flip (U.foldl step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24) $ buffer [2, 3::Int] where
step primes x =
if over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes then primes <| x else pure primes
Т.е. издержки и синтаксическая нагрузка от контроля за эффектами есть, но насколько эти издержки серьезны? _>Вы то всё равно не согласитесь с моей оценкой
Тут не важно, соглашусь я с ней или нет. Вы как раз оценивать не стесняетесь, только в этом посте вы заклеймили "монадные ужасы" несколько раз. Дело в том, что вы так и не удосужились сказать в чем они заключаются. Вся критика "монадных ужасов" здесь мной же и написана. Это синтаксические издержки на обслуживание контроля эффектов. т.е. do нотация, не один оператор композиции и один применения всех функций, а еще и дополнительные операторы для композиции стрелок клейсли и стыковки этих двух видов конвейеров, т.е для лифтинга чистых функций.
Что касается упомянутых вами "проблем с поддержкой мутабельности": да, некоторые проблемы с поддержкой мутабельности есть во всех языках с поддержкой иммутабельности. Тут трейдофф. Например, это write barrier, который замедляет работу с мутабельными ссылками в языках с быстрым ГЦ, необходимым для поддержки иммутабельных объектов, вроде Java. _>но зато любой вменяемый читатель сразу же оценит разницу между этим вашим кодом, вашим же кодом для иммутабельного случая
Конечно заметит. Ничего общего (в контексте обсуждения иммутабельности) между первым и вторым кодом нет. _>и кодом на D.
Заметит, что в коде на D короче имена, например iota место U.enumFromStepN, целые числа автоматически приводятся к bool и легковеснее тернарный оператор ?: вместо if then else. Ах да, ещеиэкономиянапробелах. На этом фоне ваши любимые "монадные ужасы" едва заметны. _>Иммутабельность данных в языках типа D или C++ зависят не от класса, а от объекта. Т.е. если мы пишем "const vector<int> data;", то мы не сможем модифицировать data, хотя у него есть метод push_back и т.п.
Это не иммутабельность. Иммутабельность данных означает, что операции заданные над этими данными их не меняют, а возвращают новые версии, сохраняя старые. _>Что касается диапазонов в D, то я бы сказал что они чем-то напоминают IEnumerable в C# с поправкой на попытку делать всё в статике и не терять информацию о типе изначальной коллекции (например если она с произвольным доступом, то это может существенно оптимизировать многие алгоритмы и т.п.).
Ну да. Точнее, IEnumerator, которые этот самый IEnumerable производит. И IEnumerator мутабельный. У него три мутирующих его данные (о положении внутри структуры, которую он обходит и неуправляемых ресурсах, которыми он владеет) метода MoveNext, Reset и Dispose.
Его хаскельный аналог иммутабельный:
-- | Result of taking a single step in a streamdata Step s a = Yield a s -- ^ a new element and a new seed
| Skip s -- ^ just a new seed
| Done -- ^ end of stream
-- | Monadic streamsdata Stream m a = forall s. Stream (s -> m (Step s a)) s Size
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[75]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали: _>>И главное, каким образом мы разместим иерархию типов данного модуля внутри подобного значка модуля? ) K>С использованием инструментария для обозначения вложенных классов. Т.е. внутри элемента или соответствующим отношением (емнип, плюс в круге на конце линии), если инструмент поддерживает.
В uml нет ничего подобного. K>Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете?
Ну например как у нас там обстоят дела с массивом модулей? _>>Чем например D не подходит? ) K>Тем, что не мультипарадигменный.
Типа снова переходим к троллизму? ))) K>Вполне возможно и появится. Сейчас, когда планеты сравнивают, на графиках в координатах период — масса, например, оси обычно логарифмические строят. Так что когда сформируется классификация планет вроде той, что уже для звезд есть — посмотрим какие там будут "рейтинги".
У вас похоже наблюдается по этому вопросу чёткое недопонимание. Повторюсь ещё раз: надо очень чётко разделять наличие логарифмических масштабов на графиках (которые делаются грубо говоря для красоты и соответственно встречаются очень часто) и наличие логарифмов в формулах (которые несут конкретный аналитических смысл и кстати не очень распространены в физике). А у вас постоянно проскальзывает мысль вида "если на графике это лучше отображается с логарифмическом масштабе, то значит и везде в формулах расставим логарифмы", а это полный бред. K>Вы правы в том смысле, что все это началось с человеческой физиологии. Но сейчас это просто инструментарий для работы с большими диапазонами чисел, не только "воспринимаемыми" какими-то органами чувств, но вообще любыми.
Если мы говорим про графики, то безусловно. Если же мы говорим про формулы, то ничего подобного — требуется какое-то обоснование по сути для введения логарифмов. Т.е. вот например для обсуждаемого случая есть некий рейтинг вида R=(S/S_max+G/G_max)*50, а вы по сути предлагаете заменить его чем-то вроде R'=(log(S)/log(S_max)+log(G)/log(G_max))*50. Так вот это будет совсем другой рейтинг и для обоснования наличия смысла в нём совершенно недостаточно аргумента вида "красивее выглядит на графике". K>И если с помощью инструментария можно построить объединение каких-то двух "рейтингов" — в обсуждаемом нами случае SO и github — да еще так, чтоб они друг друга проверяли, то это же хорошо. Без логарифмов, популярность всех языков, кроме, допустим "большой пятерки" была бы одинаковой, зато все члены этой самой большой пятерки отличались бы по популярности друг от друга и от всех остальных крайне существенно. При этом какой бы "измеряемый" показатель мы не брали бы, популярность на ресурсе X, ресурсе Y или число ссылок в поисковике Z — во всех этих случаев популярность внутри пятерки была бы существенно различной, ее никак нельзя было бы согласовать.
Да, всё правильно. Но фокус в том, что в реальности действительно всего десяток языков имеет заметную популярность и при этом продолжают заметно отличаться между собой. Т.е. именно так и должен отображать картину адекватный рейтинг, даже если это вам и не нравится почему-то. K>Неужели эта проблема не понятна?
Я вижу проблему в том, что вы ищите путь подогнать результаты под заранее придуманную картину, а не попытаться понять объективную реальность. K>Проблема в том, что если вы множество чистых функций расширяете добавлением в него "нечистых" — то называть получившееся множество функций нечистыми нет никаких оснований. Вот есть у вас простые числа {2,3,7..} , вы их "расширили" добавлением всех остальных. ладно, не всех остальных, а, допустим, всех четных. Есть у вас теперь основания утверждать, что все четные числа — простые?
Что это за чушь? ) Мы же говорим не о самих множествах, а как раз о функциях над этим множествами. Т.е. вот допустим у нас есть область "функции иммутабельных параметров". Данная область имеется и в Хаскеле (собственно там только она и есть) и в D. И в этой области у нас могут существовать как чистые функции, так и нет. Так вот в этой области определение чистой функции Хаскеля и D будут полностью совпадать. Далее, расширим нашу область, добавив в неё ещё и функции мутабельных параметров (правда такое уже только в D возможно) и снова получим как чистые функции (в значение D) так и нет. K>Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось K>
K>map (p . q) = map p . map q
K>
K>
Скрытый текст
впереди 7 месяцев рассуждений про ненужность контроля эффектов, и почему его отсутствие в ди равняется наличию
Определения чистоты из D для функций p и q как раз уже достаточно для верности данного утверждения. Причём оно позволяет ещё и производить подобное преобразование по месту, а не только с генерацией новых данных.
===============
Здесь пропущено множество возражений на тему теста быстройдествия. Причину см. в конце сообщения.
=============== _>>Да, но и и функциональный код на D можно довести до оптимального быстродействия, слегка подправив алгоритм. Например так: _>>
K>Ну правильно, вы еще уменьшили число стадий конвейера. Но вы же, наверное, понимаете, что для всех случаев специальных функций не найдется, и надо будет пользоваться комбинациями функций между которыми как-то передаются данные?
Ну так а причём тут иммутабельность, комбинаторы и т.п.? ) Вы похоже совсем не понимаете откуда появляется разница в быстродействие в тех двух случаях. Или же вам действительно надо пояснять почему такой код
for(c: col) f(c);
for(c: col) g(c);
и такой код
for(c: col){
f(c);
g(c);
}
будут отличаться по быстродействию на современных компьютерах? Причём это не будет зависеть от языка программирования... _>>Это просто разные подходы к проектированию вообще. У вас подход "всунуть иммутабельные данные везде, _>>А у меня подход "использовать иммутабельные данные там, где они такие по условию задачи". Соответственно при моём подходе область применимость никак не завязана на "поддержку в языке". K>Конечно связано. У вас "использовать иммутабельные данные там, где они такие по условию задачи" означает буквально следующее: K>"По условию задачи тормозов быть не должно, значит используем мутабельные данные". Понятно, что применимость иммутабельных данных зависит от накладных расходов, с ними связанных напрямую. Потому, что именно от этого и зависит — подходят ли тут иммутабельные данные "по условию задачи".
Ээээм, вы серьёзно не понимаете что я хочу сказать? ) Разве не очевидно, что можно поделить используемые данные на мутабельные и иммутабельные уже просто условию задачи, а не по каким-то религиозным или же скоростным причинам? Т.е. грубо говоря ещё даже до выбора языка программирования можно обсуждать иммутабельность разных данных для конкретной задачи... _>>Иммутабельность данных в языках типа D или C++ зависят не от класса, а от объекта. Т.е. если мы пишем "const vector<int> data;", то мы не сможем модифицировать data, хотя у него есть метод push_back и т.п. K>Это не иммутабельность. Иммутабельность данных означает, что операции заданные над этими данными их не меняют, а возвращают новые версии, сохраняя старые.
Ну так всё правильно. У массивов D определены два разных оператора добавления ~ и ~=. Первый возвращает новую версию данных (новый массив), а второй соответственно производит добавление по месту и возвращает старый. Соответственно для просто массива доступны оба оператора, а для массива определённого с модификатором immutable (или const или in) доступен только оператор ~.
И как раз благодаря этому я мог легко продемонстрировать обе версии кода (с мутабельными данными и с иммутабельными) путём изменения всего одного символа в нём. Естественно для проверки я делал более существенные изменения — добавление модификатора immutable в соответствующих местах, который во-первых гарантировал отсутствие использования "нечестных" операторов где-то внутри и во-вторых теоретически мог привнести какие-то ускорения, в случае наличия соответствующих оптимизаций в библиотеке языка. Но т.к. никаких изменений ни в корректности ни в быстродействие добавление immutable не привносило, то для наших целей (измерения быстродействия) его наличие даже и не принципиально.
Все последующие возражения на тему этих наших тестов я пропустил, т.к. пока до вас не дойдут такие базовые вещи из мира императивных языков, как объяснённые выше (и соответственно не будет понято, что код с иммутабельными данными я показал давным давно), говорить собственно не о чем.
Re[76]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В uml нет ничего подобного.
Как же нет? Ну, я не любитель UML, но вот прямо сейчас набрал запрос https://www.google.ru/search?q=inner+class+uml и первые же пара картинок с этим самым отношением.
K>>Не нужно сравнивать модули паскаля. Сравните лучше модули хаскеля — чем вас такая инкапсуляция не устраивает по сравнению с той, что есть в ООЯ — вы претензии озвучить можете? _>Ну например как у нас там обстоят дела с массивом модулей?
Зачем для инкапсуляции нужен массив модулей? Это примерно как спросить "а можно в Java сделать массив атрибутов private?".
_>Типа снова переходим к троллизму? )))
Если вы говорите нечто сомнительное и без всякого подтверждения, а я вам наслово отказываюсь верить — это еще не троллизм.
Впрочем, тут обычное недопонимание.
Вы написали "в которых есть полноценная поддержка и объектов и замыканий и всего остального"
и я, ответил "Как только такой язык появится — обязательно мне сообщите." но это потому, что под "всего остального" я понял то, что я тут перечислял среди поддерживаемого в ФЯ, а вы видимо подразумевали "ничего". И под "поддержкой замыканий" я как обычно подразумевал всякие фичи оптимизатора и рантайма, которые делают их использование практичным, а вы подразумевали, как обычно, "замыкания не нужны, а значит где угодно поддерживаются". Если разворачивать эти слова как я — тогда D, конечно, не подходит. Если как вы — то подходит, как и многие другие языки, так что и спорить не о чем.
K>>Вполне возможно и появится. Сейчас, когда планеты сравнивают, на графиках в координатах период — масса, например, оси обычно логарифмические строят. Так что когда сформируется классификация планет вроде той, что уже для звезд есть — посмотрим какие там будут "рейтинги".
_>У вас похоже наблюдается по этому вопросу чёткое недопонимание. Повторюсь ещё раз: надо очень чётко разделять наличие логарифмических масштабов на графиках (которые делаются грубо говоря для красоты и соответственно встречаются очень часто) и наличие логарифмов в формулах (которые несут конкретный аналитических смысл и кстати не очень распространены в физике).
Во первых, мы говорим о сравнении языков, а тут как раз график и нужен. Во вторых, графики нужны не "для красоты", а для визуализации. В третьих, нету никакого "четкого разделения" между графиком и формулой, наоборот, это разные представления одного и того же.
_>Да, всё правильно. Но фокус в том, что в реальности действительно всего десяток языков имеет заметную популярность и при этом продолжают заметно отличаться между собой.
Естественно. Но в чем выражается это заметное отличие объективно? В показаниях множества "градусников". Эти градусники — число вопросов на одном сайте, число найденных ссылок по запросу на втором сайте, число репозиториев на третьем сайте, число предложений работы на четвертом сайте и т.д. При этом относительные показания для языков у всех "градусников" будут различаться. При этом один рейтинг, который вы называете "нормальным" усредняет показания части "градусников" с некими поправочными к-тами и этот метод усреднения постоянно меняется. Т.е. это некий черный ящик, который что-то показывает, вдруг начинает показывать что-то другое и т.д. Тот же рейтинг, который позволяет оценить корреляцию между показаниями "градусников" и критически оценить точность оценки для разных групп по разбросу точек на графике вы почему-то считаете "ненормальным".
_>Т.е. именно так и должен отображать картину адекватный рейтинг, даже если это вам и не нравится почему-то.
Т.е. адекватный рейтинг должен поддерживать сравнение только между популярными языками? Почему? Мне не нравится вот что:
1) Нельзя сравнивать непопулярные языки. 2) Нельзя адекватно оценивать разницу между популярными, потому что из-за экспоненциального роста показанного в нелогарифмических координатах создается ощущение непреодолимых пропастей между популярными языками, которые на самом деле достаточно быстро преодолеваются (динамика популярности у языков с высокой популярностью тоже может быть очень высокой).
_>Я вижу проблему в том, что вы ищите путь подогнать результаты под заранее придуманную картину, а не попытаться понять объективную реальность.
Непонятно, на чем вы основываете свое наблюдение. Что подо что я хочу подогнать, критикуя TIOBE? B в том и в другом рейтинге разницы между теми языками которые мы сравнивали (Haskell и Go) нет, так что и куда я подгоняю?
_>вот допустим у нас есть область "функции иммутабельных параметров". Данная область имеется и в Хаскеле (собственно там только она и есть) и в D. И в этой области у нас могут существовать как чистые функции, так и нет. Так вот в этой области определение чистой функции Хаскеля и D будут полностью совпадать. Далее, расширим нашу область, добавив в неё ещё и функции мутабельных параметров (правда такое уже только в D возможно) и снова получим как чистые функции (в значение D) так и нет.
Нет, дело обстоит вот так: есть функции чистые в математическом и хаскельном смысле. А есть процедуры, которые под это определение не попадают. И в D компилятор проверяет некую "дишную чистоту", при этом функции и соответствующие мат. определению и не соответствующие ему в ди могут считаться чистыми. При этом функции, которые соответствуют мат. определению чистоты также могут не соответствовать дишному определению чистоты. Потому, что дишная чистота — это проверка на принадлежность данных потоку, никакого отношения к чистоте и функциям она не имеет, просто так называется. Одно другое никак не расширяет и не сужает.
Про "область "функции иммутабельных параметров"" вообще что-то странное. В хаскеле есть чистые функции, которые работают с "мутабельными параметрами" они там отличаются тем же, чем в ди отличаются "функции целочисленных параметров" от, например, "функций строковых параметров".
K>>Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось K>>
K>>map (p . q) = map p . map q
K>>
_>Определения чистоты из D для функций p и q как раз уже достаточно для верности данного утверждения.
Нет, недостаточно.
_>Причём оно позволяет ещё и производить подобное преобразование по месту, а не только с генерацией новых данных.
Ничего не понятно.
_>Ну так а причём тут иммутабельность, комбинаторы и т.п.? ) _>Вы похоже совсем не понимаете откуда появляется разница в быстродействие в тех двух случаях. Или же вам действительно надо пояснять почему такой код _>
_>for(c: col) f(c);
_>for(c: col) g(c);
_>
и такой код _>
_>for(c: col){
_> f(c);
_> g(c);
_>}
_>
_>будут отличаться по быстродействию на современных компьютерах? Причём это не будет зависеть от языка программирования...
Вот причем:
Упрощенно говоря, когда вы используете иммутабельные структуры данных и комбинировать комбинаторы вы при наивной реализации чаще будете получать код первого типа. Поэтому, "поддержкой иммутабельности и комбинаторов" я называю способность того, что поддерживает сводить код первого типа к коду второго типа, т.е. уменьшать число проходов, улучшать локальность и т.д. И от языка программирования, а точнее от степени наивности реализации его компилятора и рантайма тут будет зависеть все.
Понятно теперь что тут причем?
_>Ээээм, вы серьёзно не понимаете что я хочу сказать? )
Отлично понимаю. Вы натягиваете свое решение на глобус моей задачи любыми средствами. В место того, чтоб сделать нормальное решение, которое натягивать не нужно или сообщить, что вы его делать не хотите/не можете и т.д.
_>Разве не очевидно, что можно поделить используемые данные на мутабельные и иммутабельные уже просто условию задачи, а не по каким-то религиозным или же скоростным причинам? Т.е. грубо говоря ещё даже до выбора языка программирования можно обсуждать иммутабельность разных данных для конкретной задачи...
Т.е. вы делите данные на иммутабельные и мутабельные не по причине удобства работы и "скоростных соображений", а по некоим "простоусловиям задачи". Похоже, что религия как раз у вас.
Иммутабельность данных удобна для программиста, но может быть и часто бывает неэффективна с точки зрения производительности. Это определяет область применения иммутабельных данных. Поддержка снижает часть издержек, и таким образом расширяет область применения удобного для программиста к радости этого самого программиста.
Вот и все.
_>У массивов D определены два разных оператора добавления ~ и ~=. Первый возвращает новую версию данных (новый массив), а второй соответственно производит добавление по месту и возвращает старый.
Проблема не в массиве. Я же вам объясняю, да — в единственно месте вы меняете мутабельность данных — в случае как раз этого массива. Все остальные промежуточные данные у вас диапазоны-итераторы, которые всегда мутабельны.
_>И как раз благодаря этому я мог легко продемонстрировать обе версии кода (с мутабельными данными и с иммутабельными) путём изменения всего одного символа в нём.
Вы, путем изменения символа в одном месте меняете мутабельность промежуточных данных в одном месте. В остальных 256-и местах конвейера вы мутабельность промежуточных данных не меняете.
_>Все последующие возражения на тему этих наших тестов я пропустил...
... так как ответить по теме нечего, потому вы слезаете с темы и начинаете объяснять понятные всем вещи.
В следующем ответе не пропускайте то, что я вам пишу, а наоборот, отвечайте на вопросы и комментируйте, так выйдет гораздо лучше.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[77]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Как же нет? Ну, я не любитель UML, но вот прямо сейчас набрал запрос https://www.google.ru/search?q=inner+class+uml и первые же пара картинок с этим самым отношением.
Нет, значит нет. Можно посмотреть подробнее например тут http://www.uml-diagrams.org/nested-classifier.html. Ну и главное (из-за чего мы собственно обсуждали эти нюансы) — в трёх используемых мною uml инструментах (кстати одних из самых известных) нет ничего подобного.
Кстати, ещё по ассоциации появился вопрос на близкую тему: есть ли аналог doxygen'a для хаскеля? И если есть, то умеет ли он генерировать какие-то диаграммы? И если умеет, то какие?
K>Зачем для инкапсуляции нужен массив модулей? Это примерно как спросить "а можно в Java сделать массив атрибутов private?".
Именно "массив модулей" не требуется. Требуется (и очень часто) массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы. Вы говорите, что инкаспсуляция в хаскеле реализована через модули. Соответственно сразу возникает вопрос: как у нас обстоят дела с массивами модулями и т.п?
K>Естественно. Но в чем выражается это заметное отличие объективно? В показаниях множества "градусников". Эти градусники — число вопросов на одном сайте, число найденных ссылок по запросу на втором сайте, число репозиториев на третьем сайте, число предложений работы на четвертом сайте и т.д. При этом относительные показания для языков у всех "градусников" будут различаться. При этом один рейтинг, который вы называете "нормальным" усредняет показания части "градусников" с некими поправочными к-тами и этот метод усреднения постоянно меняется. Т.е. это некий черный ящик, который что-то показывает, вдруг начинает показывать что-то другое и т.д. Тот же рейтинг, который позволяет оценить корреляцию между показаниями "градусников" и критически оценить точность оценки для разных групп по разбросу точек на графике вы почему-то считаете "ненормальным".
Да, лично я вижу весьма существенную разницу между линейной комбинацией параметров и нелинейной функцией от них. Кстати, замечу, что даже по вашей ссылке рейтинг опять же вычислялся как просто среднее от двух параметров. Точнее он должен был бы так вычисляться, судя по их описанию, но на практике похоже просто бралось значения одного параметра. Но в любом случае никаких логарифмов или других нелинейных функций.
K>Т.е. адекватный рейтинг должен поддерживать сравнение только между популярными языками? Почему? Мне не нравится вот что: K>1) Нельзя сравнивать непопулярные языки. 2) Нельзя адекватно оценивать разницу между популярными, потому что из-за экспоненциального роста показанного в нелогарифмических координатах создается ощущение непреодолимых пропастей между популярными языками, которые на самом деле достаточно быстро преодолеваются (динамика популярности у языков с высокой популярностью тоже может быть очень высокой).
Ну почему же. Тот же tiobe вполне себе позволяет сравнивать и непопулярные. Да и существенная разница в значениях для популярных очень даже нормально интуитивно ощущается.
K>Нет, дело обстоит вот так: есть функции чистые в математическом и хаскельном смысле. А есть процедуры, которые под это определение не попадают. И в D компилятор проверяет некую "дишную чистоту", при этом функции и соответствующие мат. определению и не соответствующие ему в ди могут считаться чистыми.
Это верно. Только надо добавить, что сочетание модификаторов pure и immutable (для параметров) даст как раз в точности хаскельное определение. Т.е. всё же имеем однозначное подмножество.
K>При этом функции, которые соответствуют мат. определению чистоты также могут не соответствовать дишному определению чистоты.
Жду пример такой функции... )
K>>>Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось K>>>
K>>>map (p . q) = map p . map q
K>>>
_>>Определения чистоты из D для функций p и q как раз уже достаточно для верности данного утверждения. K>Нет, недостаточно.
Жду пример функций p и q, имеющих модификатор pure и для которых данное равенство не выполняется.
K>Вот причем: K>Упрощенно говоря, когда вы используете иммутабельные структуры данных и комбинировать комбинаторы вы при наивной реализации чаще будете получать код первого типа. Поэтому, "поддержкой иммутабельности и комбинаторов" я называю способность того, что поддерживает сводить код первого типа к коду второго типа, т.е. уменьшать число проходов, улучшать локальность и т.д. И от языка программирования, а точнее от степени наивности реализации его компилятора и рантайма тут будет зависеть все. K>Понятно теперь что тут причем?
Ага, ага... Осталось только продемонстрировать, что Хаскель реализует такую оптимизацию... )
K>Т.е. вы делите данные на иммутабельные и мутабельные не по причине удобства работы и "скоростных соображений", а по некоим "простоусловиям задачи". Похоже, что религия как раз у вас.
Что значит "неким условиям"? ) Если мы точно знаем, что определённый кусок данных является неизменным (при программирование в обычном императивном стиле) на протяжение всей своей жизни, то перевод его в иммутабельный статус гарантированно не понизит быстродействие. А возможно и повысит его. И в любом случае повысит надёжность кода.
Кстати, только сейчас, при написание предыдущей фазы, понял ещё один минус подхода с иммутабельностью как в Хаскеле — он не помогает явно декларировать в коде инварианты задачи.
K>Проблема не в массиве. Я же вам объясняю, да — в единственно месте вы меняете мутабельность данных — в случае как раз этого массива. Все остальные промежуточные данные у вас диапазоны-итераторы, которые всегда мутабельны.
Ээээм. Вообще то тут нет никаких промежуточных данных. Все операции работают только с одним массивом и всё. Если же вы подразумеваете под промежуточными данными индексы, используемые при пробеге по массиву внутри функций работы с диапазонами, то это абсолютно равносильно утверждению, что ваш хаскельный код работает с мутабельными данными, т.к. в итоге компилятор Хаскеля преобразовывает все пробеги по массивам (да и вообще все нужные рекурсии) в циклы, внутри которых используется мутабельный индекс.
K>Вы, путем изменения символа в одном месте меняете мутабельность промежуточных данных в одном месте. В остальных 256-и местах конвейера вы мутабельность промежуточных данных не меняете.
Во-первых все эти функции диапазонов и т.п. являются шаблонами. И соответственно при использование иммутабельного базового типа доступ к мутабельному набору функций блокируется. Т.е. если где-то в начале мы использовали соответствующий тип, то компилятор не позволит использовать мутирующие контейнер функции на протяжение всей цепочки.
А во-вторых (и это главное) в данном коде вообще ровно одна точка модификации нашего массива (которую уже обсудили), так что никаких мутирующих промежуточных данных нет. Или вы всё про индексы используемые для пробега по массиву где-то внутри библиотечных функций? )
Re[78]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, значит нет. Можно посмотреть подробнее например тут http://www.uml-diagrams.org/nested-classifier.html. Ну и главное (из-за чего мы собственно обсуждали эти нюансы) — в трёх используемых мною uml инструментах (кстати одних из самых известных) нет ничего подобного.
Ну значит есть что-то другое для обозначения вложенных классов. В конце концов, можно доступные в инструменте и близкие по смыслу отношения использовать. Или языки со вложенными классами для использования UML тоже не подходят?
_>Кстати, ещё по ассоциации появился вопрос на близкую тему: есть ли аналог doxygen'a для хаскеля?
Есть.
_>И если есть, то умеет ли он генерировать какие-то диаграммы? И если умеет, то какие?
Думаю, что нет. По крайней мере, я никогда никакие диаграммы для кода на хаскеле не генерировал (но я этого и для кода на других языках обычно не делаю).
K>>Зачем для инкапсуляции нужен массив модулей? Это примерно как спросить "а можно в Java сделать массив атрибутов private?".
_>Именно "массив модулей" не требуется. Требуется (и очень часто) массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы. Вы говорите, что инкаспсуляция в хаскеле реализована через модули. Соответственно сразу возникает вопрос: как у нас обстоят дела с массивами модулями и т.п?
Ну вот, а в Java инкапсуляция "реализована через атрибуты private". Ну так вот, когда вам "Требуется массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы" вам при этом требуется массив атрибутов private или нет?
_>рейтинг опять же вычислялся как просто среднее от двух параметров. Точнее он должен был бы так вычисляться, судя по их описанию, но на практике похоже просто бралось значения одного параметра. Но в любом случае никаких логарифмов или других нелинейных функций.
сообщение читали?
_>Тот же tiobe вполне себе позволяет сравнивать и непопулярные.
Как же позволяет, если они все примерно одинаковые получаются?
_>Это верно. Только надо добавить, что сочетание модификаторов pure и immutable (для параметров) даст как раз в точности хаскельное определение.
Конечно нет, потому что хаскельная чистая функция иммутабельности параметров не требует.
K>>При этом функции, которые соответствуют мат. определению чистоты также могут не соответствовать дишному определению чистоты. _>Жду пример такой функции... )
putStrLn
_>Жду пример функций p и q, имеющих модификатор pure и для которых данное равенство не выполняется.
Чем вас пример D.Mon не устраивает?
_>Ага, ага... Осталось только продемонстрировать, что Хаскель реализует такую оптимизацию... )
_>Что значит "неким условиям"? ) Если мы точно знаем, что определённый кусок данных является неизменным (при программирование в обычном императивном стиле) на протяжение всей своей жизни, то перевод его в иммутабельный статус гарантированно не понизит быстродействие. А возможно и повысит его. И в любом случае повысит надёжность кода.
А то, какой "кусок данных" окажется неизменным, как раз из озвученных мной соображений и определяется. Т.е. из баланса удобства деланья его неизменным и штрафов, которые мы за эту неизменность получаем по времени и памяти.
_>Кстати, только сейчас, при написание предыдущей фазы, понял ещё один минус подхода с иммутабельностью как в Хаскеле — он не помогает явно декларировать в коде инварианты задачи.
Можете вот это расшифровать?
_>Ээээм. Вообще то тут нет никаких промежуточных данных.
Замечательно! Т.е. вы сами же считаете, что поставленную задачу вы не выполнили. Читаем задачу "Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных..." здесь http://rsdn.ru/forum/philosophy/5559447.1
На самом деле промежуточные данные конечно есть — только они мутабельные, что впрочем тоже условию задачи не соответствует.
_>Если же вы подразумеваете под промежуточными данными индексы, используемые при пробеге по массиву внутри функций работы с диапазонами,
Да, именно их я и имею в виду.
_>то это абсолютно равносильно утверждению, что ваш хаскельный код работает с мутабельными данными, т.к. в итоге компилятор Хаскеля преобразовывает все пробеги по массивам (да и вообще все нужные рекурсии) в циклы, внутри которых используется мутабельный индекс.
Разумеется это не равносильно. В первом случае есть код на D, который содержит работу с мутабельными данными. И преобразуется потом в некий промежуточный результат (уже не D) в ходе кодогенерации который тоже содержит работу с мутабельными данными. Во втором случае есть код на хаскеле, который содержит работу с иммутабельными данными, и преобразуется потом в некий промежуточный результат (уже не хаскель) в ходе кодогенерации который содержит работу с мутабельными данными. Т.е. кода на хаскеле, работающего с мутабельными данными нет, а на D такой код есть. Разница понятна?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[79]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну значит есть что-то другое для обозначения вложенных классов. В конце концов, можно доступные в инструменте и близкие по смыслу отношения использовать. Или языки со вложенными классами для использования UML тоже не подходят?
В этих язык оно обычно имеет смысл просто пространства имён и соответственно отображается на диаграммах. Но вы то наоборот хотите на базе этого создать всю свою диаграмму. )))
_>>И если есть, то умеет ли он генерировать какие-то диаграммы? И если умеет, то какие? K>Думаю, что нет. По крайней мере, я никогда никакие диаграммы для кода на хаскеле не генерировал (но я этого и для кода на других языках обычно не делаю).
Печально, печально. Это весьма удобный инструмент для изучения кода. Можно глянуть пример скажем здесь http://docs.wxwidgets.org/3.0/classwx_evt_handler.html — с учётом возможности навигации по классам с помощью клику по нему на диаграммке получается крайне удобный инструмент.
K>Ну вот, а в Java инкапсуляция "реализована через атрибуты private". Ну так вот, когда вам "Требуется массив неких сущностей, которые при этом умеют инкапсулировать некие внутренние нюансы" вам при этом требуется массив атрибутов private или нет?
В Java мне предоставляют массив объектов, каждый из которых обладает атрибутом private. А массив каких сущностей, обладающих возможностью инкапсуляции, может предложить Хаскель?
_>>Тот же tiobe вполне себе позволяет сравнивать и непопулярные. K>Как же позволяет, если они все примерно одинаковые получаются?
В смысле примерно одинаковые? Там полсотни языков с довольно равномерным распределением не популярных.
K>putStrLn
И с каких пор эта функция стала чистой? )
K>Чем вас пример D.Mon не устраивает?
У D.Mon где-то был пример в котором map (p . q) != map p . map q для чистых p и q? )
K>Это в этом разговоре уже было продемонстрировано здесь http://rsdn.ru/forum/philosophy/5441040.1
Это даже близко не имеет никакого отношения к обсуждаемой проблеме. В данном случае мы изначально имели код вида
is_prime= v=> primes.until(p^^2>v).all(v%p!=0);
и заменили его для оптимизации (и это довело быстродействие до равного явному циклу) на код вида:
is_prime= v=> primes.find(v%p==0||p^^2>v)^^2>v;
С удовольствием посмотрю как реализована автоматизация подобной оптимизации в Хаскеле...
K>А то, какой "кусок данных" окажется неизменным, как раз из озвученных мной соображений и определяется. Т.е. из баланса удобства деланья его неизменным и штрафов, которые мы за эту неизменность получаем по времени и памяти.
Понятно... Т.е. видеть реальную неизменность данных в условиях задачи вы не умеете...
_>>Кстати, только сейчас, при написание предыдущей фазы, понял ещё один минус подхода с иммутабельностью как в Хаскеле — он не помогает явно декларировать в коде инварианты задачи. K>Можете вот это расшифровать?
Судя по предыдущему абзацу это бесполезно.
K>Замечательно! Т.е. вы сами же считаете, что поставленную задачу вы не выполнили. Читаем задачу "Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных..." здесь http://rsdn.ru/forum/philosophy/5559447.1
Потому как в D они просто не нужны. Кстати говоря, в конкретно этой задачке в принципе можно было и на Хаскеле организовать такое же (и без мутабельных структур при этом). Достаточно реализовать некое подобие диапазонов, но соответственно через рекурсии и т.п.
_>>Если же вы подразумеваете под промежуточными данными индексы, используемые при пробеге по массиву внутри функций работы с диапазонами, K>Да, именно их я и имею в виду. _>>то это абсолютно равносильно утверждению, что ваш хаскельный код работает с мутабельными данными, т.к. в итоге компилятор Хаскеля преобразовывает все пробеги по массивам (да и вообще все нужные рекурсии) в циклы, внутри которых используется мутабельный индекс.
K>Разумеется это не равносильно. В первом случае есть код на D, который содержит работу с мутабельными данными. И преобразуется потом в некий промежуточный результат (уже не D) в ходе кодогенерации который тоже содержит работу с мутабельными данными. Во втором случае есть код на хаскеле, который содержит работу с иммутабельными данными, и преобразуется потом в некий промежуточный результат (уже не хаскель) в ходе кодогенерации который содержит работу с мутабельными данными. Т.е. кода на хаскеле, работающего с мутабельными данными нет, а на D такой код есть. Разница понятна?
В таком случае, если я перепишу в стандартной библиотеке D внутренности реализации диапазонов и алгоритмов через рекурсии (при этом скорее всего ни код моего примера в этой задачке, ни итоговый бинарник не изменятся), то всё резко станет в точности как в Хаскеле?
Re[80]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В этих язык оно обычно имеет смысл просто пространства имён и соответственно отображается на диаграммах.
Не обязательно. Ну а если в случае хаскеля будет "смысл просто пространства имён"?
_>Но вы то наоборот хотите на базе этого создать всю свою диаграмму.
С чего бы это? Мне показалось просто, что вы видите какую-то проблему с вложенными сущностями. Если нет — вообще не понятно, в чем претензии-то? Если можно на диаграмме классов показывать стат.классы, интерфейсы, классы — почему нельзя модули, классы типов, АлгТД?
_>Печально, печально. Это весьма удобный инструмент для изучения кода. Можно глянуть пример скажем здесь http://docs.wxwidgets.org/3.0/classwx_evt_handler.html — с учётом возможности навигации по классам с помощью клику по нему на диаграммке получается крайне удобный инструмент.
Какие-то построители таких схем есть и для хаскеля — http://code.haskell.org/~ivanm/Sample_SourceGraph/graphviz/graphviz.html — но я ими никогда не пользовался, как не пользовался такими средствами и для других языков, так что ничего подробно о них рассказать не могу.
_>В Java мне предоставляют массив объектов, каждый из которых обладает атрибутом private. А массив каких сущностей, обладающих возможностью инкапсуляции, может предложить Хаскель?
Массив значений алгебраических типов данных, конструкторы которых можно экспортировать, а можно — не.
_>В смысле примерно одинаковые? Там полсотни языков с довольно равномерным распределением не популярных.
Со всеми перечисленными мной в предыдущих постах недостатками.
_>И с каких пор эта функция стала чистой? )
Она чистая по построению (с объяснения этого все мое участие в этой ветке и начинается), так что с момента ее написания.
_>У D.Mon где-то был пример в котором map (p . q) != map p . map q для чистых p и q? )
У него был пример "чистой" функции, которая изменяет передаваемые ей объекты, без всякой системы упорядочивания этих действий. Это значит, что обсуждаемый закон для такой функции не выполняется.
_>Это даже близко не имеет никакого отношения к обсуждаемой проблеме.
Конечно имеет.
_>В данном случае мы изначально имели код вида _>
_>С удовольствием посмотрю как реализована автоматизация подобной оптимизации в Хаскеле...
Такой код на хаскеле:
is_prime :: Int -> Vector Int -> Bool
is_prime v primes = all (\p -> v `mod` p /= 0) . takeWhile (\p -> p^2 <= v) $ primes
преобразуется вот в такой:
is_prime :: Int -> Vector Int -> Bool
is_prime v (Vector start len vec) =
case len < 0 of
False ->
let x0 = vec ! start in
case x0*x0 <= v of
False -> True
True ->
case v `mod` x0 of
0 -> False
_ -> let loop sc =
case len < sc of
False ->
let x = vec ! (start + sc) in
case x*x <= v of
False -> True
True ->
case v `mod` x of
0 -> False
_ -> loop (sc + 1)
True -> True
in loop 1;
True -> True
с точностью до преобразования между хаскелем и одним из промежуточных представлений кода в кодогенераторе.
Ровно такие примеры в приведенных мной ссылках и рассмотрены.
Из чего, собственно, можно сделать вывод, что и этот пример вы проигнорируете и напишете про "не имеет отношения".
_>Понятно... Т.е. видеть реальную неизменность данных в условиях задачи вы не умеете...
Никакой "реальной неизменности данных" не существует, потому что память изменяема. Даже если мы храним какую-нибудь предвычисленную таблицу синусов, которую менять нет смысла — пи четырем даже в военное время равняться не станет — все равно вопрос изменяемости этих данных решается исходя из баланса удобства и вычислительных возможностей: например, у нас мало памяти, и часть таблицы, которая больше использоваться не будет можно переписать чем-то другим.
_>Судя по предыдущему абзацу это бесполезно.
Т.е. не можете (что можно было ожидать из опыта предыдущего рзговора).
K>>Замечательно! Т.е. вы сами же считаете, что поставленную задачу вы не выполнили. Читаем задачу "Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных..." здесь http://rsdn.ru/forum/philosophy/5559447.1
Ну так об этом и речь. Вы говорите что что-то поддерживается, имея в виду, что это "не нужно". Однако у многие другие люди, включая и меня — подразумевают совсем другое. В этом и причина недопонимания.
_>В таком случае, если я перепишу в стандартной библиотеке D внутренности реализации диапазонов и алгоритмов через рекурсии (при этом скорее всего ни код моего примера в этой задачке,
Скорее всего так и будет.
_>ни итоговый бинарник не изменятся)
Если он не изменится, то значит задание опять не выполнено. Потому что по заданию нужно создавать как устранимые аллокации (чтоб дать возможность продемонстрировать оптимизатор), так и неустранимые, чтоб создать работу для менеджера памяти.
Впрочем, я сильно сомневаюсь, что если вы изменение индексов при продвижении итераторов замените на выделение новых итераторов в памяти (что, собственно и означает иммутабельность данных) — итоговый бинарник не изменится.
_>то всё резко станет в точности как в Хаскеле?
Если вы перепишите свой код так, чтоб он отвечал заданию, то он будет иметь какое-то отношение к нашему разговору про поддержку иммутабельности. пока что он совершенно нерелевантен.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[81]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Не обязательно. Ну а если в случае хаскеля будет "смысл просто пространства имён"?
Так на диаграмме это просто отображается как некий префикс к имени класса. Типа std::string. Т.е. не получится строить из этого нормальную диаграмму (где есть всякие отношения и т.п.).
K>С чего бы это? Мне показалось просто, что вы видите какую-то проблему с вложенными сущностями. Если нет — вообще не понятно, в чем претензии-то? Если можно на диаграмме классов показывать стат.классы, интерфейсы, классы — почему нельзя модули, классы типов, АлгТД?
Напомню мою основную претензию, на которую так и не было ответа: как у нас отображаются функции (которые в отличие от ООП могут нести основную смысловую нагрузку программы) на диаграмме? У вас была попытка ответить через размещение модулей на диаграмме классов, но как мы видим это получается бредово.
K>Какие-то построители таких схем есть и для хаскеля — http://code.haskell.org/~ivanm/Sample_SourceGraph/graphviz/graphviz.html — но я ими никогда не пользовался, как не пользовался такими средствами и для других языков, так что ничего подробно о них рассказать не могу.
Ага, какие-то попытки идти по правильному пути есть, но им ещё очень далеко до чего-то реального. И скорее всего так и будет оставаться, пока не будут разработаны и общеприняты (возможно включены в тот же UML) какие-то новые виды диаграмм, специально для функционального программирования.
K>Массив значений алгебраических типов данных, конструкторы которых можно экспортировать, а можно — не.
Воот, это уже ближе к делу... И как мы видим, уже никаких модулей — они резко отступают на роль модулей Паскаля или вообще h/c файлов в C. И инкапсуляция того уже уровня выходит. )))
K>Она чистая по построению (с объяснения этого все мое участие в этой ветке и начинается), так что с момента ее написания.
Т.е. мы можем спокойно закэшировать пару одинаковых вызовов putStrLn, как и положено с любой чистой функцией? )
K>У него был пример "чистой" функции, которая изменяет передаваемые ей объекты, без всякой системы упорядочивания этих действий. Это значит, что обсуждаемый закон для такой функции не выполняется.
Ну так покажите где он там не выполняется... Я вот вижу другое:
auto p(ref int v) pure {return ++v+1;}
auto q(int v) pure {return v*2;}
//проверяем, что p действительно модифицирующаяauto data=[1, 2, 3, 4, 5];
data.writeln;//выводит: [1, 2, 3, 4, 5]
data.map!p.writeln;//выводит: [3, 4, 5, 6, 7]
data.writeln;//выводит: [2, 3, 4, 5, 6]
//и собственно проверка нашего равенства
[1, 2, 3, 4, 5].map!p.map!q.writeln;//выводит: [6, 8, 10, 12, 14]
[1, 2, 3, 4, 5].map!(x=>x.p.q).writeln;//выводит: [6, 8, 10, 12, 14]
Да, кстати, т.к. в D оставлена возможность самого низкоуровневого доступа, то вообще говоря модификатор pure вполне можно обмануть с помощью игр с указателями (причём для этого даже не требуется право модифицировать параметры)... Но я надеюсь, что тут не требуется пояснять разницу между сознательным попытками обмануть компилятор и нормальным программированием? )
K>Такой код на хаскеле: K>
K>is_prime :: Int -> Vector Int -> Bool
K>is_prime v primes = all (\p -> v `mod` p /= 0) . takeWhile (\p -> p^2 <= v) $ primes
K>
K>преобразуется вот в такой: K>... K>с точностью до преобразования между хаскелем и одним из промежуточных представлений кода в кодогенераторе.
Весьма сомнительно, т.к. иначе с чего бы это ваш вариант вычислений с мутабельными данными на Хаскеле в несколько раз более тормознутый, чем вариант на D? ) Да и к тому же вы не показали собственно с помощью чего производятся подобные оптимизации или это магия? )))
K>Никакой "реальной неизменности данных" не существует, потому что память изменяема. Даже если мы храним какую-нибудь предвычисленную таблицу синусов, которую менять нет смысла — пи четырем даже в военное время равняться не станет — все равно вопрос изменяемости этих данных решается исходя из баланса удобства и вычислительных возможностей: например, у нас мало памяти, и часть таблицы, которая больше использоваться не будет можно переписать чем-то другим.
Ооо, наконец то начинает появляться понимание... Кстати, замечу, что неизменяемое значение должно быть таким только на протяжение своей жизни. Так что immutable табличку вполне можно стереть после использования и заменить ту же самую ячейку памяти новыми данными (возможно тоже неизменяемыми).
_>>ни итоговый бинарник не изменятся) K>Если он не изменится, то значит задание опять не выполнено. Потому что по заданию нужно создавать как устранимые аллокации (чтоб дать возможность продемонстрировать оптимизатор), так и неустранимые, чтоб создать работу для менеджера памяти.
То, что тестирование работы с иммутабельными данными равносильно насилованию менеджера памяти — это исключительно ваш тезис. Причём в D (в котором есть множество различных способов размещения данных) это вообще выглядит крайне смешно.
K>Впрочем, я сильно сомневаюсь, что если вы изменение индексов при продвижении итераторов замените на выделение новых итераторов в памяти (что, собственно и означает иммутабельность данных) — итоговый бинарник не изменится.
Выделение не обязательно делать в динамической памяти. Можно и на стеке и тогда при сворачивание рекурсии в цикл мы можем получить практически точную копию текущего библиотечного кода.
Re[82]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Так на диаграмме это просто отображается как некий префикс к имени класса. Типа std::string. Т.е. не получится строить из этого нормальную диаграмму (где есть всякие отношения и т.п.).
Так почему не получится? Есть у вас вложенные классы. Вы можете их обозначать просто с префикосом к имени, если этого достаточно. Можете с помощью имеющихся отношений (вы же сами ссылку на пример и дали) их обозначать, если префикса недостаточно. И этих возможностей хватит чтоб строить диаграммы для хаскель-кода. _>Напомню мою основную претензию, на которую так и не было ответа: как у нас отображаются функции (которые в отличие от ООП могут нести основную смысловую нагрузку программы) на диаграмме? У вас была попытка ответить через размещение модулей на диаграмме классов, но как мы видим это получается бредово.
Так в чем бредовость? Чем это бредовее отображения на диаграмме класса у которого есть методы и вложенные классы? _>Ага, какие-то попытки идти по правильному пути есть, но им ещё очень далеко до чего-то реального. И скорее всего так и будет оставаться, пока не будут разработаны и общеприняты (возможно включены в тот же UML) какие-то новые виды диаграмм, специально для функционального программирования.
Мы так и не выяснили, что туда нужно добавлять, если там и так уже все необходимое есть.
Впрочем, "так и будет оставаться" — это верно, потому что популярность такого рода диаграмм в ФП-комьюнити крайне низкая и почти никто в этом направлении не работает. K>>Массив значений алгебраических типов данных, конструкторы которых можно экспортировать, а можно — не. _>Воот, это уже ближе к делу... И как мы видим, уже никаких модулей
Как никаких модулей? Модули вот здесь "можно экспортировать, а можно — не".
У вас — грубо говоря — получается, что если инкапсуляция обозначается так:
public foo;
public bar;
public baz;
то она есть, а если так
public (foo, bar, baz)
foo;
bar;
baz;
то ее нет. K>>Она чистая по построению (с объяснения этого все мое участие в этой ветке и начинается), так что с момента ее написания. _>Т.е. мы можем спокойно закэшировать пару одинаковых вызовов putStrLn, как и положено с любой чистой функцией? )
Можно ли "закэшировать пару вызовов" функций зависит от того, можно ли закэшировать значение которое она возвращает. Определение чистой функции тут только притом, что мы переходим к рассуждению о свойствах этого самого возвращаемого значения.
Если вы хотите сказать, что
putStrLn "foo" >> putStrLn "foo"
и
let f = putStrLn "foo"in f >> f
это одно и то же — то да, так и есть. K>>У него был пример "чистой" функции, которая изменяет передаваемые ей объекты, без всякой системы упорядочивания этих действий. Это значит, что обсуждаемый закон для такой функции не выполняется. _>Ну так покажите где он там не выполняется...
D я не знаю, но принцип, думаю, понятен:
> let f (i : int ref) a = a + !i;;
val f : i:int ref -> a:int -> int
> let g (i : int ref) b = i := b; b;;
val g : i:int ref -> b:int -> int
> let i = ref 0 in List.map (f i) << List.map (g i) <| [1..10];;
val it : int list = [11; 12; 13; 14; 15; 16; 17; 18; 19; 20]
> let i = ref 0 in List.map (f i << g i) <| [1..10];;
val it : int list = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]
_>Весьма сомнительно,
Я просто скомпилировал указанный код на хаскеле с ключем -O2 -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques -dppr-case-as-let
И получил дамп промежуточного представления такого вот вида:
Скрытый текст
\ w w1 ->
let { Vector ipv ipv1 ipv2 ~ _ <- w1 `cast` ... } in
case >=# 0 ipv1 of _ {
False ->
let { I# y ~ _ <- w } in
let { __DEFAULT ~ wild <- indexIntArray# ipv2 ipv } in
case <=# (*# wild wild) y of _ {
False -> True;
True ->
case wild of wild4 {
__DEFAULT ->
case modInt# y wild4 of _ {
__DEFAULT ->
letrec {
$s$wand_loop
$s$wand_loop =
\ sc ->
case >=# sc ipv1 of _ {
False ->
let { __DEFAULT ~ wild6 <- indexIntArray# ipv2 (+# ipv sc) } in
case <=# (*# wild6 wild6) y of _ {
False -> True;
True ->
case wild6 of wild8 {
__DEFAULT ->
case modInt# y wild8 of _ {
__DEFAULT -> $s$wand_loop (+# sc 1);
0 -> False
};
(-1) -> False;
0 -> case divZeroError of wild9 { }
}
};
True -> True
}; } in
$s$wand_loop 1;
0 -> False
};
(-1) -> False;
0 -> case divZeroError of wild5 { }
}
};
True -> True
}
и перевел его обратно в хаскель с некоторыми не влияющими на смысл упрощениями. _>т.к. иначе с чего бы это ваш вариант вычислений с мутабельными данными на Хаскеле в несколько раз более тормознутый, чем вариант на D? )
1) Мы их никогда не запускали на одной машине. так что описанные несколько раз это в основном ваше wishful thinking.
2) Это не весь код, а только часть его — не везде промежуточные данные могут быть устранены оптимизатором.
3) Мало ли что там могло отличаться, к примеру в случае D могли быть i32, а в случае хаскеля i64 и так далее.
4) Мало ли что там могло тормозить? Я этот код не оптимизировал. _>Да и к тому же вы не показали собственно с помощью чего производятся подобные оптимизации или это магия? )))
Это обычные общеполезные оптимизации для ФЯ + правила перезаписи, небольшой пример и объяснение работы которых я уже в этой ветке раньше показывал.
В данном случае это stream fusion, прочесть про него можно здесь: http://community.haskell.org/~duncan/thesis.pdf _>Ооо, наконец то начинает появляться понимание... Кстати, замечу, что неизменяемое значение должно быть таким только на протяжение своей жизни. Так что immutable табличку вполне можно стереть после использования и заменить ту же самую ячейку памяти новыми данными (возможно тоже неизменяемыми).
И? Как это противоречит тому что я говорю?
В любом случае иммутабельность таблицы синусов — это маргинальный юзкейс для иммутабельности. Нормальный юзкейс — это персистентные структуры данных. _>То, что тестирование работы с иммутабельными данными равносильно насилованию менеджера памяти — это исключительно ваш тезис.
Нет, не равносильно, но это один из аспектов. Что неоднократно мной уже разъяснено. Если вы не модифицируете структуру данных на месте, а создаете новую версию — без "насилованию менеджера памяти" тут никак не обойдется, он должен быть к такому готов.
Впрочем, альтернативных предложений о методике измерения поддержки иммутабельных данных от вас все равно не поступает. Вы больше напираете на ненужность. _>Причём в D (в котором есть множество различных способов размещения данных) это вообще выглядит крайне смешно.
Смешное тут разве что то, что вы не спешите демонстрировать эти успехи "различных способов размещения". А разгадка проста — самого подходящего способа размещения иммутабельных структур — хипа с быстрым точным сборщиком — в D как раз и нет. _>Выделение не обязательно делать в динамической памяти. Можно и на стеке и тогда при сворачивание рекурсии в цикл мы можем получить практически точную копию текущего библиотечного кода.
Даже при воспроизведении моего крайне простого примера в пару строк вам возможностей стека уже не будет хватать.
Это если оставить за скобками привычную уже абсурдность измерения скорости работы с динамической памятью ее неиспользованием.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[83]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали: K>Так почему не получится? Есть у вас вложенные классы. Вы можете их обозначать просто с префикосом к имени, если этого достаточно. Можете с помощью имеющихся отношений (вы же сами ссылку на пример и дали) их обозначать, если префикса недостаточно. И этих возможностей хватит чтоб строить диаграммы для хаскель-кода.
Я же говорю, что нет этого отношения ни в стандарте, ни в известных инструментах для UML. ) K>Так в чем бредовость? Чем это бредовее отображения на диаграмме класса у которого есть методы и вложенные классы?
Потому что, ради того, чтобы всунуть модули в диаграмму классов (хотя им явно самое место в диаграмме пакетов), вы предлагаете обозначать одинаковыми значками абсолютно разные сущности. Т.е. они разные не просто в рамках какой-то программы, а вообще по определению — имеют разные возможные типы связей, разные виды жизни, разное содержимое и в принципе концептуально разные. K>Мы так и не выяснили, что туда нужно добавлять, если там и так уже все необходимое есть. K>Впрочем, "так и будет оставаться" — это верно, потому что популярность такого рода диаграмм в ФП-комьюнити крайне низкая и почти никто в этом направлении не работает.
Естественно, т.к. от того "что есть" (в смысле диаграмм) никакой особой пользы не видно. А в итоге получаем отсутствие инструментов помощи в проектирование для подобных языков. Да и средства документирования выглядят не так выразительно. K>Как никаких модулей? Модули вот здесь "можно экспортировать, а можно — не". K>У вас — грубо говоря — получается, что если инкапсуляция обозначается так: K>
K>public foo;
K>public bar;
K>public baz;
K>
K>то она есть, а если так K>
K>public (foo, bar, baz)
K>foo;
K>bar;
K>baz;
K>
K>то ее нет.
Нет, дело не в этом. Вопрос в том, кто у нас является единицей инкапсуляции в Хаскеле. Судя по вашим ответам, это алгебраический тип данных. А модули соответственно служат лишь инструментом отделения публичной части этих типов от приватной. И это больше всего напоминает древнюю схему Паскаля или даже вообще С. K>Можно ли "закэшировать пару вызовов" функций зависит от того, можно ли закэшировать значение которое она возвращает. Определение чистой функции тут только притом, что мы переходим к рассуждению о свойствах этого самого возвращаемого значения. K>Если вы хотите сказать, что K>
K>putStrLn "foo" >> putStrLn "foo"
K>
K>и K>
K>let f = putStrLn "foo"in f >> f
K>
K>это одно и то же — то да, так и есть.
Уууу какая демагогия пошла... А без монад? ) K>D я не знаю, но принцип, думаю, понятен: K>
>> let f (i : int ref) a = a + !i;;
K>val f : i:int ref -> a:int -> int
>> let g (i : int ref) b = i := b; b;;
K>val g : i:int ref -> b:int -> int
>> let i = ref 0 in List.map (f i) << List.map (g i) <| [1..10];;
K>val it : int list = [11; 12; 13; 14; 15; 16; 17; 18; 19; 20]
>> let i = ref 0 in List.map (f i << g i) <| [1..10];;
K>val it : int list = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]
K>
Нет, это вообще не то. Здесь вы доказываете, что map (f(p, g_var) . f(q, g_var)) != map f(p, g_var) . map f(q , g_var), что в общем то и так очевидно. Для реального доказательства вам надо передать в map именно те функции, которые служат аналогами чистых функций в D. K>Я просто скомпилировал указанный код на хаскеле с ключем -O2 -ddump-simpl -ddump-to-file -dsuppress-all -dsuppress-uniques -dppr-case-as-let K>И получил дамп промежуточного представления такого вот вида: K>
Скрытый текст
K>
K> \ w w1 ->
K> let { Vector ipv ipv1 ipv2 ~ _ <- w1 `cast` ... } in
K> case >=# 0 ipv1 of _ {
K> False ->
K> let { I# y ~ _ <- w } in
K> let { __DEFAULT ~ wild <- indexIntArray# ipv2 ipv } in
K> case <=# (*# wild wild) y of _ {
K> False -> True;
K> True ->
K> case wild of wild4 {
K> __DEFAULT ->
K> case modInt# y wild4 of _ {
K> __DEFAULT ->
K> letrec {
K> $s$wand_loop
K> $s$wand_loop =
K> \ sc ->
K> case >=# sc ipv1 of _ {
K> False ->
K> let { __DEFAULT ~ wild6 <- indexIntArray# ipv2 (+# ipv sc) } in
K> case <=# (*# wild6 wild6) y of _ {
K> False -> True;
K> True ->
K> case wild6 of wild8 {
K> __DEFAULT ->
K> case modInt# y wild8 of _ {
K> __DEFAULT -> $s$wand_loop (+# sc 1);
K> 0 -> False
K> };
K> (-1) -> False;
K> 0 -> case divZeroError of wild9 { }
K> }
K> };
K> True -> True
K> }; } in
K> $s$wand_loop 1;
K> 0 -> False
K> };
K> (-1) -> False;
K> 0 -> case divZeroError of wild5 { }
K> }
K> };
K> True -> True
K> }
K>
K>и перевел его обратно в хаскель с некоторыми не влияющими на смысл упрощениями.
О, а тогда может быть можно сделать аналогичное и для вашего примера с мутабельными данными? ) K>Нет, не равносильно, но это один из аспектов. Что неоднократно мной уже разъяснено. Если вы не модифицируете структуру данных на месте, а создаете новую версию — без "насилованию менеджера памяти" тут никак не обойдется, он должен быть к такому готов. K>Впрочем, альтернативных предложений о методике измерения поддержки иммутабельных данных от вас все равно не поступает. Вы больше напираете на ненужность.
Совершенно верно) Для подобных случаев я точно никогда не буду использовать иммутабельные данные. Ни в каком языке. ) K>Смешное тут разве что то, что вы не спешите демонстрировать эти успехи "различных способов размещения". А разгадка проста — самого подходящего способа размещения иммутабельных структур — хипа с быстрым точным сборщиком — в D как раз и нет.
А что тут демонстрировать то? ) Я например стараюсь использовать стековые данные везде, кроме разве что коллекций или больших блоков данных. Причём "стараюсь" — это сильно сказано, т.к. обычно их использовать наоборот приятнее: писать "A a;" удобнее, чем "A* a=new A;" и т.д. и т.п. Ну а кроме стековых, в D мы можем использовать опять же динамическую память, но без GC... K>Даже при воспроизведении моего крайне простого примера в пару строк вам возможностей стека уже не будет хватать. K>Это если оставить за скобками привычную уже абсурдность измерения скорости работы с динамической памятью ее неиспользованием.
Так мы же подразумеваем, что рекурсия свернётся в цикл компилятором. Так что всё там будет нормально со стеком, в точности как и в текущем коде с мутабельными индексами. Весь вопрос же только в них, т.к. главный массив у нас по любому остаётся в динамической памяти.
Re[84]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я же говорю, что нет этого отношения ни в стандарте, ни в известных инструментах для UML. )
Прямо по той ссылке, которую вы же сами и давали, написано, что для этого можно использовать обычное отношение композиции.
_>Потому что, ради того, чтобы всунуть модули в диаграмму классов (хотя им явно самое место в диаграмме пакетов),
Вовсе нет. На диаграмме пакетов место для пакетов. А место модулей на той же диаграмме, на которой место для классов.
_> вы предлагаете обозначать одинаковыми значками абсолютно разные сущности. Т.е. они разные не просто в рамках какой-то программы, а вообще по определению — имеют разные возможные типы связей, разные виды жизни, разное содержимое и в принципе концептуально разные.
Совершенно верно. Точно так же как одними значками (но с разными стереотипами) обозначаются "имеющие разные возможные типы связей, разные виды жизни, разное содержимое и в принципе концептуально разные" статические классы, классы и интерфейсы.
_>Естественно, т.к. от того "что есть" (в смысле диаграмм) никакой особой пользы не видно.
Мне с этим сложно спорить, потому что я не вижу от таких вещей заметной пользы безотносительно языка.
_>А в итоге получаем отсутствие инструментов помощи в проектирование для подобных языков. Да и средства документирования выглядят не так выразительно.
Не вижу проблемы в использовании существующих инструментов.
_>Нет, дело не в этом. Вопрос в том, кто у нас является единицей инкапсуляции в Хаскеле. Судя по вашим ответам, это алгебраический тип данных.
Единицей инкапсуляции являются значения, функции, конструкторы, точно так же, как в яве поля, методы, конструкторы. Разница заключается, в основном, в синтаксическом оформлении декларации публичности/приватности.
_>А модули соответственно служат лишь инструментом отделения публичной части этих типов от приватной. И это больше всего напоминает древнюю схему Паскаля или даже вообще С.
Не вижу смысла критиковать систему модулей паскаля, критикуйте систему модулей хаскеля (они не тождественны), если вы про систему модулей хаскеля ничего не знаете — просто составьте представление — это не долго, это не какие-нибудь мл-модули. В С же вообще обсуждать нечего.
_>Уууу какая демагогия пошла...
Где тут демагогия?
_>А без монад? )
Легко:
putStrLn "foo" `thenIO` putStrLn "foo"let f = putStrLn "foo"in f `thenIO` f
_>Нет, это вообще не то. Здесь вы доказываете, что map (f(p, g_var) . f(q, g_var)) != map f(p, g_var) . map f(q , g_var), что в общем то и так очевидно.
Ну так в этом и вопрос: как написать map, в который такие функции не передать?
_>Для реального доказательства вам надо передать в map именно те функции, которые служат аналогами чистых функций в D.
Не понял.
auto p(ref int v) pure {return ++v+1;}
в ди чистая функция, а
auto p(ref int v, int x) pure {v = x; return x;}
нет?
_>О, а тогда может быть можно сделать аналогичное и для вашего примера с мутабельными данными? )
Если имеется в виду сырой дамп промежуточного представления, то легко: http://files.rsdn.ru/46291/Main.dump-simpl.txt
Если имеется в виду "приглаженная" версия, то нет — слишком много кода, мне лень его править.
_>Совершенно верно) Для подобных случаев я точно никогда не буду использовать иммутабельные данные. Ни в каком языке. )
Т.е. персистентные структуры данных вы ни в каком языке использовать не будете?
Вообще, я могу только позавидовать вашей неприхотливости. Но многие люди отличаются от вас, когда они слышать что "есть поддержка иммутабельности" — они ожидают, что какая-то поддержка действительно есть.
_>А что тут демонстрировать то?
Демонстрировать работающий пример, отвечающий условиям задачи.
_>в D мы можем использовать опять же динамическую память, но без GC...
О да, для работы с иммутабельными данными такая возможность конечно же крайне полезна.
_>Так мы же подразумеваем, что рекурсия свернётся в цикл компилятором. Так что всё там будет нормально со стеком, в точности как и в текущем коде с мутабельными индексами. Весь вопрос же только в них, т.к. главный массив у нас по любому остаётся в динамической памяти.
Посмотрите внимательнее на мой пример с иммутабельными данными.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[85]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Прямо по той ссылке, которую вы же сами и давали, написано, что для этого можно использовать обычное отношение композиции.
Нет, это другое. Просто чаще всего экземпляры вложенного класса ещё и содержатся внутри внешнего (типа как List::Node), т.е. требуется и композицию.
K>Вовсе нет. На диаграмме пакетов место для пакетов. А место модулей на той же диаграмме, на которой место для классов.
Ещё раз: если вы решите обозначать модули значком класса (что довольно бредово — см. ниже), то тогда АТД вы не можете обозначать так же, т.к. нельзя обозначать одним и тем же значком сущности с абсолютно разными свойствами, временем жизни и т.п.
K>Совершенно верно. Точно так же как одними значками (но с разными стереотипами) обозначаются "имеющие разные возможные типы связей, разные виды жизни, разное содержимое и в принципе концептуально разные" статические классы, классы и интерфейсы.
Вы не понимаете ключевой нюанс. Если какой-то класс имеет особое поведение (в данном случае это означает, что не имеет некоторых обычных связей) в данной конкретной программе, то это совершенно не означает, что мы не можем пририсовать их (с полным сохранением корректности). Это особо хорошо чувствуется на инструментах, позволяющих генерировать исходный код по диаграмме. К примеру, если у вас находится в программе статический класс и вы пририсуете на диаграммке создание нескольких его экземпляров в другом классе, то при этом всё равно сгенерируется компилируемый исходник. А что будет в случае модулей хаскеля на подобном месте? )))
В общем не стоит придумывать ерунду. Значок класса в UML предполагает наличие набора определённых свойств, которым модули хаскеля очевидно не удовлетворяют. Этим свойствам более менее удовлетворяют АДТ хаскеля и вот их действительно можно пытаться рисовать на диаграммке классов (что мы и видели в паре примеров выше). Но такие диаграммки естественно будут давать не полное представление о программе, о чём мы уже говорили выше.
K>Единицей инкапсуляции являются значения, функции, конструкторы, точно так же, как в яве поля, методы, конструкторы. Разница заключается, в основном, в синтаксическом оформлении декларации публичности/приватности.
Это вы говорите "что" инкапсулируется. А я обсуждаю вопрос "куда". В ООП языках это класс. В Хаскеле, как я понимаю, АТД.
K>Не вижу смысла критиковать систему модулей паскаля, критикуйте систему модулей хаскеля (они не тождественны), если вы про систему модулей хаскеля ничего не знаете — просто составьте представление — это не долго, это не какие-нибудь мл-модули. В С же вообще обсуждать нечего.
Я критикую не систему модулей хаскеля (не вижу в ней ничего плохого, если говорить только о собственно модулях), а попытку введения инкапсуляции (для АТД) с помощью них. Вот это выглядит очень убого и напоминает технологии древного Паскаля или вообще C. А сами модули то очень даже ничего, удобные.
_>>Нет, это вообще не то. Здесь вы доказываете, что map (f(p, g_var) . f(q, g_var)) != map f(p, g_var) . map f(q , g_var), что в общем то и так очевидно. K>Ну так в этом и вопрос: как написать map, в который такие функции не передать?
Ээээ с чего это у нас должны быть какие-то ограничения на map? Она то как раз должна работать с любыми функциями и вполне нормально, если то равенство не будет выполняться для нечистых (в значение D).
Вы то пытаетесь доказать, что оно не выполняется для чистых функций. Ну так вот и доказывайте...
K>Не понял. K>
K>auto p(ref int v) pure {return ++v+1;}
K>
K>в ди чистая функция, а K>
K>auto p(ref int v, int x) pure {v = x; return x;}
K>
K>нет?
p и q в вашем коде на Хаскеле действительно являются нормальными аналогами чистых функций в D. Только вот в своём примере вы передаёте в map не p или q, а совсем другие функции...
K>Если имеется в виду сырой дамп промежуточного представления, то легко: http://files.rsdn.ru/46291/Main.dump-simpl.txt K>Если имеется в виду "приглаженная" версия, то нет — слишком много кода, мне лень его править.
Не, такое не разберу. А может вы тогда просто глянете сколько там всего у нас циклов (рекурсий)? В идеале должно быть ровно две: один по возрастающим целым числам и внутри второй по нашему массиву. И всё. Именно такой код генерирует в итоге та одна моя строчка на D. И вы анонсировали, что на Хаскеле будет тоже самое благодаря хитрым оптимизациям...
_>>Совершенно верно) Для подобных случаев я точно никогда не буду использовать иммутабельные данные. Ни в каком языке. ) K>Т.е. персистентные структуры данных вы ни в каком языке использовать не будете?
Почему же не буду? ) Я их постоянно использую, если они таковые по условию задачи. Однако, если я вижу, что какие-то данные имеют тенденцию к изменению, то я естественно не буду делать их иммутабельными и порождать новые копии при изменение, а просто использую мутабельные структуры.
_>>в D мы можем использовать опять же динамическую память, но без GC... K>О да, для работы с иммутабельными данными такая возможность конечно же крайне полезна.
В D и для таких сущностей вполне можно с пользой использовать иммутабельность. )))
Re[84]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Так в чем бредовость? Чем это бредовее отображения на диаграмме класса у которого есть методы и вложенные классы?
_>Потому что, ради того, чтобы всунуть модули в диаграмму классов (хотя им явно самое место в диаграмме пакетов), вы предлагаете обозначать одинаковыми значками абсолютно разные сущности. Т.е. они разные не просто в рамках какой-то программы, а вообще по определению — имеют разные возможные типы связей, разные виды жизни, разное содержимое и в принципе концептуально разные.
Вообще то классика ООП утверждает, что классы в ооп это
1 модули
2 типы
Отсюда все их преимущества и недостатки
В свою очередь классика ФП разделяет эти вещи — типы отдельно от модулей. Что характерно, и там и там в основе типов лежит АТД. Отсюда ясно что оба подхода могут и используют один и тот же UML
Re[85]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Вообще то классика ООП утверждает, что классы в ооп это I>1 модули I>2 типы
I>Отсюда все их преимущества и недостатки
Всё правильно и это единая неделимая сущность, которая имеет определённый набор свойств (отражённый в UML соответствующими правилами).
I>В свою очередь классика ФП разделяет эти вещи — типы отдельно от модулей. Что характерно, и там и там в основе типов лежит АТД. Отсюда ясно что оба подхода могут и используют один и тот же UML
Да, безусловно можно разработать некий вид диаграмм (и даже включить их в стандарт UML), которые будут отлично отображать эти две сущности. Могу даже предложить для этого взять за основу диаграмму классов, в которой чуть поменять свойства для значка класса, добавить новый значок для модулей, и соответственно пересмотреть набор возможных видов связей.
Т.е. основная моя мысль в том, что в теории то без проблем, а на практике (в существующих стандартах и соответственно инструментах) фигово у чистых ФЯ с этим делом.
Re[86]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, это другое. Просто чаще всего экземпляры вложенного класса ещё и содержатся внутри внешнего (типа как List::Node), т.е. требуется и композицию.
Допустим, что у вас статический класс и вложенный в него обычный. Как вы их покажете на диаграмме?
_>Ещё раз: если вы решите обозначать модули значком класса (что довольно бредово — см. ниже), то тогда АТД вы не можете обозначать так же, т.к. нельзя обозначать одним и тем же значком сущности с абсолютно разными свойствами, временем жизни и т.п.
Можно. Например статический класс и не статический класс.
_>А что будет в случае модулей хаскеля на подобном месте?
Очевидно, что ничего. Мы говорим об использовании инструментов, которые не предназначены специально для хаскеля. Разумеется, код на хаскеле такие инструменты не генерируют.
_>В общем не стоит придумывать ерунду. Значок класса в UML предполагает наличие набора определённых свойств, которым модули хаскеля очевидно не удовлетворяют.
Каким свойствам удовлетворяют статические классы и не удовлетворяют модули?
_>Этим свойствам более менее удовлетворяют АДТ хаскеля и вот их действительно можно пытаться рисовать на диаграммке классов (что мы и видели в паре примеров выше). Но такие диаграммки естественно будут давать не полное представление о программе, о чём мы уже говорили выше.
Чем неполнота представления о программе на хаскеле будет отличатся от неполноты представления о программе на Яве?
_>Это вы говорите "что" инкапсулируется. А я обсуждаю вопрос "куда". В ООП языках это класс. В Хаскеле, как я понимаю, АТД.
В хаскеле "куда" — это модуль. Потому, что класс является модулем (первоклассным), а АлгТД — не является.
_>Я критикую не систему модулей хаскеля (не вижу в ней ничего плохого, если говорить только о собственно модулях), а попытку введения инкапсуляции (для АТД) с помощью них. Вот это выглядит очень убого и напоминает технологии древного Паскаля или вообще C. А сами модули то очень даже ничего, удобные.
Вообще ничего не понятно. Если вам ими удобно пользоваться, то в чем претензии к убогости тогда. Что конкретно плохо — вы можете пример показать, а не говорить что что-то просто убого, только непонятно что? И в чем сходство с Си? Как наличие модулей может быть сходным с отсутствием модулей?
_>Ээээ с чего это у нас должны быть какие-то ограничения на map?
Должны потому что такие уж свойства у map. И без "ограничения" на функции такие свойства не выполняются.
Я же с самого начала и спросил: "Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось map (p . q) = map p . map q". И функции в языке для того и нужны, чтоб такие вот законы могли выполнятся.
_>Она то как раз должна работать с любыми функциями и вполне нормально, если то равенство не будет выполняться для нечистых (в значение D).
Нет, это не нормально.
_>p и q в вашем коде на Хаскеле действительно являются нормальными аналогами чистых функций в D. Только вот в своём примере вы передаёте в map не p или q, а совсем другие функции...
Которые в D не могут быть чистыми? Ну пусть тогда список к которому map применяется заполнен объектами со ссылкой на один и тот же мутабельный объект.
_>Не, такое не разберу. А может вы тогда просто глянете сколько там всего у нас циклов (рекурсий)? В идеале должно быть ровно две: один по возрастающим целым числам и внутри второй по нашему массиву. И всё. Именно такой код генерирует в итоге та одна моя строчка на D. И вы анонсировали, что на Хаскеле будет тоже самое благодаря хитрым оптимизациям...
? Так я показал во что превращается ее аналог.
_>Почему же не буду? ) Я их постоянно использую, если они таковые по условию задачи. Однако, если я вижу, что какие-то данные имеют тенденцию к изменению, то я естественно не буду делать их иммутабельными и порождать новые копии при изменение, а просто использую мутабельные структуры.
Вы точно понимаете, что такое персистентные структуры данных? Они собственно и предназначены для хранения "того, что имеет тенденцию к изменению", а не для таблиц синусов.
_>В D и для таких сущностей вполне можно с пользой использовать иммутабельность. )))
Нельзя. Сборщик мусора не потянет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Darooma, Вы писали:
D>а я даже понял. они служат просто для сцепления, комбинирования методов.
Наверное все-же нет, обычные делегаты служат для сцепления методов.
Я тоже не очень четко понимаю что такое монады (поэтому все ниженаписанное может содержать ошибки — поправляйте если что). Проблема еще в том что в русском языке нет (как мне кажется) достаточно общих и в то же время всем понятных слов для выражения того эффекта, который дают монады. Все что говорится обычно — лишь частные случаи.
Монада — это конструкция языка. Такая же как условное выполнение, функция, класс, обработка исключений. Т.е. это вещь, относящаяся к парадигмам программирования. Некоторые говорят что это "паттерн проектирования", но я считаю что это все-же нечно большее.
Мы привыкли к императивному подходу, включающему в себя структурное и процедурное программирование. Для нас программа — это дерево, состоящее из блоков — последовательного выполнения, условных операторов, циклов, вызовов функций. ООП и известная большинству часть ФП ничего в этой парадигме не затронули: ООП в основном относится к данным, к способу их структурирования и инкапсуляции, ФП-расширения основных языков позволяют передавать функции как аргументы и возвращать их как значения — но концептуально все это базиурется на незыблемом императивном фундаменте.
Я не знаком с декларативными языками (в частности с haskell), но как я понимаю, основной смысл декларативной парадигмы — описательный стиль, программа описывает предметную область и решаемую задачу, а не инструкции "как сделать то-то". Это такая своеобразная большая система уравнений (?), а не пошаговый алгоритм. Поэтому в декларативных языках понятия "последовательность выполнения кода" просто нет. Но компьютер есть компьютер, в нем есть взаимодействие с пользователем, с другими программами и сервисами... все это императивное по определению, и с этим нужно как-то взаимодействовать.
Например, если мы хотим разделить два числа, то в императивном языке простейшая программа последовательно запросит делимое, делитель и выведет результат деления. Последовательность вызова функции получения числа заложена в самой сути императивной программы, в последовательности строчек кода.
В декларативном языке такое просто невозможно: даже если есть некая системная функция типа "readIntFromConsole()": нет никакой гарантии, что она будет вызвана в правильном порядке, т.е. сначала для делимого, а затем для делителя. Монада (с названием "IO") — это сущность, вводящая в декларативную "систему уравнений" фрагмент последовательного выполнения, гарантирующая что одно выражение (получение делимого с консоли) будет вычислено раньше, чем другое (получение делителя с консоли).
Монады естественны в декларативной среде. Декларативная среда — "нулевая" с точки зрения парадигмы выполнения кода; там последовательность выполнения кода вообще не определена. В ней монады фактически реализуют некоторые конструкции, алгоритмы и паттерны проектирования, которые в классической императивной среде реализуются совершенно разными способами, начиная от языковых конструкций. Но это не значит, что монады не могут существовать в "ненулевой" императивной среде. Некоторые из них (типа "IO") будут просто не нужны, зато другие предположительно дадут очень интересные эффекты, суть которых — в неявном встраивании в привычную императивную последовательность выполнения кода некоторых дополнительных действий. С некоторой точки зрения, монада, включенная в одно единственное место большого длинного выражения, способна перестроить все это выражение целиком.
Например "Maybe", реализующая прозрачную работу с объектами, обладающими недействительным состоянием "Nothing". В обычном императивном коде это могут быть обычные указатели, которые могут указывать как на объект, так и на NULL. Раньше нужны были проверки: если указатель не равен NULL, делаем с ним что-то... С "Maybe" такие проверки можно было бы пропустить: монада добавила бы в привычный императивный код некоторый дополнительный слой проверок таким образом, что для значения "Nothing" никаких действий бы не выполнялось.
Maybe<int> x1 = 10, x2 = Nothing;
int y = x1 + 2; // y == 12
x1 = x2 + 2; // x1 == nothing; поскольку x1 - maybe, все происходит молча
y = x2 + 2; // y == nothing; но y - не maybe, можем ничего не делать (y останется равным 12), или лучше бросить исключение?
"List" также перестраивает последовательность выполнения — там, где раньше было действие с одним значением, List обеспечивает выполнение этого действия с каждым значением из списка. Это принципиально отличается от всего, что мы видели в императивных языках.
Re[87]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Допустим, что у вас статический класс и вложенный в него обычный. Как вы их покажете на диаграмме?
Обычно это будет просто префикс (через ::) в имени вложенного. Если этот внешний класс действительно статический и не содержит экземпляров внутреннего.
K>Можно. Например статический класс и не статический класс.
Ни в UML ни в C++ и т.п. ООП языках нет такой сущности как "статический класс". Есть просто классы с по сути одинаковыми для всех этих языков свойствами (максимум разница в наличие множественного наследования). Вот статические методы/свойства в языках (и в UML кстати) есть... Ну и вроде как-то принято называть класс, состоящий только из них, статическим. Но при этом он на самом деле обладает всеми свойствами обычного класса. Мы мы можем и не статические члены в него добавить и экземпляры его завести и т.п.
K>Очевидно, что ничего. Мы говорим об использовании инструментов, которые не предназначены специально для хаскеля. Разумеется, код на хаскеле такие инструменты не генерируют.
Собственно об этом речь. Т.е. естественно не про генерацию кода, а в про вообще отсутствие поддержки языков типа Хаскеля в подобных инструментах.
K>Чем неполнота представления о программе на хаскеле будет отличатся от неполноты представления о программе на Яве?
В Хаскеле (в отличие от Явы) значительная часть сущности программы может задаваться свободными функциями.
K>В хаскеле "куда" — это модуль. Потому, что класс является модулем (первоклассным), а АлгТД — не является.
Тогда мы снова возвращаемся к вопросу о массивах модулей... В общем вам надо выбрать один из двух вариантов:
1. Единицей инкапсуляции в Хаскеле являются АТД. Тогда у нас получаются убогие средства для инкапсуляции — через внешнюю сущность (модули) делящую код на части (интерфейс/реализацию), как в древнем Паскале/С.
2. Единицей инкапсуляции в Хаскеле являются модули. Но тогда у нас вообще всё плохо — нельзя получить например массив сущностей, инкапсулирующих какие-то свойства.
По моим ощущениям правилен вариант 1, но возможно вам, как практику Хаскеля, виднее. Всё равно оба варианта фиговые. )))
K>Вообще ничего не понятно. Если вам ими удобно пользоваться, то в чем претензии к убогости тогда. Что конкретно плохо — вы можете пример показать, а не говорить что что-то просто убого, только непонятно что? И в чем сходство с Си? Как наличие модулей может быть сходным с отсутствием модулей?
Напоминаю, мы говорим об инкапсуляции, а не о системе модулей. Да, и если что, в ООП языках инкапсуляция реализуется независимо от системы модулей. Собственно она есть в полную силу и в языках, по сути вообще без модульной системы (типа C++).
K>Должны потому что такие уж свойства у map. И без "ограничения" на функции такие свойства не выполняются. K>Я же с самого начала и спросил: "Ну вот у вас есть функция map, которая принимает какую-то функцию p или q. Как можно проконтролировать эффекты, чтоб выполнялось map (p . q) = map p . map q". И функции в языке для того и нужны, чтоб такие вот законы могли выполнятся.
Это у вас какой-то свой особый map. А в большинстве языков программирования это правило не выполняется для map и произвольных функций.
_>>Она то как раз должна работать с любыми функциями и вполне нормально, если то равенство не будет выполняться для нечистых (в значение D). K>Нет, это не нормально.
Почему это? )
K>Которые в D не могут быть чистыми? Ну пусть тогда список к которому map применяется заполнен объектами со ссылкой на один и тот же мутабельный объект.
Да, совершенно верно. Функции, передаваемые в вашем примере в map не могут быть чистыми на D.
А на счёт массива ссылок на один и тот же объект... В D такое тоже не пройдёт (в том смысле что всё будет работать и при этом наше равенство будет сохраняться), т.к. в результате map'a в любом случае будет получаться массив с разными ссылками. Я же говорю, что без перехода на уровень игр с указателями у вас ничего не выйдет.
K>Какая "та строчка"? Та, что тут http://rsdn.ru/forum/philosophy/5624883.1
Это у вас показан вариант с иммутабельными данными (что вообще не интересно, т.к. дико отстаёт по быстродействию), а нужен как раз с мутабельными. Причём в случае Хаскеля, как я понимаю, тут как раз может быть большая разница в коде...
K>Вы точно понимаете, что такое персистентные структуры данных? Они собственно и предназначены для хранения "того, что имеет тенденцию к изменению", а не для таблиц синусов.
Нет, не так. Скорее для того, что имеет тенденцию к изменению, и плюс нам необходимо сохранять доступ к старым версиям. Это уже гораздо более редкая задачка (по сравнению с просто мутабельными или даже иммутабельными данными). И естественно, если она мне встретится, то я могу использовать коллекцию иммутабельных данных или же специальную персистентную структуру, если требуется оптимизация по быстродействию.
А вот что я точно никогда не буду делать, так это пытаться использовать наборы иммутабельных данных (пусть даже и оптимизированных с помощью персистентной структуры) для представления нормальных мутабельных данных (для которых не надо хранить старые версии), которых собственно большинство в обычных программах.
_>>В D и для таких сущностей вполне можно с пользой использовать иммутабельность. ))) K>Нельзя. Сборщик мусора не потянет.
Вообще то в том контексте разговора под сущностью подразумевалась динамическая память, выделенная в ручную (а не через GC), так что ответ выглядит мягко говоря странно. Но я уже и так понял, что для вас GC является чуть не главным вообще. На что мне, привыкшему к работе через стек и RAII, вообще очень забавно смотреть.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
У вас просто великолепное понимание, особенно для незнакомого с декларативными языками. Только вот один важный вывод из ваших же мыслей вы упустили. Как вы правильно заметили, монады задают императивные конструкции в декларативных языках. Т.е. они являясь лишь небольшой частью языка, пытаются выполнить ту же задачу, для реализации которой предназначена вся мощь современных императивных языков. Т.е. грубо говоря монады являются убогонькой альтернативой самим императивным языкам. И соответственно использовать их здесь в явном виде довольно глупо (но совсем не сложно, как было показано в начале этой темки).
Да, кстати, поскольку монады задают не произвольный императивный код, а с весьма специфическими параметрами, то их можно изредка встретить в обычном императивном коде. Т.е. это не значит, что авторы планировали создать монаду. Они просто писали обычный императивный код под специфическую задачку и в результате у них нарисовалась типичная монада (им от этого правда ни холодно, ни жарко). Как примеры:
— вариации на тему maybe (std.optional в C++, optional в C# и Swift)
— различные продолжения (конструкции future.then в реализации многопоточности во многих языках)
— различные дипазоны (boost.range в C++, std.range в D, IEnumerable в C#, Sequence в Swift)
и много ещё чего может быть, типа реализаций различных парсеров и т.п.
Так что в принципе это вещь естественная для специфических задачек. А убогость соответственно заключается в том, что работая только с монадами, мы должны писать вообще весь императивный код только таким способом.
Re[88]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Допустим, что у вас статический класс и вложенный в него обычный. Как вы их покажете на диаграмме? _>Обычно это будет просто префикс (через ::) в имени вложенного. Если этот внешний класс действительно статический и не содержит экземпляров внутреннего.
ОК. А где на этой диаграмме будут статические методы статического класса?
_>Ни в UML ни в C++ и т.п. ООП языках нет такой сущности как "статический класс".
В C# есть статический класс. Что, C# тоже не совместим с UML, как и хаскель?
_>Мы мы можем и не статические члены в него добавить и экземпляры его завести и т.п.
Нет, не можем. Если мы попытаемся добавить нестатический член в статический класс в C# будет ошибка компиляции.
_>Собственно об этом речь. Т.е. естественно не про генерацию кода, а в про вообще отсутствие поддержки языков типа Хаскеля в подобных инструментах.
Поддержки генерации хаскель кода разумеется нет, а что не хватает в UML чтоб можно было схемы для хаскельного кода строить вы все никак не можете показать.
_>В Хаскеле (в отличие от Явы) значительная часть сущности программы может задаваться свободными функциями.
В хаскеле не бывает свободных функций, они всегда находятся, по крайней мере, в каком-то модуле. И если вы не опишете никакого модуля — они будут "публичными членами" модуля Main.
_>Тогда мы снова возвращаемся к вопросу о массивах модулей...
Не нужно возвращается к массиву модулей, потому что нет связи между тем в чем что-то инкапсулируется и в чем что-то хранится. Да, классы в ООП совмещают несколько функций, которые в других языках могут не совмещаться в одном инструменте, но это не значит, что инкапсуляции в них нет — с чего вы этот разговор и начали.
_>Напоминаю, мы говорим об инкапсуляции, а не о системе модулей. Да, и если что, в ООП языках инкапсуляция реализуется независимо от системы модулей. Собственно она есть в полную силу и в языках, по сути вообще без модульной системы (типа C++).
Собственно в том, что в классах можно что-то инкапсулировать и является проявлением того, что классы обладают некоторыми свойствами/функциями модулей. Поэтому, если про C можно точно сказать, что модулей в нем нет — то в случае C++ есть нюанс — потому что классы — это тоже, в общем-то, модули (схемеры бы сказали, наверное, "модули для бедных").
_>Это у вас какой-то свой особый map. А в большинстве языков программирования это правило не выполняется для map и произвольных функций.
Нет, мап самый обычный. Если вашу дишную чистоту нельзя использовать для того, чтоб функция могла проконтролировать, что в нее именно чистые функции передаются — то никаким надмножеством чистоты в математическом смысле она не является.
K>>Нет, это не нормально. _>Почему это? )
Видите ли, абстракция должна иметь какие-то свойства, иначе ее нельзя использовать без "протекания". В ФП, где абстракции используют нешуточным образом, это особенно очевидно и важно.
В большинстве языков программирования, конечно, никаких удобств для ФП нет — ну, тем больше головной боли для программиста, который вдруг решит на них фп-код писать.
Впрочем, позиция понятна, очередная колбаса, потребности в которой в вашем дишном коммунизме нет.
_>А на счёт массива ссылок на один и тот же объект... В D такое тоже не пройдёт (в том смысле что всё будет работать и при этом наше равенство будет сохраняться), т.к. в результате map'a в любом случае будет получаться массив с разными ссылками.
Каким образом это можно обеспечить, если "чистые" функции могут изменяемые данные получить?
_>Это у вас показан вариант с иммутабельными данными (что вообще не интересно, т.к. дико отстаёт по быстродействию), а нужен как раз с мутабельными. Причём в случае Хаскеля, как я понимаю, тут как раз может быть большая разница в коде...
Это фрагмент кода, из примера с изменяемым буфером. Который демонстрирует как раз то, о чем я говорил — устранение ненужных промежуточных структур. Код на ди, как я понял, так не оптимизируется, вы заменили конвейер на одну функцию find вручную. Разумеется все промежуточные данные в моем примере иммутабельные. Ну так о них и разговор.
Когда мы с вами обсуждали — наоборот — поддержку мутабельности в хаскеле — я вам показывал устранение ненужных копирований при работе с мутабельными массивами.
_>Нет, не так. Скорее для того, что имеет тенденцию к изменению, и плюс нам необходимо сохранять доступ к старым версиям. Это уже гораздо более редкая задачка (по сравнению с просто мутабельными или даже иммутабельными данными). И естественно, если она мне встретится, то я могу использовать коллекцию иммутабельных данных или же специальную персистентную структуру, если требуется оптимизация по быстродействию.
Ну правильно, если у вас персистентные структуры слишком тормозят, вы будете их использовать только в крайнем случае. Но код, который с персистентными структурами работает обычно понятнее и меньше ошибок содержит. Поэтому в языке с поддержкой иммутабельности такие структуры применяют просто для удобства программиста.
_>А вот что я точно никогда не буду делать, так это пытаться использовать наборы иммутабельных данных (пусть даже и оптимизированных с помощью персистентной структуры) для представления нормальных мутабельных данных (для которых не надо хранить старые версии), которых собственно большинство в обычных программах.
Конечно. Ведь и эту колбасу не завезли. Значит и потребности нет.
_>Вообще то в том контексте разговора под сущностью подразумевалась динамическая память, выделенная в ручную (а не через GC),
Так я на это сразу сказал, как здорово при таком подходе персистентные структуры использовать. Может ирония была не достаточно заметна?
_>я уже и так понял, что для вас GC является чуть не главным вообще.
Повторяю в очередной раз. Это один из двух важных аспектов. Другой — устранение промежуточных данных на этапе компиляции. Если есть и то и другое — иммутабельностью можно даже начинать пользоваться, а не обосновывать, почему без нее можно обойтись.
Каждый раз, когда я говорю, что при работе с персистентными структурами будет выделятся куча объектов в памяти, в том числе и много короткоживущих, вы скипаете текст и в очередной раз удивляетесь — чего это я такое значение сборщику мусора придаю. Попробуйте связать одно с другим. Связь есть — точно вам говорю.
_>На что мне, привыкшему к работе через стек и RAII, вообще очень забавно смотреть.
Ничего удивительного. Если для вас поддержка иммутабельности равна заверениям о ее ненужности — смешными вам могут показаться самые неожиданные вещи.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>У вас просто великолепное понимание, особенно для незнакомого с декларативными языками. Только вот один важный вывод из ваших же мыслей вы упустили. Как вы правильно заметили, монады задают императивные конструкции в декларативных языках. Т.е. они являясь лишь небольшой частью языка, пытаются выполнить ту же задачу, для реализации которой предназначена вся мощь современных императивных языков. Т.е. грубо говоря монады являются убогонькой альтернативой самим императивным языкам. И соответственно использовать их здесь в явном виде довольно глупо (но совсем не сложно, как было показано в начале этой темки).
Монады не задают императивные конструкции в декларативных языках. Монады это отделение вычислений от побочных эффектов.
_>Да, кстати, поскольку монады задают не произвольный императивный код, а с весьма специфическими параметрами, то их можно изредка встретить в обычном императивном коде. Т.е. это не значит, что авторы планировали создать монаду. Они просто писали обычный императивный код под специфическую задачку и в результате у них нарисовалась типичная монада (им от этого правда ни холодно, ни жарко). Как примеры:
Из ложной посылки следует ложный вывод. Поскольку монады отделяют вычисления от побочных эффектов, то это можно использовать и в императивных языках.
_>Так что в принципе это вещь естественная для специфических задачек. А убогость соответственно заключается в том, что работая только с монадами, мы должны писать вообще весь императивный код только таким способом.
Снова неверно. Во первых, пиши как угодно, ну разве что в Хаскеле есть внятные ограничения. Во вторых, если хочешь отделять побочыные эффекты от вычислений, выбор у тебя на самом деле невелик.
Re[89]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>ОК. А где на этой диаграмме будут статические методы статического класса?
Формально то способ есть — отобразить как статические методы обычного класса и всё. Но на практике этот класс вообще не рисуют, т.к. он по сути является всего лишь заменой (и кстати весьма убогой) пространств имён, а функции в нём обычно носят утилитарный характер. Естественно мы говорим про ООП программу.
K>В C# есть статический класс. Что, C# тоже не совместим с UML, как и хаскель?
Ну во всяком случае в стандате UML никакого специального выделения для статических классов нет. Однако это естественно не мешает отображать их при надобности (хотя при классическом ООП это сомнительно) как обычный класс. А вот для генерации подобного кода видимо уже придётся использовать только фирменые инструменты от MS, в которых наверняка это как-то добавлено. )))
K>В хаскеле не бывает свободных функций, они всегда находятся, по крайней мере, в каком-то модуле. И если вы не опишете никакого модуля — они будут "публичными членами" модуля Main.
Даже если забыть про то, что мы так и не договорились по факту наличия модулей на диаграмме классов, то в любом случае здесь они являются всего лишь разновидностью пространства имён — никаких связей прорисовать не удастся. Т.е. получится не связанная диаграмма, некий набор независимых значков. Или может вы например подскажете, как нам например отобразить какие функции из данного модуля работают с каким-то из данного АТД (одного из определённых в том же модуле)?
K>Не нужно возвращается к массиву модулей, потому что нет связи между тем в чем что-то инкапсулируется и в чем что-то хранится. Да, классы в ООП совмещают несколько функций, которые в других языках могут не совмещаться в одном инструменте, но это не значит, что инкапсуляции в них нет — с чего вы этот разговор и начали.
Ага, есть инкапсуляция... Ну например:
1. Если у нас есть несколько АТД определённых в модуле и плюс имеем в модуле функции, работающие с приватными внутренностями этих АТД, то я правильно понимаю, что все функции внутри этого модуля имеют доступ ко внутренностям всех АТД, даже если реально не имеют к ним никакого отношения?
2. Я могу у какого-то АТД сделать доступ снаружи только к части данных? Т.е. не закрывая всё и вводя публичную функцию типа геттера, а именно доступ к самим данным, но частичный.
Это только то что с ходу в голову пришло, без изучения деталей. Подозреваю, что если начать копаться, то столько всего найти можно...
K>Собственно в том, что в классах можно что-то инкапсулировать и является проявлением того, что классы обладают некоторыми свойствами/функциями модулей. Поэтому, если про C можно точно сказать, что модулей в нем нет — то в случае C++ есть нюанс — потому что классы — это тоже, в общем-то, модули (схемеры бы сказали, наверное, "модули для бедных").
Вообще то для этих целей в C++ служат пространства имён, которые обладают своими мощными возможностям, уж точно превосходящими классы C++, а скорее всего и модули Хаскеля (тут вообще сложно сравнивать, т.к. предназначения немного различаются всё же — пространства имён никак не завязаны на компиляцию и т.п.)
K>Нет, мап самый обычный. Если вашу дишную чистоту нельзя использовать для того, чтоб функция могла проконтролировать, что в нее именно чистые функции передаются — то никаким надмножеством чистоты в математическом смысле она не является.
Ну естественно можно написать map, принимающий только чистые функции. Только нафига он мне такой-то, зачем себя ограничивать? Я вполне могу себе представить сценарии, в которых будет удобно применить map с не чистой функцией.
K>Видите ли, абстракция должна иметь какие-то свойства, иначе ее нельзя использовать без "протекания". В ФП, где абстракции используют нешуточным образом, это особенно очевидно и важно. K>В большинстве языков программирования, конечно, никаких удобств для ФП нет — ну, тем больше головной боли для программиста, который вдруг решит на них фп-код писать. K>Впрочем, позиция понятна, очередная колбаса, потребности в которой в вашем дишном коммунизме нет.
Я так и не понял какое отношение эта тирада имеет к вопросу о нужности требования чистоты от параметров map'a.
K>Каким образом это можно обеспечить, если "чистые" функции могут изменяемые данные получить?
Нуу грубо говоря:
class A {v=1;};
auto a=new A;
auto x=[a, a, a];//ссылки на один объектauto f(А p) pure {++p.v; return v;}
auto y=map!f(y);//после этого вызова имеем:
//x=[A{4}, A{4}, A{4}]
//y=[A{2}, A{3}, A{4}]
Т.е. хотя мы и меняем изначальный массив хитрым образом, то на результате это никак не отражается. И соответственно map p.q=map p . map q будет работать корректно, т.к. в map q мы будем менять не изначальный массив, а некий промежуточный.
K>Это фрагмент кода, из примера с изменяемым буфером. Который демонстрирует как раз то, о чем я говорил — устранение ненужных промежуточных структур. Код на ди, как я понял, так не оптимизируется, вы заменили конвейер на одну функцию find вручную. Разумеется все промежуточные данные в моем примере иммутабельные. Ну так о них и разговор.
Ну а я вот не уверен, что наличие мутабельных данных (даже не смотря на то, что в самом примере их никто не меняет) никак не влияет на получающийся код. На внешность то изначального кода это влияет и довольно заметно...
K>Когда мы с вами обсуждали — наоборот — поддержку мутабельности в хаскеле — я вам показывал устранение ненужных копирований при работе с мутабельными массивами.
Да, было такое. Но работало только благодаря искусственно введённой вами поддержке этого. В данном же примере такого не было вроде...
K>Ну правильно, если у вас персистентные структуры слишком тормозят, вы будете их использовать только в крайнем случае. Но код, который с персистентными структурами работает обычно понятнее и меньше ошибок содержит. Поэтому в языке с поддержкой иммутабельности такие структуры применяют просто для удобства программиста.
Да глупо это и не нормально по сути. Вот объясните мне зачем мне хранить историю изменения некой переменной, если я точно знаю, что старое значение мне больше никогда не понадобится (как в том же примере с обработкой кадров видео)?
K>Повторяю в очередной раз. Это один из двух важных аспектов. Другой — устранение промежуточных данных на этапе компиляции. Если есть и то и другое — иммутабельностью можно даже начинать пользоваться, а не обосновывать, почему без нее можно обойтись. K>Каждый раз, когда я говорю, что при работе с персистентными структурами будет выделятся куча объектов в памяти, в том числе и много короткоживущих, вы скипаете текст и в очередной раз удивляетесь — чего это я такое значение сборщику мусора придаю. Попробуйте связать одно с другим. Связь есть — точно вам говорю.
Ещё раз, я не говорю о том, что неважна скорость работы сборщика мусора (тем более, если речь о языке, в котором это единственный способ выделения памяти). Я пытаюсь напомнить, что кроме сборщика мусора может ещё множество разных вариантов. Может быть и банальный подсчёт ссылок (кстати, вот Apple выкатили язык вообще базирующий на этом), может быть аллокатор на пуле, может быть вообще ручная работа с указателями, а может быть и моё любимое выделение на стеке (кстати, для некоторых персистентных структур такое вполне может быть интересно, если у них сами данные хранятся единым куском в динамической памяти, а бегают туда сюда различные ссылки на него, которые вполне эффективно хранить на стеке), да и мало ли что можно придумать в языке с полным доступом на низкий уровень. И большинство из перечисленных мною вариантов будут работать быстрее любого сборщика мусора (из любого языка). Ну и соответственно если вдруг очень хочется пострадать иммутабельными структурами, то никто не мешает построить их и вокруг такого базиса.
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Монады не задают императивные конструкции в декларативных языках. Монады это отделение вычислений от побочных эффектов.
Насколько я понимаю, ты согласен с тем, что монады встречаются не только в Хаскеле? Если да, то покажи ка мне на любом примере и любом языке, кроме Хаскеля, как там монады отделяют побочные эффекты.
I>Из ложной посылки следует ложный вывод. Поскольку монады отделяют вычисления от побочных эффектов, то это можно использовать и в императивных языках.
А я разве где-то написал, что их нельзя использовать? ) Вроде как наоборот, я даже привёл примеры того, где монады сами появляются (даже если авторы их и не задумывали) в императивном коде. Правда почему-то это всё очень специфические задачки... )))
I>Снова неверно. Во первых, пиши как угодно, ну разве что в Хаскеле есть внятные ограничения. Во вторых, если хочешь отделять побочыные эффекты от вычислений, выбор у тебя на самом деле невелик.
Ограничения у нас будут, если мы будем строить весь императивный код на монадах. Если же нет, то действительно никаких проблем нет. )
Re[7]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Монады не задают императивные конструкции в декларативных языках. Монады это отделение вычислений от побочных эффектов.
Вообще, я немного погорячился. монады отделяют не просто побочные эффекты от вычислений, а эффекты, вообще, от вычислений.
_>Насколько я понимаю, ты согласен с тем, что монады встречаются не только в Хаскеле? Если да, то покажи ка мне на любом примере и любом языке, кроме Хаскеля, как там монады отделяют побочные эффекты.
I>>Из ложной посылки следует ложный вывод. Поскольку монады отделяют вычисления от побочных эффектов, то это можно использовать и в императивных языках.
_>А я разве где-то написал, что их нельзя использовать? ) Вроде как наоборот, я даже привёл примеры того, где монады сами появляются (даже если авторы их и не задумывали) в императивном коде. Правда почему-то это всё очень специфические задачки... )))
Давай перечислим вместе эти специфические задачи
обработка исключительных ситуаций.
вычисления с множественными результатами
асинхронный результат
обработка событий
вычисления с изменяемым состоянием
ввод-вывод
Как видишь, задачи мягко говоря широко распространены.
I>>Снова неверно. Во первых, пиши как угодно, ну разве что в Хаскеле есть внятные ограничения. Во вторых, если хочешь отделять побочыные эффекты от вычислений, выбор у тебя на самом деле невелик.
_>Ограничения у нас будут, если мы будем строить весь императивный код на монадах. Если же нет, то действительно никаких проблем нет. )
Ограничения появятся в том случае, если ты решишь отделить эффекты от вычислений. Точно так же, если ты решил хранить данные в SQL Server, то у тебя сразу соответсвующие ограничения связаные с этим решением.
Вот взять Promise — эффект здесь временная задержка, с помощью монады вычисления отделяются от эффекта, то есть, задержки.
Если ты захочешь, что бы код вычисления был в одном месте, то в императивном коде у тебя будут вагоны приседаний скажем с многопоточностью, синхронизацией потоков, марашлингом и блокирующими вызовами. Все это _очень_ недешево.
Re[90]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Повторяю в очередной раз. Это один из двух важных аспектов. Другой — устранение промежуточных данных на этапе компиляции. Если есть и то и другое — иммутабельностью можно даже начинать пользоваться, а не обосновывать, почему без нее можно обойтись. K>>Каждый раз, когда я говорю, что при работе с персистентными структурами будет выделятся куча объектов в памяти, в том числе и много короткоживущих, вы скипаете текст и в очередной раз удивляетесь — чего это я такое значение сборщику мусора придаю. Попробуйте связать одно с другим. Связь есть — точно вам говорю.
_>Ещё раз, я не говорю о том, что неважна скорость работы сборщика мусора (тем более, если речь о языке, в котором это единственный способ выделения памяти).
Klapaucius говорит не про скорость. точнее основной его поинт не в скорости работы GC. А ты рассматриваешь GC исключительно со стороны перформанса.
>Я пытаюсь напомнить, что кроме сборщика мусора может ещё множество разных вариантов. Может быть и банальный подсчёт ссылок
Ну вот этого достаточно. Каким это образом подсчет ссылок вдруг поможет с освобождением памяти, в которой вагон циклических ссылок, что собтсвенно типичный случай ?
То есть, в кратце, если говорить про автоматический сбор, то это только GC. Все остальные это просто варианты ручной работы. Скажем, с циклическими ссылками придется протащить методы в АПИ, только для того, что бы память корректно освобождалась.
Re[89]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет, мап самый обычный. Если вашу дишную чистоту нельзя использовать для того, чтоб функция могла проконтролировать, что в нее именно чистые функции передаются — то никаким надмножеством чистоты в математическом смысле она не является.
С помощью Dивной статической интроспекции проконтролировать, чтобы передаваемые функции были только действительно чистыми, совсем не сложно.
Они с проблемами недостаточно чистых ф-й согласны, но говорят, что если такие ф-и заворачивать в полностью чистые (с иммутабельными параметрами), то сразу получаешь как бенефиты хаскельной чистоты, так и более развязанные руки по реализации этих чистых ф-й внутри.
Re[86]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В свою очередь классика ФП разделяет эти вещи — типы отдельно от модулей. Что характерно, и там и там в основе типов лежит АТД. Отсюда ясно что оба подхода могут и используют один и тот же UML
_>Да, безусловно можно разработать некий вид диаграмм (и даже включить их в стандарт UML), которые будут отлично отображать эти две сущности. Могу даже предложить для этого взять за основу диаграмму классов, в которой чуть поменять свойства для значка класса, добавить новый значок для модулей, и соответственно пересмотреть набор возможных видов связей.
Не надо ничего менять. Во первых, в ООП и так есть модули, хотя бы на уровне библиотеки. Во вторых, если в Хаскеле класть руками один АТД в один модуль, то получится тот самый класс.
Более того, наследование в ООП используется
1. как уточнение типа
2. как расширение функционала как модуля
И то и другое требует вообще говоря разных стрелочек, но на практике обходятся одной. Более того, можно вообще все стрелочки заменить на стрелочка + её назначение, наприме 'use'. Собтсвенно именно это и видим.
_>Т.е. основная моя мысль в том, что в теории то без проблем, а на практике (в существующих стандартах и соответственно инструментах) фигово у чистых ФЯ с этим делом.
ФЯ всего лишь не имеют внятной поддержки на уровне синтаксиса, потому что все скобочки заюзали под АТД и прочие вещи, для ОО ничего не осталось. Остаётся поддерживать ОО на уровне библиотеки.
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Вообще, я немного погорячился. монады отделяют не просто побочные эффекты от вычислений, а эффекты, вообще, от вычислений.
Что такое в данном контексте эффекты, вычисления и что значит "отделяют"?
Re[8]: Есть ли вещи, которые вы прницпиально не понимаете...
Ничего не понял. Где тут монада, где вычисления, а где побочные эффекты?
I>Давай перечислим вместе эти специфические задачи I>обработка исключительных ситуаций. I>вычисления с множественными результатами I>асинхронный результат I>обработка событий I>вычисления с изменяемым состоянием I>ввод-вывод
I>Как видишь, задачи мягко говоря широко распространены.
Не не не.. Это ты по сути перечисляешь области, в которых используются инструменты построенные внутри с помощью монад (чаще всего не специально)... При таком раскладе проще было сказать вообще "всё программирование" и не ошибиться. Но это будет уже вторая итерация использования. А я то говорю о первой (о тех самых инструментах), а их как раз совсем не много.
Смотри, монада у нас получается если:
1. Есть некий контейнер, для разных типов.
2. На базе него мы строим конвейер последовательной обработки данных.
3. Конвейер строится из функций специфического вида: T1 -> C<T2>, где C — это наш контейнер.
4. Соответственно преобразование (условно говоря) вида C<T> -> T происходит автоматически на каждом шаге конвейера и как раз и задаёт ту самую полезную функциональность данной конкретной монады.
Всё это в сумме задаёт очень специфическую схему. Которая может удобно укладываться только на редкие задачки, типа той же реализации библиотеки продолжений или билиотеки диапазонов. А вот то, что эти библиотеки потом могут использоваться очень много где, никто и не спорит.
I>Вот взять Promise — эффект здесь временная задержка, с помощью монады вычисления отделяются от эффекта, то есть, задержки.
Ну скажем promise/future из C++11 (в которых нет then) не имеют никакого отношения к монадам. Но тем не менее точно так же абстрагируют результат от задержки. )
I>Если ты захочешь, что бы код вычисления был в одном месте, то в императивном коде у тебя будут вагоны приседаний скажем с многопоточностью, синхронизацией потоков, марашлингом и блокирующими вызовами. Все это _очень_ недешево.
Ты похоже пропустил, что я писал. В большинстве случаев при написание указанных выше библиотек никто не старался специально "построить монаду". Они просто писали обычный императивный код, создавая оптимальную архитектуру под свою конкретную задачу. И вот иногда при этом получаются схемы полностью попадающие под определение монады. Ну так и отлично. Или ты считаешь, что я против такого, и обнаружив внезапно возникшую в моём коде монаду, резко побегу менять всю архитектуру? )))
Бредовость я вижу в другом. Если человек начнёт специально стараться получать монады везде в своём коде — вот это уже клиника...
Re[91]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Klapaucius говорит не про скорость. точнее основной его поинт не в скорости работы GC. А ты рассматриваешь GC исключительно со стороны перформанса.
Не не не, он как раз на эффективность GC и напирает в данном разговоре. Что мол в D хотя GC и есть, но дохленький и следовательно (по его логике) нормально использовать иммутабельные данные в D нельзя. На что я ему намекаю, что в системных языках есть множество разных инструментов для эффективной работы с памятью. И мы вполне можем использовать иммутабельные данные и поверх них...
I>Ну вот этого достаточно. Каким это образом подсчет ссылок вдруг поможет с освобождением памяти, в которой вагон циклических ссылок, что собтсвенно типичный случай ?
I>То есть, в кратце, если говорить про автоматический сбор, то это только GC. Все остальные это просто варианты ручной работы. Скажем, с циклическими ссылками придется протащить методы в АПИ, только для того, что бы память корректно освобождалась.
Ну как раз далеко не всё ручное. Основная часть вообще может через стек работать (т.е. сами данные естественно в динамической памяти, но выделяются/освобождаются через конструктор/деструктор объекта на стеке). Но даже если бы и ручное, то что? ) Это как-то принципиально мешает использовать иммутабельные объекты? )
Re[87]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не надо ничего менять. Во первых, в ООП и так есть модули, хотя бы на уровне библиотеки.
Ага и для них в uml есть замечательная диаграммка пакетов... )
I>Во вторых, если в Хаскеле класть руками один АТД в один модуль, то получится тот самый класс.
Вот вот. Только соблюдая это дополнительное правило, мы начнём получать нечто отдалённо напоминающее (всё равно ещё есть набор нюансов) инкапсуляцию ООП. Но в любом случае останется непонятным как отображать такое в UML.
I>Более того, наследование в ООП используется I>1. как уточнение типа I>2. как расширение функционала как модуля
I>И то и другое требует вообще говоря разных стрелочек, но на практике обходятся одной. Более того, можно вообще все стрелочки заменить на стрелочка + её назначение, наприме 'use'. Собтсвенно именно это и видим.
Не, не выйдет, т.к. там есть и отношения времени исполнения и времени компиляции. Т.е. говоря ООП языком, там не только классы, но и объекты задаются. Собственно там даже их имена на стрелочках указываются... Это я про нормальный UML к ООП программе. А в случае Хаскеля явно надо придумывать новые значки и новые связи...
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Ничего не понял. Где тут монада, где вычисления, а где побочные эффекты?
У тебя все перед носом
I>>Как видишь, задачи мягко говоря широко распространены.
_>Не не не.. Это ты по сути перечисляешь области, в которых используются инструменты построенные внутри с помощью монад (чаще всего не специально)... При таком раскладе проще было сказать вообще "всё программирование" и не ошибиться. Но это будет уже вторая итерация использования. А я то говорю о первой (о тех самых инструментах), а их как раз совсем не много.
И что это за "те самые инструменты" ?
_>Всё это в сумме задаёт очень специфическую схему. Которая может удобно укладываться только на редкие задачки, типа той же реализации библиотеки продолжений или билиотеки диапазонов. А вот то, что эти библиотеки потом могут использоваться очень много где, никто и не спорит.
Каждая монада по отдельности решает узкую задачу. Все вмести они покрывают весь спектр насущных задач.
_>Ну скажем promise/future из C++11 (в которых нет then) не имеют никакого отношения к монадам. Но тем не менее точно так же абстрагируют результат от задержки. )
Есди ты про те future, у которых есть метод then, то это они и есть. А другие, у которых такого метода нет, ничего не абстрагируют.
_>Ты похоже пропустил, что я писал. В большинстве случаев при написание указанных выше библиотек никто не старался специально "построить монаду". Они просто писали обычный императивный код, создавая оптимальную архитектуру под свою конкретную задачу. И вот иногда при этом получаются схемы полностью попадающие под определение монады. Ну так и отлично. Или ты считаешь, что я против такого, и обнаружив внезапно возникшую в моём коде монаду, резко побегу менять всю архитектуру? )))
Не иногда, а всегда. Императивный код это явное управление эффектом. То же самое и делает монада, только при этом отделяет эффект от вычисления.
Если тебе нужно такое отделение, то и в императивном языке ты изобретешь ровно такие же механизмы.
Re[9]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, NeoCode, Вы писали:
I>>Вообще, я немного погорячился. монады отделяют не просто побочные эффекты от вычислений, а эффекты, вообще, от вычислений.
NC>Что такое в данном контексте эффекты, вычисления и что значит "отделяют"?
Вот это все асинхронная последовательность вызовов — таймаут, запрос http, запись в файл и логирование ошибки. Это вычисления, при чем первая часть, где таймаут выполняется паралельно.
Асинхронная — значит вызовы неблокирующие, в т.ч. и timeout. Поток в это время находится в idle, если нет никакой другой работы.
Поскольку вызовы неблокирующие, то все это может и работает ровно в одном потоке.
Re[88]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вот вот. Только соблюдая это дополнительное правило, мы начнём получать нечто отдалённо напоминающее (всё равно ещё есть набор нюансов) инкапсуляцию ООП. Но в любом случае останется непонятным как отображать такое в UML.
Точно так же. Представь, в джаваскрипте нет классов. Это не мешает клепать UML. B модулей нет. И это не мешает использовать модули на UML диаграммах. И наследования нет, и это не мешает рисовать стрелочки.
I>>И то и другое требует вообще говоря разных стрелочек, но на практике обходятся одной. Более того, можно вообще все стрелочки заменить на стрелочка + её назначение, наприме 'use'. Собтсвенно именно это и видим.
_>Не, не выйдет, т.к. там есть и отношения времени исполнения и времени компиляции. Т.е. говоря ООП языком, там не только классы, но и объекты задаются. Собственно там даже их имена на стрелочках указываются... Это я про нормальный UML к ООП программе. А в случае Хаскеля явно надо придумывать новые значки и новые связи...
Не надо ничего придумывать. см пример про джаваскрипт
Re[10]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Каждая монада по отдельности решает узкую задачу. Все вмести они покрывают весь спектр насущных задач.
Ага, весь спектр "задач с конвейерами данных, всегда имеющими одинаковое дополнительное действие на каждой стадии". Очень широко... )))
I>Есди ты про те future, у которых есть метод then, то это они и есть. А другие, у которых такого метода нет, ничего не абстрагируют.
У них есть метод get (собственно если бы его не было, то эти future вообще не нужны были бы), который позволяет спокойно оперировать с результатом вычислений, не думая готов он уже или ещё нет. Так что как видишь имеем полное абстрагирование и без всяких монад. Просто на его основе не построишь цепочку (тот самый конвейер), но само отделение "эффекта", как видишь, присутствует.
I>Если тебе нужно такое отделение, то и в императивном языке ты изобретешь ровно такие же механизмы.
Только если потребуется именно конвейер. Иначе достаточно вынесения "эффекта" в библиотечную функцию. )
Re[89]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Точно так же. Представь, в джаваскрипте нет классов. Это не мешает клепать UML. B модулей нет. И это не мешает использовать модули на UML диаграммах. И наследования нет, и это не мешает рисовать стрелочки.
JS — это императивный язык с ООП (насчёт наследования ты загнул конечно). Так что как раз большинство uml диаграмм ему отлично подходят. А Хаскель — это декларативный язык без ООП и соответственно у него тут полный мрак.
Re[90]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Точно так же. Представь, в джаваскрипте нет классов. Это не мешает клепать UML. B модулей нет. И это не мешает использовать модули на UML диаграммах. И наследования нет, и это не мешает рисовать стрелочки.
_>JS — это императивный язык с ООП (насчёт наследования ты загнул конечно).
Классов нет. Наследования классов, соответсвенно, тоже нет. А стрелочки обычные.
>Так что как раз большинство uml диаграмм ему отлично подходят. А Хаскель — это декларативный язык без ООП и соответственно у него тут полный мрак.
Как и джаваскрипт. В ём все ООП поддерживается на уровне библиотеки.
Re[11]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Каждая монада по отдельности решает узкую задачу. Все вмести они покрывают весь спектр насущных задач.
_>Ага, весь спектр "задач с конвейерами данных, всегда имеющими одинаковое дополнительное действие на каждой стадии". Очень широко... )))
Это мягко говоря заблуждение.
I>>Есди ты про те future, у которых есть метод then, то это они и есть. А другие, у которых такого метода нет, ничего не абстрагируют.
_>У них есть метод get (собственно если бы его не было, то эти future вообще не нужны были бы), который позволяет спокойно оперировать с результатом вычислений, не думая готов он уже или ещё нет.
Покажи как он отделяет вычисления от эффекта.
>Просто на его основе не построишь цепочку (тот самый конвейер), но само отделение "эффекта", как видишь, присутствует.
Цепочка == вычисления. Где отделение эффекта, если вычисления нереализуемы именно из за эффекта ? Опаньки !
I>>Если тебе нужно такое отделение, то и в императивном языке ты изобретешь ровно такие же механизмы.
_>Только если потребуется именно конвейер. Иначе достаточно вынесения "эффекта" в библиотечную функцию. )
Ты пока что показал, что вычисления у тебя возможны или только вместе с эффектом или невозможны вообще.
Re[92]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Klapaucius говорит не про скорость. точнее основной его поинт не в скорости работы GC. А ты рассматриваешь GC исключительно со стороны перформанса.
_>Не не не, он как раз на эффективность GC и напирает в данном разговоре.
Нет, это ты рассматриваешь ГЦ исключительно со стороны перформанса.
>Что мол в D хотя GC и есть, но дохленький и следовательно (по его логике) нормально использовать иммутабельные данные в D нельзя. На что я ему намекаю, что в системных языках есть множество разных инструментов для эффективной работы с памятью. И мы вполне можем использовать иммутабельные данные и поверх них...
Идейка в том, что в D GC приблизительно равен его отсутствию.
I>>То есть, в кратце, если говорить про автоматический сбор, то это только GC. Все остальные это просто варианты ручной работы. Скажем, с циклическими ссылками придется протащить методы в АПИ, только для того, что бы память корректно освобождалась.
_>Ну как раз далеко не всё ручное. Основная часть вообще может через стек работать (т.е. сами данные естественно в динамической памяти, но выделяются/освобождаются через конструктор/деструктор объекта на стеке). Но даже если бы и ручное, то что? ) Это как-то принципиально мешает использовать иммутабельные объекты? )
Да, мешает. Ручной контроль резко меняет весь дизайн решения.
Re[91]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Классов нет. Наследования классов, соответсвенно, тоже нет. А стрелочки обычные.
Зато прототипы есть. ))) Да, в js ООП немного не такое, как в классических реализациях. Но там всё же именно ООП.
>>Так что как раз большинство uml диаграмм ему отлично подходят. А Хаскель — это декларативный язык без ООП и соответственно у него тут полный мрак. I>Как и джаваскрипт. В ём все ООП поддерживается на уровне библиотеки.
О да, js такой весь из себя декларативный...
Re[12]: Есть ли вещи, которые вы прницпиально не понимаете...
_>>Ага, весь спектр "задач с конвейерами данных, всегда имеющими одинаковое дополнительное действие на каждой стадии". Очень широко... ))) I>Это мягко говоря заблуждение.
Да? ) Ну покажи мне монаду, которая не укладывается в эту формулировку...
I>Покажи как он отделяет вычисления от эффекта.
А то ты не представляешь... ) Пишем где-то наверху auto r=async(calculation); а потом где угодно в коде можем использовать результат вычислений с помощью r.get(), не думая, успел он там уже вычислиться или же нет.
>>Просто на его основе не построишь цепочку (тот самый конвейер), но само отделение "эффекта", как видишь, присутствует. I>Цепочка == вычисления. Где отделение эффекта, если вычисления нереализуемы именно из за эффекта ? Опаньки !
Вычисления == цепочка в монаде — это как раз только в декларативных языках. А здесь мы можем спокойно задавать вычисления обычной последовательностью императивного кода.
Кстати, та же идиома RAII — это один из самых красивых примеров "отделения эффектов" в императивном коде. И опять же без всяких монад.
Re[93]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Классов нет. Наследования классов, соответсвенно, тоже нет. А стрелочки обычные.
_>Зато прототипы есть. ))) Да, в js ООП немного не такое, как в классических реализациях. Но там всё же именно ООП.
Прототипы это не классы. Оно не просто немного не такое, оно очень сильно не такое. Классическое ООП поддерживается исключительно на уровне библиотеки.
I>>Как и джаваскрипт. В ём все ООП поддерживается на уровне библиотеки.
_>О да, js такой весь из себя декларативный...
При чем здесь декларативность, алё ? На уровне библиотеки любой язык поддерживает любую фичу.
Вот это класс
var X = (function(){ ... })();
Вот это модуль
var X = (function(){ ... })();
Вот это неймспейс
var X = (function(){ ... })();
Вот это скоп
(function(){ ... })();
Ты видишь здесь декларативный код ? Его нет. Зато это не мешает говорить об этом коде как о классах, модулях, неймспейсах и тд
Re[93]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
_>>О да, js такой весь из себя декларативный...
I>При чем здесь декларативность, алё ? На уровне библиотеки любой язык поддерживает любую фичу.
I>...
I>Ты видишь здесь декларативный код ? Его нет. Зато это не мешает говорить об этом коде как о классах, модулях, неймспейсах и тд
Ты похоже совсем не понял о чём речь. )
1. Про декларативный js — это была ирония. )))
2. А вот то, что Хаскель у нас декларативный, вызывает большие проблемы для него в uml. Только здесь уже речь шла не о диаграмме классов, а о других важнейших диаграммах (это всё обсуждалось где-то выше).
Re[13]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>>>Ага, весь спектр "задач с конвейерами данных, всегда имеющими одинаковое дополнительное действие на каждой стадии". Очень широко... ))) I>>Это мягко говоря заблуждение.
_>Да? ) Ну покажи мне монаду, которая не укладывается в эту формулировку...
Уже. Смотри внимательно пример про промисы. Там сходу сразу два действия паралельно.
I>>Покажи как он отделяет вычисления от эффекта.
_>А то ты не представляешь... ) Пишем где-то наверху auto r=async(calculation); а потом где угодно в коде можем использовать результат вычислений с помощью r.get(), не думая, успел он там уже вычислиться или же нет.
Нет, не представляю. Я вижу, что вызов get блокирует поток и вычисление приостанавливается. То есть, фактически эффект есть часть вычисления.
I>>Цепочка == вычисления. Где отделение эффекта, если вычисления нереализуемы именно из за эффекта ? Опаньки !
_>Вычисления == цепочка в монаде — это как раз только в декларативных языках.
То есть, цепочка вида
mov ax, bx
inc ax, 1
push ax
принадлежит декларативному языку ? Опаньки !!!
> А здесь мы можем спокойно задавать вычисления обычной последовательностью императивного кода.
Можно, но или вместе с эффектом или никак вообще.
_>Кстати, та же идиома RAII — это один из самых красивых примеров "отделения эффектов" в императивном коде. И опять же без всяких монад.
RAII это отделение некоторого контекста, а не эффекта. Контекст — стратегия инициализации, область видимости, счетчик ссылок и тд и тд.
Если ты переживаешь, что это без всяких монадо, то я тебя обрадую — это действительно не монады, это ко-монады.
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Да, мешает. Ручной контроль резко меняет весь дизайн решения.
_>Ну меняет и что? ) Как это мешает использовать иммутабельные структуры? )
А что, для иммутабельных структур не надо память выделять ? Вот так новость.
Re[14]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Уже. Смотри внимательно пример про промисы. Там сходу сразу два действия паралельно.
Нет, там все вычисления в рамках монады идут строго последовательно. Собственно в этом и есть весь смысле then конструкци... А то, что там в материнском потоке (и может ещё в десятке других) ещё какой-то код вычисляется, к монаде никакого отношения не имеет.
I>Нет, не представляю. Я вижу, что вызов get блокирует поток и вычисление приостанавливается. То есть, фактически эффект есть часть вычисления.
Ну так нам же об этом беспокоиться не надо, оно всё автоматом происходит где-то там... )
I>RAII это отделение некоторого контекста, а не эффекта. Контекст — стратегия инициализации, область видимости, счетчик ссылок и тд и тд. I>Если ты переживаешь, что это без всяких монадо, то я тебя обрадую — это действительно не монады, это ко-монады.
Без строгих формул это всё слишком эфемерные понятия. Контекст, эффект... В самих монадах же всё совсем не так, гораздо проще и при этом строже. Я уже показывал тебе формулировку подходящую. Кстати, а для ко-монад у тебя есть формулировка? )))
Re[95]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>А что, для иммутабельных структур не надо память выделять ? Вот так новость.
_>Надо, и будем выделять, без gc. Какие-то проблемы? )))
Покажи как ты собираешься освобождать памятью.
Re[15]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Уже. Смотри внимательно пример про промисы. Там сходу сразу два действия паралельно.
_>Нет, там все вычисления в рамках монады идут строго последовательно.
Правильно. И это особенность не монады, а вычислений. Если для вычислений не нужны такие свойства, то и монады там никому не интересны.
Скажем, если ты делаешь операцию "перевести средства с одного счета на другой", то последовательные вычисления не имеют никакого отношения к монаде, это свойство самой задачи.
Отсюда ясно, что это свойство можно реализовать двумя способами
1. императивный код, в котором инструкции выполняются последовательно
2. монады, в которых операции выполняются последовательно
3. функции, в которых реализована конкретная последовательность вычислений
Еще пример задачи — покрасить автомобиль. Здесь четкая последовательность — зачистка, шпаклевка, шлифовка, грунтовка, покраска, полировка.
Вопрос — где здесь монады ?
I>>Нет, не представляю. Я вижу, что вызов get блокирует поток и вычисление приостанавливается. То есть, фактически эффект есть часть вычисления.
_>Ну так нам же об этом беспокоиться не надо, оно всё автоматом происходит где-то там... )
Ога.
I>>RAII это отделение некоторого контекста, а не эффекта. Контекст — стратегия инициализации, область видимости, счетчик ссылок и тд и тд. I>>Если ты переживаешь, что это без всяких монадо, то я тебя обрадую — это действительно не монады, это ко-монады.
_>Без строгих формул это всё слишком эфемерные понятия.
Открой теорию категорий да посмотри, там все в самом строгом виде, строже некуда.
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ты похоже совсем не понял о чём речь. )
_>1. Про декларативный js — это была ирония. )))
А я тебе сказал, что ирония не уместна.
_>2. А вот то, что Хаскель у нас декларативный, вызывает большие проблемы для него в uml. Только здесь уже речь шла не о диаграмме классов, а о других важнейших диаграммах (это всё обсуждалось где-то выше).
Нисколько. Я вот смотрю в wxHaskell и не вижу что бы твои слова подтверждались. Т.е. декларативность нисколько не мешает хаскелю в случае с ООП
Re[97]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Покажи как ты собираешься освобождать памятью.
Так по разному, зависит от конкретной задачи. Вот например у меня тут в одном реальном приложение изначально выделяется большой кусок памяти и используется всё время работы приложения — тут можно и вообще не удалять.
Но я не очень понял как это всё относится к вопросу использования иммутабельных данных. Это же вообще ортогональные вещи. Можно же использовать:
— иммутабельные данные через gc
— мутабельные данные через gc
— иммутабельные данные с ручным выделением памяти
— мутабельные данные с ручным выделением памяти
— иммутабельные данные через подсчёт ссылок
— мутабельные данные через подсчёт ссылок
— иммутабельные данные на стеке
— мутабельные данные на стеке
— иммутабельные данные на пуле
— мутабельные данные на пуле
....
Re[16]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Правильно. И это особенность не монады, а вычислений. Если для вычислений не нужны такие свойства, то и монады там никому не интересны.
Воот, наконец то ты всё правильно сформулировал. Так вот как раз из этого и следует моя основная мысль, что монады задают только подмножество императивного кода. Соответственно, если мы используем их только для подходящих задач, то всё отлично. А вот если будем пытаться задавать всё через них (типа как в декларативных языках, где других вариантов нет), то будем себя серьёзно ограничивать.
I>Открой теорию категорий да посмотри, там все в самом строгом виде, строже некуда.
Угу, только там нет ни "эффектов", ни "контекстов"... Да и вообще это не имеет отношения к программному коду. Нужна интерпретация... Вот для монад я тебе показывал нормальные практические определения, хотя знаю и математическое. А для ко-монад ты можешь что-нибудь практическое показать? )
Re[95]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нисколько. Я вот смотрю в wxHaskell и не вижу что бы твои слова подтверждались. Т.е. декларативность нисколько не мешает хаскелю в случае с ООП
Во-первых, декларативность мешает не ООП, а использованию диаграмм действий и последовательностей (которые вместе с диаграммой классов являются основными в uml).
А во-вторых, ты действительно считаешь, что в Хаскеле есть ООП? ) Klapaucius наверное будет шокирован (для него же ООП — зло)... )))
Re[98]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Покажи как ты собираешься освобождать памятью.
_>Так по разному, зависит от конкретной задачи. Вот например у меня тут в одном реальном приложение изначально выделяется большой кусок памяти и используется всё время работы приложения — тут можно и вообще не удалять.
_>Но я не очень понял
Покажи как ты собираешься освобождать память. Не надо никаких слов, просто кусочек кода — upward funarg, замыкание , move semantic и освобождение памяти.
Re[96]: Есть ли вещи, которые вы прницпиально не понимаете...
I>>Нисколько. Я вот смотрю в wxHaskell и не вижу что бы твои слова подтверждались. Т.е. декларативность нисколько не мешает хаскелю в случае с ООП
_>Во-первых, декларативность мешает не ООП,
Правильно. Более того — она вообще не мешает ООП.
>а использованию диаграмм действий и последовательностей (которые вместе с диаграммой классов являются основными в uml).
А раз не мешает, то стало быть нет никаких проблем по диаграмме классов накидать код.
_>А во-вторых, ты действительно считаешь, что в Хаскеле есть ООП? ) Klapaucius наверное будет шокирован (для него же ООП — зло)... )))
В хаскеле ООП реализуется на уровне библиотеки. Странно, да ? А тебе не кажется странным, что на уровне библиотеки оно поддерживается не только в языке Си (без плюсов), но и ассемблере ?
Re[99]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Покажи как ты собираешься освобождать память. Не надо никаких слов, просто кусочек кода — upward funarg, замыкание , move semantic и освобождение памяти.
Ты не спутал темки? ) Здесь мы говорим про иммутабельные данные, а не про замыкания без gc. Про замыкания без gc у нас разговор в темке про Swift. Но для меня не напряжно показать и здесь... Только не думай, что я при этом забуду про тему иммутабельных данных — ты так и не показал какие у них могут быть проблемы в следствие отсутствия gc.
auto MakeF()
{
int x=42;
return [=]{return x};//здесь выделяется память для int'a
}
{
auto f=MakeF();
f();
}//здесь память будет освобождена
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Ты не спутал темки? ) Здесь мы говорим про иммутабельные данные, а не про замыкания без gc. Про замыкания без gc у нас разговор в темке про Swift. Но для меня не напряжно показать и здесь... Только не думай, что я при этом забуду про тему иммутабельных данных — ты так и не показал какие у них могут быть проблемы в следствие отсутствия gc.
Представь себе что замыкания иммутабельные.
_>
_>auto MakeF()
_>{
_> int x=42;
_> return [=]{return x};//здесь выделяется память для int'a
_>}
_>{
_> auto f=MakeF();
_> f();
_>}//здесь память будет освобождена
_>
То есть, для всех иммутабельных данных ты предлагаешь расходовать стек ? Придется передавать их по значению и тд и тд.
Ты точно уверен, что получишь перформанс ?
Re[97]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А раз не мешает, то стало быть нет никаких проблем по диаграмме классов накидать код.
Ну давай, расскажи, кто на твой взгляд будет единицей инкапсуляции в Хаскеле. С этим даже Klapaucius никак справиться не может. Посмотрим что ты скажешь...
I>В хаскеле ООП реализуется на уровне библиотеки. Странно, да ? А тебе не кажется странным, что на уровне библиотеки оно поддерживается не только в языке Си (без плюсов), но и ассемблере ?
И как у нас там реализовано наследование? )
Re[101]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Представь себе что замыкания иммутабельные.
Вообще то они именно такие и есть по умолчанию. Чтобы сделать мутабельными, надо добавить специальный модификатор.
I>То есть, для всех иммутабельных данных ты предлагаешь расходовать стек ? Придется передавать их по значению и тд и тд.
I>Ты точно уверен, что получишь перформанс ?
Если вместо инта был бы vector<int>(1000000000), то у нас действительно была бы проблемка... До появления move semantics её решали с помощью всяческих shared_ptr и т.п. Тоже вполне себе решение, но не идеальное. А вот с move semantics мы получим поведение полностью как в примере с int'ом и при этом будет копирование всего лишь sizeof(vector<Т>), т.е. жалкие 12 байт (на 32 битной машине)...
Re[98]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>А раз не мешает, то стало быть нет никаких проблем по диаграмме классов накидать код.
_>Ну давай, расскажи, кто на твой взгляд будет единицей инкапсуляции в Хаскеле. С этим даже Klapaucius никак справиться не может. Посмотрим что ты скажешь...
Я не знаю что ты понимаешь под инкапсуляцией. Судя по твоим ответам это чтото навроде игры в пермишны.
На уровне библиотеки это можно сделать бесконечным количеством способов. В любом языке. За доказательством смотри полноту по тьюрингу.
Можно, скажем, хоть акторы реализовать.
Re[102]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты точно уверен, что получишь перформанс ?
_>Если вместо инта был бы vector<int>(1000000000), то у нас действительно была бы проблемка... До появления move semantics её решали с помощью всяческих shared_ptr и т.п. Тоже вполне себе решение, но не идеальное. А вот с move semantics мы получим поведение полностью как в примере с int'ом и при этом будет копирование всего лишь sizeof(vector<Т>), т.е. жалкие 12 байт (на 32 битной машине)...
То есть, все иммутабельные объекты независимо от кода это 12 байт ? Правильно я тебя понял ?
А что если я захвачу 10 гуидов ? А если другой иммутабельный объект, что как бы типичный случай ? А если таких объектов будет целая цепочка, чего делать ?
Re[98]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>А раз не мешает, то стало быть нет никаких проблем по диаграмме классов накидать код.
_>Ну давай, расскажи, кто на твой взгляд будет единицей инкапсуляции в Хаскеле. С этим даже Klapaucius никак справиться не может. Посмотрим что ты скажешь...
Здравствуйте, Ikemefula, Вы писали:
I>Я не знаю что ты понимаешь под инкапсуляцией. Судя по твоим ответам это чтото навроде игры в пермишны.
Инкапсуляция очевидно должна осуществлять замыкание некого набора данных (и таких однотипных кусков может быть много) и кода, работающего с этими данными. Так вот у меня был вопрос в какую сущность инкапсулируются данные в Хаскеле... В ООП этой сущностью является собственно объект.
I>На уровне библиотеки это можно сделать бесконечным количеством способов. В любом языке. За доказательством смотри полноту по тьюрингу.
Нельзя. Т.е. можно, если мы говорим о наследование времени исполнения (своеобразной разновидностью композиции). Но это совсем не эффективно по сравнению с нормальным наследованием времени компиляции. Вот его на библиотеках не реализуешь. Естественно если речь не о чём-то типа библиотеки крутых макросов позволяющих мощное метапрограммирование.
I>Можно, скажем, хоть акторы реализовать.
Акторы по идее и не требуют ничего интересного во время компиляции...
Re[103]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, все иммутабельные объекты независимо от кода это 12 байт ? Правильно я тебя понял ?
Значит смотри, в C++ принято:
1. Использовать объекты на стеке. При этом у них обычно определены все соответствующие операторы, так что работа выглядит полностью как с каким-нибудь int'ом.
2. Если объект большого объёма, то он хранит данные в куче (а может и вообще быть какой-нибудь VirtualAlloc ), а за выделение/удаление этой памяти отвечает конструктор/деструктор этого объекта. сам же объект при этом по прежнему живёт на стеке и занимает при этом вообще каплю памяти.
3. Объекты можно передавать как по ссылке, так и по значению. И если для мелких объектов разницы особой нет, то для крупных передача по значению не эффективна (т.к. оператор копирования, копирует и ту динамическую память).
4. Однако возврат из функции ссылки на объект из стека этой функции не может работать. Поэтому имеем проблему, причём не только для замыканий, а вообще по эффективному возврату значения из функции. Т.е. надо или выделять возвращаемый объект в куче и возвращать ссылку на него или же терпеть неэффективный (и главное не нужный тут на самом деле) оператор копирования или же (эффективный, но не всегда уместный вариант и как раз для замыканий не подходящий) передавать в функцию ссылку на внешний объект, в качестве параметра.
5. Появление move semantics позволяет для всех подобных случаев заменить неэффективный оператор копирования на практически мгновенный оператор перемещения, тем самым полностью решая проблему.
Причём всё вышеперечисленное никак не зависит от того иммутабельные у нас данные или же нет. И я собственно так и не понял к чему ты обсуждаешь этот вопрос в теме про использование иммутабельных данных.
I>А что если я захвачу 10 гуидов ? А если другой иммутабельный объект, что как бы типичный случай ? А если таких объектов будет целая цепочка, чего делать ?
Кстати, насчёт мелких объектов... Советую глянуть в реализацию std::string — там обычно есть любопытная оптимизация для мелкий строк. )
Re[99]: Есть ли вещи, которые вы прницпиально не понимаете...
Не вижу по ссылке ни одного слова ни про комонады, ни про инкапсуляцию. Вижу только классы типов, которые являются аналогом скорее уж интерфейсов из ООП.
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
1.3 Hiding implementation details: use module export list
One more usage of OOP classes is to hide implementation details, making internal data/functions inaccessible to class clients. Unfortunately, this functionality is not part of type class facilities. Instead, you should use the sole Haskell method of encapsulation, module export list:
module Stack (Stack, empty, push, pop, top, isEmpty) where
newtype Stack a = Stk [a]
empty = Stk []
push x (Stk xs) = Stk (x:xs)
pop (Stk (x:xs)) = Stk xs
top (Stk (x:xs)) = x
isEmpty (Stk xs) = null xs
Since the constructor for the data type Stack is hidden (the export list would say Stack(Stk) if it were exposed), outside of this module a stack can only be built from operations empty, push and pop, and examined with top and isEmpty.
Re[5]: Есть ли вещи, которые вы прницпиально не понимаете...
Кстати, вот еще вопросы
1 в самом Хаскеле монады — это конструкция языка ("встроенная в компилятор") или что-то, построенное на основе других средств языка? Если последнее, то интересно как удается достичь соответствующего эффекта?
2 какие вообще бывают монады? Хочется как можно более полный список.
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я не знаю что ты понимаешь под инкапсуляцией. Судя по твоим ответам это чтото навроде игры в пермишны.
_>Инкапсуляция очевидно должна осуществлять замыкание некого набора данных (и таких однотипных кусков может быть много) и кода, работающего с этими данными. Так вот у меня был вопрос в какую сущность инкапсулируются данные в Хаскеле... В ООП этой сущностью является собственно объект.
Это очень странное определение инкапсуляции. Как будет устроен объект ООП ни разу специфицирует. Главное, что нужно обеспечить, это идентити. Т.е. нужна возможность послать сообщение конкретному объекту. А где и как этот объект будет хранить данные — дело десятое. Важно, что бы разные объекты могли работать со своими данными.
I>>На уровне библиотеки это можно сделать бесконечным количеством способов. В любом языке. За доказательством смотри полноту по тьюрингу.
_>Нельзя.
то есть, ты утверждаешь, что хаскель не обладает полнотой по тьюрингу ? Вот так новость.
?Т.е. можно, если мы говорим о наследование времени исполнения (своеобразной разновидностью композиции). Но это совсем не эффективно по сравнению с нормальным наследованием времени компиляции. Вот его на библиотеках не реализуешь. Естественно если речь не о чём-то типа библиотеки крутых макросов позволяющих мощное метапрограммирование.
Ты вероятно под ООП понимаешь исключительно вариант "инкапсуляция-наследование-полиморфизм как в С++". Между тем это всего лишь симуловское ООП, которое реализовано в С++. Скажем, Алан Кей, изобретатель ООП, c таким вариантом не согласен.
I>>Можно, скажем, хоть акторы реализовать.
_>Акторы по идее и не требуют ничего интересного во время компиляции...
У тебя есть сомнения, что на акторах реализуется ООП ?
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нельзя. Т.е. можно, если мы говорим о наследование времени исполнения (своеобразной разновидностью композиции). Но это совсем не эффективно по сравнению с нормальным наследованием времени компиляции. Вот его на библиотеках не реализуешь. Естественно если речь не о чём-то типа библиотеки крутых макросов позволяющих мощное метапрограммирование.
Здравствуйте, D. Mon, Вы писали:
DM>С помощью Dивной статической интроспекции проконтролировать, чтобы передаваемые функции были только действительно чистыми, совсем не сложно.
Насколько я понял, это будет выглядеть как строчка внутри map вроде
static assert(isPure!f)
где isPure — библиотечный код анализа f?
И достаточно будет сигнатуру проанализировать, и доступность исходного кода f не обязательна?
DM>Они с проблемами недостаточно чистых ф-й согласны, но говорят, что если такие ф-и заворачивать в полностью чистые (с иммутабельными параметрами), то сразу получаешь как бенефиты хаскельной чистоты, так и более развязанные руки по реализации этих чистых ф-й внутри.
Кстати, как в D используются бенефиты чистоты (компилятором, рантаймом и т.д.)? И насколько часто в библиотеках чистоту и иммутабельность аннотируют?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[90]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Формально то способ есть — отобразить как статические методы обычного класса и всё. Но на практике этот класс вообще не рисуют, т.к. он по сути является всего лишь заменой (и кстати весьма убогой) пространств имён, а функции в нём обычно носят утилитарный характер. Естественно мы говорим про ООП программу.
Ну, между модулями, в отличие от статических классов, могут быть нетривиальные отношения. Соответствующие агрегации, например. Так что их есть смысл на диаграмме показывать.
K>>В C# есть статический класс. Что, C# тоже не совместим с UML, как и хаскель?
_>Ну во всяком случае в стандате UML никакого специального выделения для статических классов нет.
Так ведь разве не для этого в UML стереотипы есть? Есть, допустим, в вашем языке сепулькарии. Берете значек для класса, даете ему стереотип "сепулькарий" — все.
_>Однако это естественно не мешает отображать их при надобности (хотя при классическом ООП это сомнительно) как обычный класс.
Вообще-то языков соответствующих "классическому ООП" сейчас примерно 0 — они все с расширениями (если что, это не смотря на то, что я не смолтокер и классическим ооп его не считаю) а UML все еще по какой-то причине кто-то использует.
_>А вот для генерации подобного кода видимо уже придётся использовать только фирменые инструменты от MS, в которых наверняка это как-то добавлено. )))
Не приходилось генерировать код фирменными инструментами от МС. Сгенерированные диаграммы видел — поддержка стат.классов в них действительно есть (рамки прямоугольников пунктирные, емнип)
_>Даже если забыть про то, что мы так и не договорились по факту наличия модулей на диаграмме классов
Просто потому, что вы высасываете проблемы из пальца. На самом деле нет никаких причин не использовать на диаграммах какие-то "неклассические" элементы.
_>то в любом случае здесь они являются всего лишь разновидностью пространства имён — никаких связей прорисовать не удастся.
Почему не удастся, если они есть? Отлично можно прорисовать.
_>Т.е. получится не связанная диаграмма, некий набор независимых значков. Или может вы например подскажете, как нам например отобразить какие функции из данного модуля работают с каким-то из данного АТД (одного из определённых в том же модуле)?
А как вы рисуете, какие методы одного класса работают с методами другого класса? В чем разница-то? В конце концов, вы можете принять соглашение, что функции определенные на данном АлгТД — должны в его прямоугольнике перечислятся (в диаграмме для реального хаскельного кода с которой все и началось именно так и сделано) для этого в UML ничего добавлять не надо, в конце концов, бывают ООЯ, в которых методы класса выглядят как свободные функции. Более того, ФВП можно изображать на диаграмме как классы, если нужно показать их роль "фабрик" например.
_>Ага, есть инкапсуляция... Ну например:
_>1. Если у нас есть несколько АТД определённых в модуле и плюс имеем в модуле функции, работающие с приватными внутренностями этих АТД, то я правильно понимаю, что все функции внутри этого модуля имеют доступ ко внутренностям всех АТД, даже если реально не имеют к ним никакого отношения?
Да, конечно. Непонятно, правда, что они тогда делают в обсуждаемом модуле, ну да ладно. А методы "внутри" класса имеют доступ ко всем внутренностям класса — вот ужас-то!
_>2. Я могу у какого-то АТД сделать доступ снаружи только к части данных? Т.е. не закрывая всё и вводя публичную функцию типа геттера, а именно доступ к самим данным, но частичный.
Да, конечно, можно закрывать только часть конструкторов и полей, не обязательно все или ничего.
_>Это только то что с ходу в голову пришло, без изучения деталей. Подозреваю, что если начать копаться, то столько всего найти можно...
Точно так же можно найти и плюсы у такой системы декларации приватности/публичности по сравнению с "атрибутной".
_>Вообще то для этих целей в C++ служат пространства имён, которые обладают своими мощными возможностям, уж точно превосходящими классы C++, а скорее всего и модули Хаскеля (тут вообще сложно сравнивать, т.к. предназначения немного различаются всё же — пространства имён никак не завязаны на компиляцию и т.п.)
Некоторое пересечение по функциональности у классов и с пространствами имен есть.
_>Ну естественно можно написать map, принимающий только чистые функции.
Но вы слишком заняты обоснованием ненужности иммутабельности, чтоб это продемонстрировать. Приходится у других спрашивать.
_>Только нафига он мне такой-то, зачем себя ограничивать?
А нафига мне какой-то фубар без свойств вместо мапа со свойствами?
Для того и нужен, чтоб себя не ограничивать в преобразовании кода и в рассуждении о нем.
_>Я вполне могу себе представить сценарии, в которых будет удобно применить map с не чистой функцией.
Ценой отказа от других сценариев.
_>Я так и не понял какое отношение эта тирада имеет к вопросу о нужности требования чистоты от параметров map'a.
Прямое.
K>>Каким образом это можно обеспечить, если "чистые" функции могут изменяемые данные получить?
_>Нуу грубо говоря: _>
_>class A {v=1;};
_>auto a=new A;
_>auto x=[a, a, a];//ссылки на один объект
_>auto f(А p) pure {++p.v; return v;}
_>auto y=map!f(y);//после этого вызова имеем:
_>//x=[A{4}, A{4}, A{4}]
_>//y=[A{2}, A{3}, A{4}]
_>
Я говорил не про это, а про то, что у A есть еще одно поле — ссылка на изменяемый класс, который для нескольких экземпляров A в списке может указывать на один и тот же экземпляр этого самого мутабельного класса.
_>Ну а я вот не уверен, что наличие мутабельных данных (даже не смотря на то, что в самом примере их никто не меняет) никак не влияет на получающийся код.
В каком примере никто мутабельные данные не меняет?
_>На внешность то изначального кода это влияет и довольно заметно...
Ничего не понимаю. Что на внешность изначального кода влияет? Какой изначальный код вообще имеется в виду?
_>работало только благодаря искусственно введённой вами поддержке этого.
Это неправда.
_>Да глупо это и не нормально по сути. Вот объясните мне зачем мне хранить историю изменения некой переменной, если я точно знаю, что старое значение мне больше никогда не понадобится (как в том же примере с обработкой кадров видео)?
Хранить, конечно, незачем. Так она и не будет хранится: версия не нужна, а значит нет ссылки на версию — версия не хранится.
_>Ещё раз, я не говорю о том, что неважна скорость работы сборщика мусора (тем более, если речь о языке, в котором это единственный способ выделения памяти). Я пытаюсь напомнить, что кроме сборщика мусора может ещё множество разных вариантов. Может быть и банальный подсчёт ссылок (кстати, вот Apple выкатили язык вообще базирующий на этом), может быть аллокатор на пуле, может быть вообще ручная работа с указателями, а может быть и моё любимое выделение на стеке (кстати, для некоторых персистентных структур такое вполне может быть интересно, если у них сами данные хранятся единым куском в динамической памяти, а бегают туда сюда различные ссылки на него, которые вполне эффективно хранить на стеке), да и мало ли что можно придумать в языке с полным доступом на низкий уровень. И большинство из перечисленных мною вариантов будут работать быстрее любого сборщика мусора (из любого языка). Ну и соответственно если вдруг очень хочется пострадать иммутабельными структурами, то никто не мешает построить их и вокруг такого базиса.
Замечательно. В форумном диспуте можно, конечно, хоть плац ломом подметать, хоть персистентные структуры на счетчиках ссылок строить, но в реализациях языков, где эти структуры действительно широко используются без всяких страданий вроде "что же я делаю!? зачем мне старые версии?" есть быстрый сборщик мусора. По простой причине: для иммутабельных структур данных и типичных нагрузок связанных с работой с ними оптимальное управление памятью — точный, перемещающий сборщик с поколениями. Не стек, не счетчики ссылок, не пулы, не регионы. Построить их вокруг такого базиса мешают головная боль и тормоза.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[92]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Не не не, он как раз на эффективность GC и напирает в данном разговоре. Что мол в D хотя GC и есть, но дохленький и следовательно (по его логике) нормально использовать иммутабельные данные в D нельзя. На что я ему намекаю, что в системных языках есть множество разных инструментов для эффективной работы с памятью. И мы вполне можем использовать иммутабельные данные и поверх них...
Так надо не намекать, а просто воспроизвести мой пример. При этом можно использовать любые "инструменты эффективной работы с памятью". Можете хоть счетчики ссылок использовать, хоть стек, хоть фрактальные пулы сепулькариев в подпространстве. Только вопроизведите мой пример на иммутабельных данных, с заметной нагрузкой на память, по всем условиям задачи, а не некий нерелевантный код, не использующий иммутабельные данные вообще — как в прошлый раз.
Вот тогда и посмотрим:
1) как все это будет выглядеть.
2) с какой скоростью будет работать.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[91]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
DM>>С помощью Dивной статической интроспекции проконтролировать, чтобы передаваемые функции были только действительно чистыми, совсем не сложно.
K>Насколько я понял, это будет выглядеть как строчка внутри map вроде K>
K>static assert(isPure!f)
K>
K>где isPure — библиотечный код анализа f?
Примерно так, да. Можно static assert внутри (тогда свое красивое сообщение можно выдать), а можно constraint в виде if перед телом. На скорую руку у меня такой пример заработал:
template isImmutable(T) { enum isImmutable = isScalarType!T || !isMutable!T; }
auto map(alias f, A)(A[] xs)
if (isSomeFunction!f && allSatisfy!(isImmutable, ParameterTypeTuple!f))
{
alias B = ReturnType!f;
auto bs = new B[xs.length];
foreach(i, x; xs)
bs[i] = f(x);
return bs;
}
void main(string[] argv)
{
auto bs = [1,2,3].map!((int x) => x.to!string);
writeln(bs);
}
ฺK>И достаточно будет сигнатуру проанализировать, и доступность исходного кода f не обязательна?
Да, сигнатуры должно быть достаточно.
K>Кстати, как в D используются бенефиты чистоты (компилятором, рантаймом и т.д.)? И насколько часто в библиотеках чистоту и иммутабельность аннотируют?
Аннотируют довольно старательно, где могут. По крайней мере, последнее время. Кроме того, для шаблонных функций (а библиотеки ими полны) чистота выводится компилятором автоматически. А вот используются ли бенефиты компилятором — хз. Брайт говорит, что какие-то оптимизации с чистотой есть, но на практике я их не видел пока.
Re[92]: Есть ли вещи, которые вы прницпиально не понимаете...
I>1.3 Hiding implementation details: use module export list
I>One more usage of OOP classes is to hide implementation details, making internal data/functions inaccessible to class clients. Unfortunately, this functionality is not part of type class facilities. Instead, you should use the sole Haskell method of encapsulation, module export list:
I>module Stack (Stack, empty, push, pop, top, isEmpty) where
I>newtype Stack a = Stk [a]
I>empty = Stk []
I>push x (Stk xs) = Stk (x:xs)
I>pop (Stk (x:xs)) = Stk xs
I>top (Stk (x:xs)) = x
I>isEmpty (Stk xs) = null xs
I>Since the constructor for the data type Stack is hidden (the export list would say Stack(Stk) if it were exposed), outside of this module a stack can only be built from operations empty, push and pop, and examined with top and isEmpty.
Ну так это ты как раз и процитировал ту самую инкапсуляцию уровня древнего паскаля... И заметь там слово "Unfortunately"...
Re[6]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, NeoCode, Вы писали:
NC>Кстати, вот еще вопросы NC>1 в самом Хаскеле монады — это конструкция языка ("встроенная в компилятор") или что-то, построенное на основе других средств языка? Если последнее, то интересно как удается достичь соответствующего эффекта?
Ну как сказать... Формально говоря оно всё же построено на других средствах, но при этом очень интегрировано в язык (к примеру функция Main живёт в монаде IO, т.е. без неё никак). Плюс в язык добавлен специальный синтаксический сахар (который в прочем не обязателен для использования) специально для монад.
А вот про "соответствующий эффект" я что-то не понял. Не вижу там ничего особенного, с чем были бы проблемы в других языках. К примеру в начале этой темке есть пример реализации полноценной монады на C++ в пару строчек...
NC>2 какие вообще бывают монады? Хочется как можно более полный список.
А в императивных языках большая часть этих монад или просто не нужна (в хаскеле их существование является следствием сомнительного дизайна языка) или их задача уже решена средствами самого императивного языка (исключения например и т.п.), соответственно более эффективно. Остаётся небольшая часть и я уже перечислил в предыдущем сообщение самые распространённые.
Re[101]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты вероятно под ООП понимаешь исключительно вариант "инкапсуляция-наследование-полиморфизм как в С++". Между тем это всего лишь симуловское ООП, которое реализовано в С++. Скажем, Алан Кей, изобретатель ООП, c таким вариантом не согласен.
Ну понятно что во время исполнения можно любой вариант реализовать. Но для языков типа C++ и Хаскеля (при всей их разнице) это очевидно не вариант.
Re[91]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну, между модулями, в отличие от статических классов, могут быть нетривиальные отношения. Соответствующие агрегации, например. Так что их есть смысл на диаграмме показывать.
Ага, на диаграмме пакетов — в точности соответствует...
K>Просто потому, что вы высасываете проблемы из пальца. На самом деле нет никаких причин не использовать на диаграммах какие-то "неклассические" элементы.
Хы, ну если рисовать на бумажке, то возможно. А если пользоваться всяческими мощными инструментами, то обязанность жить в рамках стандарта UML появляется сама собой...
K>А как вы рисуете, какие методы одного класса работают с методами другого класса?
Вообще то это как раз всё указывается связями, включая даже имена переменных на них. Но я тут про другое говорил. Про связь кода со своими данными (инкапсуляцию) — это в ООП и UML задаётся как бы автоматически, просто по построению.
K>В чем разница-то? В конце концов, вы можете принять соглашение, что функции определенные на данном АлгТД — должны в его прямоугольнике перечислятся (в диаграмме для реального хаскельного кода с которой все и началось именно так и сделано) для этого в UML ничего добавлять не надо, в конце концов, бывают ООЯ, в которых методы класса выглядят как свободные функции. Более того, ФВП можно изображать на диаграмме как классы, если нужно показать их роль "фабрик" например.
Ну да, если сделать вот так, то подобная диаграммка будет уже не плохо описывать архитектуру приложения. Правда при этом будет очень сложно объяснить незнакомому с ООП (представим себе такого фаната ФП) человеку, что же собственно мы обозначаем этими прямоугольниками... )))
Кстати, я смотрю вы уже вроде как осознали, что единицей инкапсуляции всё же АлгТД являются, а не что-то ещё...
K>Да, конечно. Непонятно, правда, что они тогда делают в обсуждаемом модуле, ну да ладно. А методы "внутри" класса имеют доступ ко всем внутренностям класса — вот ужас-то!
Ну если делать грубо говоря по модулю на тип, то действительно получится аналог стандартных вещей из ООП мира. Но я бы не сказал, что это приемлемое требование.
K>Да, конечно, можно закрывать только часть конструкторов и полей, не обязательно все или ничего.
Ну т.е. аналог struct S { int a; private: int b}; легко делается? )
K>А нафига мне какой-то фубар без свойств вместо мапа со свойствами? K>Для того и нужен, чтоб себя не ограничивать в преобразовании кода и в рассуждении о нем.
А с чего вы взяли, что у map'а должно быть такое свойство (требование чистой функции на входе)?
Я вообще не в первый раз замечаю за вами такую позицию, когда вы называете вашу (ну или "хаскельную") точку зрения общепринятым стандартом. Ну ладно, в случае понятия "чистоты" ещё можно дать "хаскельному" взгляду некие особые права, т.к. хаскель первопроходец в этой фиче. Но уж в случае map'ов, которые сейчас есть наверное в каждом языке и естественно нигде кроме хаскеля не в курсе ни про какую чистоту, навязывать своё видение как стандарт мягко говоря смешно.
_>>Я вполне могу себе представить сценарии, в которых будет удобно применить map с не чистой функцией. K>Ценой отказа от других сценариев.
С чего это будет отказ от каких-то сценариев? Чистые функции мы же не перестаём принимать...
K>Я говорил не про это, а про то, что у A есть еще одно поле — ссылка на изменяемый класс, который для нескольких экземпляров A в списке может указывать на один и тот же экземпляр этого самого мутабельного класса.
Это же будет буквально тоже самое, что и в моём предыдущем примере. "А" тогда будет просто лишним контейнером. Показать кодом или сами осознаете? )
Я так понимаю, что вы уже видите что ошиблись со своим утверждением насчёт нарушения того равенства? Но всё же признавать не хотите... Наверное в итоге доберётесь до игр с указателями, лишь бы не признать свою неправоту. )
K>Ничего не понимаю. Что на внешность изначального кода влияет? Какой изначальный код вообще имеется в виду?
Ну у вас было два примера кода для той задачки. Мутабельный и иммутабельный. Причём внешне они заметно отличались. А внутренне думаю ещё больше. Вы показали пример оптимизации циклов на маленьком кусочке с иммутабельными данными. А меня вот терзают сомнения на тему "а возможны ли эти же оптимизации для мутабельного аналога этого кода".
K>Хранить, конечно, незачем. Так она и не будет хранится: версия не нужна, а значит нет ссылки на версию — версия не хранится.
Угу, только мы должны в начале произвести работу по выяснению "нужна эта версия ещё или уже нет". В то время как в нормальном мутабельном коде никакого подобного бреда нет, т.к. мы заранее точно знаем ответ — никакие старые версии не нужны.
K>Замечательно. В форумном диспуте можно, конечно, хоть плац ломом подметать, хоть персистентные структуры на счетчиках ссылок строить, но в реализациях языков, где эти структуры действительно широко используются без всяких страданий вроде "что же я делаю!? зачем мне старые версии?" есть быстрый сборщик мусора. По простой причине: для иммутабельных структур данных и типичных нагрузок связанных с работой с ними оптимальное управление памятью — точный, перемещающий сборщик с поколениями. Не стек, не счетчики ссылок, не пулы, не регионы. Построить их вокруг такого базиса мешают головная боль и тормоза.
Хыхы, это вы уже похоже от незнания такое пишете... Вообще то скажем пул будет быстрее любого сборщика мусора. И использование его более чем простое и удобное. Просто он подходит далеко не для каждой задачи. Так что по сути сборщик мусора — это не скорость или удобство, а средство нормально программировать "не умея работать с памятью самим".
Re[93]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Так надо не намекать, а просто воспроизвести мой пример. При этом можно использовать любые "инструменты эффективной работы с памятью". Можете хоть счетчики ссылок использовать, хоть стек, хоть фрактальные пулы сепулькариев в подпространстве. Только вопроизведите мой пример на иммутабельных данных, с заметной нагрузкой на память, по всем условиям задачи, а не некий нерелевантный код, не использующий иммутабельные данные вообще — как в прошлый раз.
Да пожалуйста. Напишем вот такой простейший контейнер:
immutable struct IArray(int L, T){
immutable auto opSlice() {return data[0..size];}
immutable auto opBinary(string op)(in T v) if(op=="~") {auto d=cast(T*)(data); d[size]=v; return immutable IArray!(L, T)(data, size+1);}
static auto Make() {return immutable IArray!(L, T)(cast(immutable T*)(GC.malloc(L*T.sizeof, GC.BlkAttr.NO_MOVE)), 0);}
private T* data;
private int size;
invariant() {assert(data!=null, "Неинициализированный объект!"); assert(size<L, "Надо бы побольше пул!");}
};
Это у нас иммутабельные структуры, живущие на стеке и оптимизированные с помощью персистентной структуры, живущей на пуле.
И используем этот контейнер таким образом:
T Primes(int M, T=immutable IArray!(M, int))(T primes=T.Make()~2~3, int v=5)
{
if(v>=M) return primes;
return Primes!M(primes[].find!q{b%a==0||a^^2>b}(v).front()^^2>v?primes~v:primes, v+1);
}
Primes!(2^^24)[].length.writeln;
K>Вот тогда и посмотрим: K>1) как все это будет выглядеть. K>2) с какой скоростью будет работать.
Ну насчёт внешности я уже давно понял, что у нас вкусы не совпадают... А вот измерение скорости уже не позволяет особого субъективизма. Так вот, этот пример работает у меня где-то на 10% быстрее самого оптимального мутабельного варианта. Т.е. в разы быстрее вашего мутабельного и наверное на порядок быстрее вашего иммутабельного...
P.S. Как я уже говорил, правильное применение иммутабельных данных не должно приводить к каким-то компромисам. Оно должно как минимум не влиять на быстродействие, а как максимум приводить к ускорению...
Re[92]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А с чего вы взяли, что у map'а должно быть такое свойство (требование чистой функции на входе)? _>уж в случае map'ов, которые сейчас есть наверное в каждом языке и естественно нигде кроме хаскеля не в курсе ни про какую чистоту, навязывать своё видение как стандарт мягко говоря смешно.
В куче языков просто нет возможности проверить чистоту, поэтому там в документации пишут "используйте тут чистые ф-ии, а не то пеняйте на себя". Потому что по-хорошему map не должен гарантировать какой-то определенный порядок вычислений, а запуск эффектфул ф-й в неопределенном порядке — весьма ногопрострельноопасное дело. Дальше уже вопрос культуры: плюсовики привыкли иметь дело с опасными инструментами и сами думать обо всем, а в некоторых других языках предпочитают ограничить себя безопасными действиями, и тем избавиться от неприятных раздумий.
Re[92]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ага, на диаграмме пакетов — в точности соответствует...
Это точно? <merge> пакета Foo в Bar даст Bar.Foo, а я про другое.
_>Хы, ну если рисовать на бумажке, то возможно. А если пользоваться всяческими мощными инструментами, то обязанность жить в рамках стандарта UML появляется сама собой...
Очевидно, что обсуждаемая диаграмма не была нарисована на бумажке.
K>>А как вы рисуете, какие методы одного класса работают с методами другого класса? _>Вообще то это как раз всё указывается связями, включая даже имена переменных на них.
Ну а я о чем? Это и ответ на ваш вопрос.
_>Но я тут про другое говорил. Про связь кода со своими данными (инкапсуляцию)
Инкапсуляция — это не "связь кода со своими данными"
_>Ну да, если сделать вот так, то подобная диаграммка будет уже не плохо описывать архитектуру приложения. Правда при этом будет очень сложно объяснить незнакомому с ООП (представим себе такого фаната ФП) человеку, что же собственно мы обозначаем этими прямоугольниками... )))
Да чего там объяснять? В том и дело, что эти прямоугольники и связи обозначают достаточно общие вещи.
_>Кстати, я смотрю вы уже вроде как осознали, что единицей инкапсуляции всё же АлгТД являются, а не что-то ещё...
С чего вы взяли?
_>Ну если делать грубо говоря по модулю на тип,
Ну или некоторое число связанных друг с другом АлгТД (взаимно рекурсивных, например)
_>то действительно получится аналог стандартных вещей из ООП мира. Но я бы не сказал, что это приемлемое требование.
Почему?
K>>Да, конечно, можно закрывать только часть конструкторов и полей, не обязательно все или ничего.
_>Ну т.е. аналог struct S { int a; private: int b}; легко делается? )
module S (S(a)) where
data S = S { a::Int, b::Int }
_>А с чего вы взяли, что у map'а должно быть такое свойство (требование чистой функции на входе)?
С того, что это удобно. Можно код оптимизировать, например.
_>Я вообще не в первый раз замечаю за вами такую позицию, когда вы называете вашу (ну или "хаскельную") точку зрения общепринятым стандартом. Ну ладно, в случае понятия "чистоты" ещё можно дать "хаскельному" взгляду некие особые права, т.к. хаскель первопроходец в этой фиче. Но уж в случае map'ов, которые сейчас есть наверное в каждом языке и естественно нигде кроме хаскеля не в курсе ни про какую чистоту, навязывать своё видение как стандарт мягко говоря смешно.
Да причем тут хаскель или моя позиция? Это свойство функторов. F(f o g) = F(f) o F(g)
_>С чего это будет отказ от каких-то сценариев? Чистые функции мы же не перестаём принимать...
Чистые функции не самоцель, а средство для сохранения таких вот свойств. Отказаться придется от всех сценариев, где мы можем полагаться на такие свойства map при рассуждении о коде, рефакторинге, оптимизации.
K>>Я говорил не про это, а про то, что у A есть еще одно поле — ссылка на изменяемый класс, который для нескольких экземпляров A в списке может указывать на один и тот же экземпляр этого самого мутабельного класса.
_>Это же будет буквально тоже самое, что и в моём предыдущем примере. "А" тогда будет просто лишним контейнером. Показать кодом или сами осознаете? )
Показывайте кодом. Речь идет о тривиальной трансформации моего примера на F# просто переносом ссылки на "счетчик" из замыкания функций в каждый элемент списка. Вы, кстати, невнятно ответили на вопрос будет ли работать аналог моего F# кода для "чистых"" функций Ди, работающих с мутабельными данными.
K>>Ничего не понимаю. Что на внешность изначального кода влияет? Какой изначальный код вообще имеется в виду?
_>Ну у вас было два примера кода для той задачки.
Для той задачи у меня был один пример кода — иммутабельный по условию задачи. Второй пример кода — был приближенным аналогом вашего, который к задаче никакого отношения не имеет.
_>Мутабельный и иммутабельный. Причём внешне они заметно отличались.
Разумеется они отличались. Это разные алгоритмы с разными свойствами обрабатывающие разные структуры данных, реализованных с помощью разных библиотек.
_>А внутренне думаю ещё больше. Вы показали пример оптимизации циклов на маленьком кусочке с иммутабельными данными. А меня вот терзают сомнения на тему "а возможны ли эти же оптимизации для мутабельного аналога этого кода".
Это часть кода из второго примера, с мутабельными данными. Причем та часть кода которая всю работу и выполняет. И та часть которую вы оптимизировали вручную заменив конвейер на готовую функцию.
_>Угу, только мы должны в начале произвести работу по выяснению "нужна эта версия ещё или уже нет".
Наоборот, работу проводить надо если версии для эфемерных структур. Для персистентных все просто работает.
_>Хыхы, это вы уже похоже от незнания такое пишете... Вообще то скажем пул будет быстрее любого сборщика мусора.
Пул рассчитан на сценарий, в котором время жизни объектов варьируется мало. Они массово становятся ненужны и мы освобождаем весь пул. В типичном сценарии работы с иммутабельными данными у нас много короткоживущих объектов и какое-то число долгоживущих некоторым образом распределенных среди короткоживущих при размещении в куче. Т.е. при применении пулов у вас в каждом пуле до самого конца будет пара процентов живых объектов и ни один из пулов вы освободить не можете. ГЦ — это, грубо говоря, пул, из которого долгоживущие объекты эвакуируют, чтоб его можно было освободить. При использовании пулов эту эвакуацию придется добавлять в алгоритм (в обсуждаемом примере это несложно: долгоживущие объекты — это простые числа, но при более-менее нетривиальном использовании персистентных структур — это уже не так просто). Все проекты автоматического разделения объектов на долгоживущие и короткоживущие стат.анализом и размещения их по этому признаку в разных пулах (вроде MLKit) пока успехом не увенчались.
_>Просто он подходит далеко не для каждой задачи.
Вот именно. Для работы с иммутабельными структурами он не подходит.
_>Так что по сути сборщик мусора — это не скорость или удобство, а средство нормально программировать "не умея работать с памятью самим".
Это просто миф про зеленый виноград, который распространяют любители языков в которых нормального ГЦ нет и не будет. ГЦ это именно средство оптимизации для типичных сценариев выделения памяти в высокоуровневых языках, а так же само средство достижения этой самой высокоуровневости.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Да пожалуйста. Напишем вот такой простейший контейнер: _>
_>immutable struct IArray(int L, T){
_> immutable auto opSlice() {return data[0..size];}
_> immutable auto opBinary(string op)(in T v) if(op=="~") {auto d=cast(T*)(data); d[size]=v; return immutable IArray!(L, T)(data, size+1);}
_> static auto Make() {return immutable IArray!(L, T)(cast(immutable T*)(GC.malloc(L*T.sizeof, GC.BlkAttr.NO_MOVE)), 0);}
_> private T* data;
_> private int size;
_> invariant() {assert(data!=null, "Неинициализированный объект!"); assert(size<L, "Надо бы побольше пул!");}
_>};
_>
_>Это у нас иммутабельные структуры, живущие на стеке и оптимизированные с помощью персистентной структуры, живущей на пуле. _>И используем этот контейнер таким образом: _>
не имеет. Там строится длинный конвейер (у вас этого нет) между стадиями которого данные передаются в иммутабельных структурах данных (у вас этого нет) и, следовательно размещает много объектов в куче. Без оптимизации 276Гб, с оптимизацией 16Гб — это демонстрирует возможности компилятора уменьшать аллокации для такого кода. И делает это за 8 сек. — это показатель эффективности рантайма.
_>P.S. Как я уже говорил, правильное применение иммутабельных данных не должно приводить к каким-то компромисам. Оно должно как минимум не влиять на быстродействие, а как максимум приводить к ускорению...
Да, я уже понял, что "правильное использование иммутабельных данных" по вашему мнению сводится к их неприменению.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[93]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>В куче языков просто нет возможности проверить чистоту, поэтому там в документации пишут "используйте тут чистые ф-ии, а не то пеняйте на себя". Потому что по-хорошему map не должен гарантировать какой-то определенный порядок вычислений, а запуск эффектфул ф-й в неопределенном порядке — весьма ногопрострельноопасное дело. Дальше уже вопрос культуры: плюсовики привыкли иметь дело с опасными инструментами и сами думать обо всем, а в некоторых других языках предпочитают ограничить себя безопасными действиями, и тем избавиться от неприятных раздумий.
Ну скажем так: явно существует ненулевое множество полезных нечистых функций, применение которых map'ом полностью безопасно. Хотя в принципе в императивных языках (см. ниже) я вполне готов был бы допустить такое ограничение на map. )))
А вообще в императивных языках это всё выглядит надуманными проблемами — если мы передаём в map не готовую библиотечную функцию, а какую-то лямбду (чаще всего), то обычно гораздо удобнее использовать явный цикл (тем более, если есть foreach).
Re[93]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Очевидно, что обсуждаемая диаграмма не была нарисована на бумажке.
Ну так на ней и нарисованы по сути некие виртуальные объекты в стиле ООП, как вы и предлагали ниже...
_>>Вообще то это как раз всё указывается связями, включая даже имена переменных на них. K>Ну а я о чем? Это и ответ на ваш вопрос.
А там речь про другое была. Нет в uml стрелочки "инкапсулированы"... )
K>Да чего там объяснять? В том и дело, что эти прямоугольники и связи обозначают достаточно общие вещи.
Безусловно. И эти общие вещи напрямую отображаются в код ООП программы. А в случае Хаскеля нам потребуется специальный перевод.
Собственно если мы говорим про диаграмму классов, то хаскель тут не одинок — тому же ассемблеру будет ещё хуже на ней. Но зато на ассемблере мы можем использовать две остальные важнейшие диаграммы, а в хаскеле, из-за его декларативности, они ни к чему (ну это мы уже обсуждали).
_>>Кстати, я смотрю вы уже вроде как осознали, что единицей инкапсуляции всё же АлгТД являются, а не что-то ещё... K>С чего вы взяли?
Потому как предлагаете рисовать виртуальные объекты именно на базе АлгТД, а не на базе модулей. ) Ну в общем то это и очевидно (мысль о массиве модулей сразу всё проясняет), хотя вы почему-то долго упирались. )))
K>С того, что это удобно. Можно код оптимизировать, например.
Так я не понял зачем запрещать то? ) Т.е. вот есть универсальный map (работает с любыми функциями и ничего не гарантирует не чистым). Посылаем в него чистые функции — получаем нужную вам картину. Посылаем не чистые — значит знаем что делаем и просчитываем эффекты.
K>Да причем тут хаскель или моя позиция? Это свойство функторов. F(f o g) = F(f) o F(g)
Во-первых это только в вашем мире функция map и понятие функторов жёстко связаны. )))
А во-вторых это правило будет сохраняться в D даже и для не чистых функций.
K>Чистые функции не самоцель, а средство для сохранения таких вот свойств. Отказаться придется от всех сценариев, где мы можем полагаться на такие свойства map при рассуждении о коде, рефакторинге, оптимизации.
Ещё раз: это будут свойства не map'а, а того, что мы подаём ей в качестве аргументов. Реализация map'a и принимающая только чистые функции и принимающая любые абсолютно одинаковая.
K>Показывайте кодом. Речь идет о тривиальной трансформации моего примера на F# просто переносом ссылки на "счетчик" из замыкания функций в каждый элемент списка. Вы, кстати, невнятно ответили на вопрос будет ли работать аналог моего F# кода для "чистых"" функций Ди, работающих с мутабельными данными.
Не помню что за F# код (я кстати не особо в курсе этого языка, хотя говорят там почти точная копия ocaml'а). Но в любом случае в D свой map, который работает на базе диапазонов, так что в нём даже с не чистыми функциями всё отлично. )))
K>Это часть кода из второго примера, с мутабельными данными. Причем та часть кода которая всю работу и выполняет. И та часть которую вы оптимизировали вручную заменив конвейер на готовую функцию.
Нет, в вашей "части кода" присутствует "Vector Int" в роли primes. А в том мутабельном варианте было нечто жуткое вида "data Buffer m a = Buffer { len :: !Int, buf :: !(Vector.Unboxed.Mutable.MVector m a) }". Так вот меня терзают сомнения, справится ли компилятор с оптимизацией для такой штуки... )
K>Пул рассчитан на сценарий, в котором время жизни объектов варьируется мало. Они массово становятся ненужны и мы освобождаем весь пул. В типичном сценарии работы с иммутабельными данными у нас много короткоживущих объектов и какое-то число долгоживущих некоторым образом распределенных среди короткоживущих при размещении в куче. Т.е. при применении пулов у вас в каждом пуле до самого конца будет пара процентов живых объектов и ни один из пулов вы освободить не можете. ГЦ — это, грубо говоря, пул, из которого долгоживущие объекты эвакуируют, чтоб его можно было освободить. При использовании пулов эту эвакуацию придется добавлять в алгоритм (в обсуждаемом примере это несложно: долгоживущие объекты — это простые числа, но при более-менее нетривиальном использовании персистентных структур — это уже не так просто). Все проекты автоматического разделения объектов на долгоживущие и короткоживущие стат.анализом и размещения их по этому признаку в разных пулах (вроде MLKit) пока успехом не увенчались.
Не не не. Это вы говорите про использование чего-то вроде автоматического сборщика мусора, основанного на пулах, т.е. опять же каком-то универсальном решение. А я говорю о непосредственном использование пулов в конкретных задачах. Т.е. когда мы заранее точно знаем (а не пытаемся отслеживать во время работы) время жизни набора объектов (например в рамках выполнения какой-то задачи). В таком случае мы спокойно размещаем все объекты (по этой задаче) на нашем пуле и спокойно уничтожаем его при завершение задачи.
K>Вот именно. Для работы с иммутабельными структурами он не подходит.
Ну конечно. ))) А код в моём соседнем сообщение оказывается из иной реальности. )))
K>Это просто миф про зеленый виноград, который распространяют любители языков в которых нормального ГЦ нет и не будет. ГЦ это именно средство оптимизации для типичных сценариев выделения памяти в высокоуровневых языках, а так же само средство достижения этой самой высокоуровневости.
Пока что по всем тестам ваше "средство оптимизации" болтается среди отстающих по быстродействию... )))
Re[102]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты вероятно под ООП понимаешь исключительно вариант "инкапсуляция-наследование-полиморфизм как в С++". Между тем это всего лишь симуловское ООП, которое реализовано в С++. Скажем, Алан Кей, изобретатель ООП, c таким вариантом не согласен.
_>Ну понятно что во время исполнения можно любой вариант реализовать. Но для языков типа C++ и Хаскеля (при всей их разнице) это очевидно не вариант.
Вообще говоря нормальный вариант. Я тут рядом дал ссылку от Gaperton, посмотри, убедись.
Re[95]: Есть ли вещи, которые вы прницпиально не понимаете...
не имеет. Там строится длинный конвейер (у вас этого нет) между стадиями которого данные передаются в иммутабельных структурах данных (у вас этого нет) и, следовательно размещает много объектов в куче. Без оптимизации 276Гб, с оптимизацией 16Гб — это демонстрирует возможности компилятора уменьшать аллокации для такого кода. И делает это за 8 сек. — это показатель эффективности рантайма.
Ээээ вы в своём уме? ))) Напомню нашу дискуссию:
K: В D иммутабельные структуры использовать нельзя, т.к. сборщик мусора не оптимизирован под это.
A: В языках типа D есть много других эффективных способов работы с памятью, помимо сборщика мусора.
K: Все другие способы тормозные и неудобные.
A: Стек и пул будут побыстрее любого сборщика мусора и вполне удобны, в том числе и для иммутабельных данных.
K: Ну покажите реализацию того нашего примера с иммутабельными данными на базе стека, пулов или чего угодно.
A: Вот код. В нём иммутабельнные данные на стеке и пуле. Работает быстрее всех наших предыдущих примеров.
K: Этот код не подходит, т.к. не размещает много объектов в куче.
K>Да, я уже понял, что "правильное использование иммутабельных данных" по вашему мнению сводится к их неприменению.
Ну покажите мне в моём последнем примере хоть одну не иммутабельную структуру данных.
Re[103]: Есть ли вещи, которые вы прницпиально не понимаете...
Кстати, самое забавное, что прототипное ООП применяется обычно в динамических языках. А в них можно намутить классическое ООП на уровне библиотеки, как ты и говорил. А вот в "серьёзных" языках это всё не варианты. )))
Re[103]: Есть ли вещи, которые вы прницпиально не понимаете...
Прототипное ООП это громкий баззворд для простой идеи — поддержка ООП на уровне библиотеки. Сама поддержка ООП в языке сводится примерно к трем или четырем словами навроде constructor, prototype, instanceof
Отсюда ясно, что JS на уровне библиотеки поддерживает все мыслимые и не мыслимые варианты наследования.
_>Кстати, самое забавное, что прототипное ООП применяется обычно в динамических языках. А в них можно намутить классическое ООП на уровне библиотеки, как ты и говорил. А вот в "серьёзных" языках это всё не варианты. )))
В разных языках все по разному. Синтаксическая поддержка ООП есть только в ООП языках. Вот эрланг динамический язык, однако ООП как тебе хочется,в ём нет,даже прототипного. А ООП вообще вполне реализуется, на уровне библиотеки разумеется.
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А вообще в императивных языках это всё выглядит надуманными проблемами — если мы передаём в map не готовую библиотечную функцию, а какую-то лямбду (чаще всего), то обычно гораздо удобнее использовать явный цикл (тем более, если есть foreach).
Не-не-не, цикл это фу, с ним нельзя однострочники делать, где кроме map'а всякие другие штуки, да и самих map'ов может быть несколько. Циклы не композятся.
Re[94]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так на ней и нарисованы по сути некие виртуальные объекты в стиле ООП, как вы и предлагали ниже...
Нет, объекты в стиле ООП на ней не нарисованы. На ней нарисованы функции в стиле ФП и определенные на множествах этих функций другие функции. Ничего дальше от ООП чем это просто не бывает, но UML с отображением этого вполне справился. Отсюда вывод, что необходимости что-то в него добавлять для этой цели нет.
_>А там речь про другое была. Нет в uml стрелочки "инкапсулированы"... )
И что с того?
_>И эти общие вещи напрямую отображаются в код ООП программы. А в случае Хаскеля нам потребуется специальный перевод.
Не понятно, что вы подразумеваете под "отображается в код". Восстановить код ООП программы по диаграмме классов нельзя. Но можно некоторые трансформации этой диаграммы перевести в трансформации кода. Ну так и с ФП кодом такое возможно, хотя никто и не удосужился сделать.
_>Собственно если мы говорим про диаграмму классов, то хаскель тут не одинок — тому же ассемблеру будет ещё хуже на ней.
Ассемблеру будет плохо, потому что со средствами организации кода там плохо, и рисовать на диаграмме след. нечего. Если же какие-то нетривиальные средства организации кода есть — значит можно их на диаграмме показать. Хоть классы, хоть АлгТД, хоть сепулькарии.
_>Потому как предлагаете рисовать виртуальные объекты именно на базе АлгТД, а не на базе модулей. )
Причем тут инкапсуляция?
_>Ну в общем то это и очевидно (мысль о массиве модулей сразу всё проясняет), хотя вы почему-то долго упирались. )))
Точно также как и мысль о массиве атрибутов public. Никакой связи между средствами организации инкапсуляции и массивами нет.
_>Так я не понял зачем запрещать то? )
За тем же, зачем запрещать передачу массивов, строк и сепулькариев вместо функций. Я в курсе, что в некоторых языках это не запрещено и может даже какой-то результат получиться, но меня такой подход никогда не привлекал.
_>Т.е. вот есть универсальный map (работает с любыми функциями и ничего не гарантирует не чистым). Посылаем в него чистые функции — получаем нужную вам картину. Посылаем не чистые — значит знаем что делаем и просчитываем эффекты.
Как автор библиотеки может полагаться на то, что будет в его функции посылать пользователь его библиотеки, если не выразит это в системе типов?
_>Во-первых это только в вашем мире функция map и понятие функторов жёстко связаны. )))
Да, конечно, именно в моем мире. Он же и ваш мир. Мир вообще-то один. Если кто-то не знает, например, о форме земли, это же не значит, что он в каком-то другом мире живет, где земля плоская и на трех слонах стоит — просто он этого еще не знает.
_>А во-вторых это правило будет сохраняться в D даже и для не чистых функций.
Конечно не будет. Потому, что в одном случае все эффекты будут объеденены в две группы, а в другом — чередоваться.
_>Ещё раз: это будут свойства не map'а, а того, что мы подаём ей в качестве аргументов.
Это свойства map-а. Вы не заметили, разве, что в них map фигурирует? Разумеется, эти свойства выполняются для функций.
_>Не помню что за F# код (я кстати не особо в курсе этого языка, хотя говорят там почти точная копия ocaml'а).
> let f (i : int ref) a = a + !i;;
val f : i:int ref -> a:int -> int
> let g (i : int ref) b = i := b; b;;
val g : i:int ref -> b:int -> int
> let i = ref 0 in List.map (f i) << List.map (g i) <| [1..10];;
val it : int list = [11; 12; 13; 14; 15; 16; 17; 18; 19; 20]
> let i = ref 0 in List.map (f i << g i) <| [1..10];;
val it : int list = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]
_>Нет, в вашей "части кода" присутствует "Vector Int" в роли primes. А в том мутабельном варианте было нечто жуткое вида "data Buffer m a = Buffer { len :: !Int, buf :: !(Vector.Unboxed.Mutable.MVector m a) }". Так вот меня терзают сомнения, справится ли компилятор с оптимизацией для такой штуки... )
Ну правильно. Я MVector m Int "замораживаю" и получаю иммутабельный Vector Int.
_>Не не не. Это вы говорите про использование чего-то вроде автоматического сборщика мусора, основанного на пулах, т.е. опять же каком-то универсальном решение. А я говорю о непосредственном использование пулов в конкретных задачах. Т.е. когда мы заранее точно знаем (а не пытаемся отслеживать во время работы) время жизни набора объектов (например в рамках выполнения какой-то задачи). В таком случае мы спокойно размещаем все объекты (по этой задаче) на нашем пуле и спокойно уничтожаем его при завершение задачи.
Так в том и проблема, что в типичном коде, работающем с иммутабельными данными мы не знаем точно сколько какой объект проживет. Мы знаем только, что небольшая доля из размещенных в памяти объектов проживет долго, а остальные — долго не проживут. какие именно — зависит от входны данных и т.д. Очевидно, что пулы для этого не подходят.
В языке с поддержкой иммутабельности не то что не нужно выбирать что и где размещать и каким способом, там большинство размещений вроде бы следующих из кода — "виртуальные" — в действительности никогда не происходят.
_>Ну конечно. ))) А код в моём соседнем сообщение оказывается из иной реальности. )))
Код в вашем соседнем сообщении, как обычно, не имеет никакого отношения к работе с иммутабельными данными.
_>Пока что по всем тестам ваше "средство оптимизации" болтается среди отстающих по быстродействию... )))
Непонятно только, с чем оно при этом соревнуется, потому что решение моей задачи пока одно — мое, от вас его получить так и не удалось.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[96]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Напомню нашу дискуссию:
_>K: В D иммутабельные структуры использовать нельзя, т.к. сборщик мусора не оптимизирован под это. _>A: В языках типа D есть много других эффективных способов работы с памятью, помимо сборщика мусора. _>K: Все другие способы тормозные и неудобные. _>A: Стек и пул будут побыстрее любого сборщика мусора и вполне удобны, в том числе и для иммутабельных данных. _>K: Ну покажите реализацию того нашего примера с иммутабельными данными на базе стека, пулов или чего угодно. _>A: Вот код. В нём иммутабельнные данные на стеке и пуле. Работает быстрее всех наших предыдущих примеров. _>K: Этот код не подходит, т.к. не размещает много объектов в куче.
Нет, я же согласился с тем, что размещать объекты вы можете где угодно. Хоть на стеке (правда, если вы хотите нормальную поддержку иммутабельности в языке, вам и стек в куче скорее всего придется делать), хоть в куче, хоть в подпространстве. Главное чтоб были иммутабельные структуры, их было много и они где-то размещались.
K>>Да, я уже понял, что "правильное использование иммутабельных данных" по вашему мнению сводится к их неприменению. _>Ну покажите мне в моём последнем примере хоть одну не иммутабельную структуру данных.
Смотрим мой пример, видим:
[5,7..] производит иммутабельную структуру данных список
filter' isPrime принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
(3: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
(2: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
takeWhile' ((<= x) . (^2)) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
map (x `rem`) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
map (/= 0) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
foldr (&&) True принимает иммутабельную структуру данных список
takeWhile' (<= 2^24) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список
length принимает иммутабельную структуру данных список
Длинный конвейер, промежуточные данные — иммутабельные структуры данных. Все по условию задачи.
Смотрим ваш код — ничего этого нет. Конвейера нет, контейнер мутабельный (если вы такое за иммутабельность считаете — то и мой пример с буфером полностью "иммутабельный" тогда), рейндж, который из слайса [] получается — тоже мутабельный.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[95]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет, объекты в стиле ООП на ней не нарисованы. На ней нарисованы функции в стиле ФП и определенные на множествах этих функций другие функции. Ничего дальше от ООП чем это просто не бывает, но UML с отображением этого вполне справился. Отсюда вывод, что необходимости что-то в него добавлять для этой цели нет.
Ерунда какая. Большинство нормальных GUI библиотек работают через делегаты (в роли обработчиков сообщений) и при этом полностью базируются на ООП. Т.е. для современного ООП абсолютно привычно иметь у объектов поля, являющиеся указателями на функции, и соответственно методы, работающие с этими полями.
_>>А там речь про другое была. Нет в uml стрелочки "инкапсулированы"... ) K>И что с того?
Ну так из-за этого и приходится придумывать виртуальные сущности типа классов ООП, вместо того чтобы честно нарисовать типы (одним значком со своими свойствами, тут в принципе значок класса пойдёт), модули с функциями (другим значком, с другими свойствами) и как-то обозначить их связи (какой-то новой стрелочкой или как-то ещё). Вот такое было бы честной диаграммой для Хаскеля, но такое не нарисуешь с помощью современных инструментов uml. Соответственно в ход идёт рисование виртуальных сущностей в подражание ООП.
K>Не понятно, что вы подразумеваете под "отображается в код". Восстановить код ООП программы по диаграмме классов нельзя. Но можно некоторые трансформации этой диаграммы перевести в трансформации кода. Ну так и с ФП кодом такое возможно, хотя никто и не удосужился сделать.
Вообще то я нигде и не говорил, что для Хаскеля это невозможно в принципе. Очевидно же, что можно легко доработать UML и соответствующие инструменты. Весь вопрос как раз в том, что это ещё не сделано и я подозреваю и не будет сделано, судя по по популярности языка...
K>Как автор библиотеки может полагаться на то, что будет в его функции посылать пользователь его библиотеки, если не выразит это в системе типов?
Для начала поясните как код map'а может зависеть от того допускаем мы чистые функции в него или нет.
K>Да, конечно, именно в моем мире. Он же и ваш мир. Мир вообще-то один. Если кто-то не знает, например, о форме земли, это же не значит, что он в каком-то другом мире живет, где земля плоская и на трех слонах стоит — просто он этого еще не знает.
Угу, угу. ))) В Хаскеле само понятие функтора определено через функцию map (ну точнее fmap, но не суть). А в других языках map — это просто одна из функций библиотеки алгоритмов и всё! Да, кстати, а слово функтор в современном промышленном программирование чаще всего обозначает "функциональный объект", а не особый вид отображений из теории категорий. )))
_>>А во-вторых это правило будет сохраняться в D даже и для не чистых функций. K>Конечно не будет. Потому, что в одном случае все эффекты будут объеденены в две группы, а в другом — чередоваться.
Я же вроде как явно подсказал в предыдущем сообщение, что map в D работает на базе диапазонов. Т.е. в любом случае будет чередоваться. Более того, это касается не только map'а, но и большинства функций из библиотеки алгоритмов D (и соответственно они тоже не будут портить цепочку). Так что то равенство прямо в таком виде не получится испортить в D даже не чистыми функциями.
K>Это свойства map-а. Вы не заметили, разве, что в них map фигурирует? Разумеется, эти свойства выполняются для функций.
Ну как только вы покажете мне отличие кода map'а принимающего только чистые функции от кода map'a принимающего любые, то я тут же с вами соглашусь. )))
K>
>> let f (i : int ref) a = a + !i;;
K>val f : i:int ref -> a:int -> int
>> let g (i : int ref) b = i := b; b;;
K>val g : i:int ref -> b:int -> int
>> let i = ref 0 in List.map (f i) << List.map (g i) <| [1..10];;
K>val it : int list = [11; 12; 13; 14; 15; 16; 17; 18; 19; 20]
>> let i = ref 0 in List.map (f i << g i) <| [1..10];;
K>val it : int list = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]
K>
Ааа этот помню. ) Просто не заметил, что оно было на F#. Ну так я же уже говорил, что в этом примере в map передаются не чистые функции даже в терминологии D. Но самое забавное, что с такими не чистыми функциями map из D всё равно будет работать корректно:
Я же говорю, диапазоны!)))
K>Ну правильно. Я MVector m Int "замораживаю" и получаю иммутабельный Vector Int.
Нуу оптимизаторы — это хитрая вещь. Так я не понял, вы показали оптимизацию вырезав кусок из компиляции всего того примера или же в начале вырезали этот маленький кусок и скомпилировали отдельно? )
K>Так в том и проблема, что в типичном коде, работающем с иммутабельными данными мы не знаем точно сколько какой объект проживет. Мы знаем только, что небольшая доля из размещенных в памяти объектов проживет долго, а остальные — долго не проживут. какие именно — зависит от входны данных и т.д. Очевидно, что пулы для этого не подходят. K>В языке с поддержкой иммутабельности не то что не нужно выбирать что и где размещать и каким способом, там большинство размещений вроде бы следующих из кода — "виртуальные" — в действительности никогда не происходят.
Да, да, я уже понял что вы в принципе не способны выбирать инструменты в зависимости от условий конкретной задачи. Как все данные должные быть иммутабельные (хотя в данной конкретной задачи это может быть очевидно не удобно), так и с памятью можем работать только через сборщик мусора (хотя для данной конкретной задаче пул может подходить идеально и соответственно решение будет намного быстрее и проще). Только обобщённые автоматические решение, созданные кем-то за вас. И никакого тюнинга под конкретную задачу. Ну в принципе это тоже поход, для определённых аудиторий...
K>Код в вашем соседнем сообщении, как обычно, не имеет никакого отношения к работе с иммутабельными данными.
Тогда осталось показать не иммутабельные структуры там. )
K>Непонятно только, с чем оно при этом соревнуется, потому что решение моей задачи пока одно — мое, от вас его получить так и не удалось.
Да, я уже понял, что результатом того вашего примера было не вычисление нужного числа и даже не демонстрация работы с иммутабельными данными, а просто выделение побольше объёма в куче. Ну с такими тестами вы явно не по адресу. )))
Re[97]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет, я же согласился с тем, что размещать объекты вы можете где угодно. Хоть на стеке (правда, если вы хотите нормальную поддержку иммутабельности в языке, вам и стек в куче скорее всего придется делать), хоть в куче, хоть в подпространстве. Главное чтоб были иммутабельные структуры, их было много и они где-то размещались.
Структуры в моём примере полностью иммутабельные — за этим строго следит соответствующий модификатор. Ну а размещается их около миллиона (это я не про массив интов, а именно про иммутабельные структурки, хранящие ссылки) — вроде как не мало уже. А большего в данной задаче и не требуется.
K>Смотрим мой пример, видим: K>[5,7..] производит иммутабельную структуру данных список K>filter' isPrime принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>(3: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>(2: ) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>takeWhile' ((<= x) . (^2)) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>map (x `rem`) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>map (/= 0) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>foldr (&&) True принимает иммутабельную структуру данных список K>takeWhile' (<= 2^24) принимает иммутабельную структуру данных список и возвращает иммутабельную структуру данных список K>length принимает иммутабельную структуру данных список
Я не очень понял каким образом разбор вашего неоптимального кода может как-то подтвердить ваше утверждение о том, что в моём коде используются не иммутабельные структуры данных.
K>Смотрим ваш код — ничего этого нет. Конвейера нет,
А откуда взялось требование на конвейер? ) Вроде бы был разговор только про иммутабельные структуры и всё. Снова задним числом меняем условия? )))
K>контейнер мутабельный (если вы такое за иммутабельность считаете — то и мой пример с буфером полностью "иммутабельный" тогда),
Ну так покажите в какой точке контейнер меняется то... )
K>рейндж, который из слайса [] получается — тоже мутабельный.
Хы, при таком подходе и map в Хаскеле мутабельный, т.к. там счётчик бегает в итоге, а не рекурсия.
Re[96]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ерунда какая. Большинство нормальных GUI библиотек работают через делегаты (в роли обработчиков сообщений) и при этом полностью базируются на ООП. Т.е. для современного ООП абсолютно привычно иметь у объектов поля, являющиеся указателями на функции, и соответственно методы, работающие с этими полями.
Да какие поля. Там именно функции.
_>Ну так из-за этого и приходится придумывать виртуальные сущности типа классов ООП, вместо того чтобы честно нарисовать типы (одним значком со своими свойствами, тут в принципе значок класса пойдёт), модули с функциями (другим значком, с другими свойствами)
Зачем другим значком? Что вы можете предложить для этого принципиально отличное от "класса"? Это же просто разделенный на части список с заголовком. Для какой группировки сущностей его может не хватить? И механизм заведения своих "значков" уже готовый существует — стереотипы.
_>и как-то обозначить их связи (какой-то новой стрелочкой или как-то ещё).
И что это за отношение вы придумали, для которой готовой стрелочки нет? Даже если и придумаете и тут есть штатный механизм расширения — метки на этих отношениях.
_>Вообще то я нигде и не говорил, что для Хаскеля это невозможно в принципе. Очевидно же, что можно легко доработать UML и соответствующие инструменты. Весь вопрос как раз в том, что это ещё не сделано и я подозреваю и не будет сделано, судя по по популярности языка...
Для генерации кода инструменты дорабатывать, конечно, придется. А зачем дорабатывать UML? Вы можете хоть на одном примере проиллюстрировать проблему или на примере показать как может выглядеть это "дорабатывание"?
_>Для начала поясните как код map'а может зависеть от того допускаем мы чистые функции в него или нет.
Код мапа не будет, а код его использующий — тоже в этой же библиотеке — будет.
Вот те же обсуждаемые тут трансформации кода во много проходов в код в один проход. Как автор библиотеки может их описать, если они только для чистых функций корректны?
_>Угу, угу. ))) В Хаскеле само понятие функтора определено через функцию map (ну точнее fmap, но не суть).
Абракадабра какая-то.
_>А в других языках map — это просто одна из функций библиотеки алгоритмов и всё!
Проблемы "других языков". Что хорошего-то в том, что это "просто одна из функций"?
_>Да, кстати, а слово функтор в современном промышленном программирование чаще всего обозначает "функциональный объект", а не особый вид отображений из теории категорий. )))
Функтор еще много чего означает в разных контекстах, к примеру, параметризованный модуль в ML. Ну так что?
_>Я же вроде как явно подсказал в предыдущем сообщение, что map в D работает на базе диапазонов. Т.е. в любом случае будет чередоваться.
Ну так map можно не только для диапазонов написать, а для любого контейнера. В моем примере на ml не итераторы использованы, а списки.
_>Более того, это касается не только map'а, но и большинства функций из библиотеки алгоритмов D (и соответственно они тоже не будут портить цепочку). Так что то равенство прямо в таком виде не получится испортить в D даже не чистыми функциями.
Почему не получится-то?
Для этого достаточно вставить в конвейер "форсирование" или "кеширование" которое постоянно приходиться при работе с итераторами и аналогами то тут то там вставлять:
> let f a = printf "f"; a;;
val f : a:'a -> 'a
> let g a = printf "g"; a;;
val g : a:'a -> 'a
> Seq.map f << Seq.map g <| [1..5];;
gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
> Seq.map (f << g) <| [1..5];;
gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
(* пока все хорошо *)
> Seq.map f << Seq.toList << Seq.map g <| [1..5];;
gggggfffffval it : seq<int> = seq [1; 2; 3; 4; ...]
_>Нуу оптимизаторы — это хитрая вещь. Так я не понял, вы показали оптимизацию вырезав кусок из компиляции всего того примера или же в начале вырезали этот маленький кусок и скомпилировали отдельно? )
Сначала я вырезал и скомпилировал отдельно, но когда вы попросили промежуточный результат компиляции всего кода, я и его вам предоставил. Вот вам фрагмент из него:
Код
t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes
if t then ...
преобразуется в
letrec {
$s$wand_loop1
$s$wand_loop1 =
\ sc5 ->
case >=# sc5 tpl1 of _ {
False ->
let { __DEFAULT ~ wild12
<- indexIntArray# ipv3 (+# rb3 sc5)
} in
case <=# (*# wild12 wild12) sc4
of _ {
False -> True;
True ->
case wild12 of wild14 {
__DEFAULT ->
case remInt# sc4 wild14
of _ {
__DEFAULT ->
$s$wand_loop1
(+# sc5 1);
0 -> False
};
(-1) -> False;
0 ->
case divZeroError
of wild15 {
}
}
};
True -> True
}; } in
case $s$wand_loop1 0 of _ { ...
_>Да, да, я уже понял что вы в принципе не способны выбирать инструменты в зависимости от условий конкретной задачи.
Конечно способен: выбираю наиболее удобный инструмент из тех, что могу себе позволить.
_>Как все данные должные быть иммутабельные (хотя в данной конкретной задачи это может быть очевидно не удобно), так и с памятью можем работать только через сборщик мусора (хотя для данной конкретной задаче пул может подходить идеально и соответственно решение будет намного быстрее и проще). Только обобщённые автоматические решение, созданные кем-то за вас. И никакого тюнинга под конкретную задачу. Ну в принципе это тоже поход, для определённых аудиторий...
Обычный ход. Выставляем отсутствие нормального сборщика мусора как собственную доблесть.
_>Тогда осталось показать не иммутабельные структуры там. )
Так я и показал.
_>Да, я уже понял, что результатом того вашего примера было не вычисление нужного числа и даже не демонстрация работы с иммутабельными данными, а просто выделение побольше объёма в куче. Ну с такими тестами вы явно не по адресу.
Это прямо в описании задачи и сказано. Я рад, конечно, что после n повторений на разные лады одного и того же вы наконец поняли.
_> Ну с такими тестами вы явно не по адресу.
Конечно не по адресу. Я с самого начала и об этом говорил: нормальной поддержки иммутабельности в D нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[98]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я не очень понял каким образом разбор вашего неоптимального кода может как-то подтвердить ваше утверждение о том, что в моём коде используются не иммутабельные структуры данных.
Разбор моего кода, неоптимального по условию задачи, иллюстрирует то, насколько далеко вы отошли от условия задачи. Про миллион иммутабельных пар индекс-указатель на мутабельный массив вообще вообще отличная шутка (напоминаю, что мой код при выключенной оптимизации компилятора размещает сотни гигабайт, а не десятки мегабайт).
_>А откуда взялось требование на конвейер? ) Вроде бы был разговор только про иммутабельные структуры и всё. Снова задним числом меняем условия? )))
Читаем условия:
Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет.
Прочитав эти условия вы разродились программой, которая создает как можно меньше промежуточных данных и данные эти — мутабельные.
_>Ну так покажите в какой точке контейнер меняется то... )
Там где ~ используется.
_>Хы, при таком подходе и map в Хаскеле мутабельный, т.к. там счётчик бегает в итоге, а не рекурсия.
Конечно нет. Мап описан на хаскеле как функция работающая с иммутабельной структурой данных. Правила перезаписи для map и прочих функций не переписывают их в функции, которые с мутабельными данными работают.
В случае D это не так. Функции работающие с рейнжем описаны как функции, работающие с мутабельными данными, соотвествующая рейнджу структура данных — мутабельная.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[97]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Зачем другим значком? Что вы можете предложить для этого принципиально отличное от "класса"? Это же просто разделенный на части список с заголовком. Для какой группировки сущностей его может не хватить? И механизм заведения своих "значков" уже готовый существует — стереотипы.
Смысл в том, что значок класса у вас уже занят на другую сущность. Причём с принципиально отличными свойствами. Более того, модули было логично рисовать с визуальным размещением типов и функций внутри. Даже не знаю, что тут лучше предложить. Возможно большой такой прямоугольник, в котором одна часть отделена для списка функций, а в другой свободно располагаются типы (в виде значков классов).
Что касается стереотипов в ООП, то они не меняют базовые свойства сущности "класс", а только добавляют какие-то уточнения.
K>И что это за отношение вы придумали, для которой готовой стрелочки нет? Даже если и придумаете и тут есть штатный механизм расширения — метки на этих отношениях.
Стрелочка будет нужна в случае честного раздельного рисования модулей (и соответственно списка функций в них) и типов, чтобы указать инкапсуляцию. Ну или вот можно рисовать виртуальные ООП объекты — тогда действительного никаких лишних связей не надо. )))
K>Для генерации кода инструменты дорабатывать, конечно, придется. А зачем дорабатывать UML? Вы можете хоть на одном примере проиллюстрировать проблему или на примере показать как может выглядеть это "дорабатывание"?
Ещё раз: или вы рисуете виртуальное ООП (никаких модулей; типы значками классов; и функции, работающие с этими типами, внутри этих значков классов) или же вам надо разрабатывать дополнительные значки, связи и т.п.
Кстати, генерация кода по диаграммам — это не особо популярная функция. А вот генерация диаграмм по коду используется очень часто.
K>Код мапа не будет, а код его использующий — тоже в этой же библиотеке — будет. K>Вот те же обсуждаемые тут трансформации кода во много проходов в код в один проход. Как автор библиотеки может их описать, если они только для чистых функций корректны?
Ну так код, использующий map, знает какие параметры он в него передаёт. Если передаёт чистые функции, то может какие-то трансформации делать и т.п. Если функции чужие, то может опять же сделать ограничение по типу, но в параметрах вызова себя, а не map'a.
_>>А в других языках map — это просто одна из функций библиотеки алгоритмов и всё! K>Проблемы "других языков". Что хорошего-то в том, что это "просто одна из функций"?
Тут дело не в том хорошо это или плохо. Главное, что именно это является объективной реальность для большинства программистов на планете. А вовсе не ваши взгляды.
K>Ну так map можно не только для диапазонов написать, а для любого контейнера. В моем примере на ml не итераторы использованы, а списки.
Дело не в том что передаём в map, а в том, что возвращаем из него. В D map всегда возвращает диапазон.
K>Почему не получится-то? K>Для этого достаточно вставить в конвейер "форсирование" или "кеширование" которое постоянно приходиться при работе с итераторами и аналогами то тут то там вставлять: K>
>> let f a = printf "f"; a;;
K>val f : a:'a -> 'a
>> let g a = printf "g"; a;;
K>val g : a:'a -> 'a
>> Seq.map f << Seq.map g <| [1..5];;
K>gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
>> Seq.map (f << g) <| [1..5];;
K>gfgfgfgfgfval it : seq<int> = seq [1; 2; 3; 4; ...]
K>(* пока все хорошо *)
>> Seq.map f << Seq.toList << Seq.map g <| [1..5];;
K>gggggfffffval it : seq<int> = seq [1; 2; 3; 4; ...]
K>
Да, всё правильно. Только возвращаясь к нашему равенству... Вы здесь его переделали уже в вид map f.g = map f . h . map f, что собственно никто и не гарантировал даже для чистых функций. )
K>Сначала я вырезал и скомпилировал отдельно, но когда вы попросили промежуточный результат компиляции всего кода, я и его вам предоставил. Вот вам фрагмент из него: K>...
Спасибо, понятно. Тем более удивительно, что этот ваш пример целиком отстаёт в разы от вариантов на D.
K>Конечно способен: выбираю наиболее удобный инструмент из тех, что могу себе позволить.
Интересная формулировка. т.е. вот для того примера с обработкой видео вы бы лично при проектирование архитектуры приложения выбрали бы мутабельный буфер? )
K>Обычный ход. Выставляем отсутствие нормального сборщика мусора как собственную доблесть.
Бррр, я же вам говорю, что даже самый самый идеальный сборщик мусора не может быть быстрее пула, просто по построению. А про стековые переменные я вообще молчу...
K>Конечно не по адресу. Я с самого начала и об этом говорил: нормальной поддержки иммутабельности в D нет.
Если вы про готовые библиотечные классы контейнеры и т.п., оптимизированные под такие игры, то в стандартной библиотеке их действительно нет. Однако, как вы видели по моему примеру, такие вещи легко пишутся в несколько строк. Вся необходимая поддержка для этого в языке имеется.
Re[99]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Разбор моего кода, неоптимального по условию задачи, иллюстрирует то, насколько далеко вы отошли от условия задачи. Про миллион иммутабельных пар индекс-указатель на мутабельный массив вообще вообще отличная шутка (напоминаю, что мой код при выключенной оптимизации компилятора размещает сотни гигабайт, а не десятки мегабайт).
Ну так это и есть результат оптимизации с помощью персистентной структуры. Вы же сами про них так любили говорить... ))) А если взять мой код, но без оптимизации, то там будет соответственно выделяться около гигабайта.
K>Читаем условия: K>
K>Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет.
K>Прочитав эти условия вы разродились программой, которая создает как можно меньше промежуточных данных и данные эти — мутабельные.
При подобном условие абсолютно невозможно проводить сравнительное тестирование быстродействия. Реально протестировать такие варианты:
1. Код выдающий конкретный результат (например то самое число простых чисел) и использующий только иммутабельные данные. Способы оптимизации не ограничены. Как раз такое я и показал.
2. Код выделяющий N байт (виртуальных, до оптимизации) порциями по M (тут даже сама вычислительная задача не важна). Если есть желание потестировать такое, то я тоже не против.
Ваша же формулировка "создания как можно большего числа промежуточных значений" абсолютно не совместима с тестированием на быстродействие. Потому как можно всегда добавить ещё немного промежуточных — и как такое тестировать? )
_>>Ну так покажите в какой точке контейнер меняется то... ) K>Там где ~ используется.
У нас используется контейнер IArray, который абстрагирует в себе массив int'ов размером в size (поле в контейнере). Он абсолютно иммутабельный. Мы не можем поменять в нём ни значения в массиве, ни размер массива.
При операции a ~ v, создаётся новый иммутабельный объект типа IArray, размером a.size+1, заполненный данными из a, плюс v. Изначальный контейнер не меняется ни в чём.
Если же вас почему-то смущает, что области хранения данных у старого и нового IArray частично пересекаются (в следствие частичного совпадения данных в них), то не вижу в этом ничего страшного, т.к. это же у нас иммутабельные контейнеры. Более того, это как раз и есть разновидность той самой оптимизации по иммутабельности, про которую вы всё время говорили.
K>Конечно нет. Мап описан на хаскеле как функция работающая с иммутабельной структурой данных. Правила перезаписи для map и прочих функций не переписывают их в функции, которые с мутабельными данными работают. K>В случае D это не так. Функции работающие с рейнжем описаны как функции, работающие с мутабельными данными, соотвествующая рейнджу структура данных — мутабельная.
Вообще то range — это просто один бегающий индекс, точно такой же как и внутри map'a. Но если это всё вас так нервирует, то для меня не проблема написать свою функцию вместо find'а, работающую без диапазонов:
bool WhileAny(string P1, string P2, T)(immutable T[] a, T v, int i=0)
{
if(i>=a.length||binaryFun!P1(a[i], v)) return false;
if(binaryFun!P2(a[i], v)) return true;
return WhileAny!(P1, P2)(a, v, i+1);
}
И я даже на всякий случай записал её в виде рекурсии, а не через foreach, а то же в нём тоже типа бегает мутабельный (о ужас!) индекс.
Имея такую библиотечную функцию, наш код для вычисления простых чисел станет выглядеть так:
T Primes(int M, T=immutable IArray!(M, int))(T primes=T.Make()~2~3, int v=5)
{
if(v>=M) return primes;
return Primes!M(!primes[].WhileAny!(q{a^^2>b}, q{b%a==0})(v)?primes~v:primes, v+1);
}
И кстати от такой переделки он стал работать ещё где-то на 3% быстрее... )))
Re[98]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Смысл в том, что значок класса у вас уже занят на другую сущность.
Конечно нет. Потому, что этим знаком обозначаются также интерфейсы, статические классы и как вы вовремя напомнили — делегаты.
_>Более того, модули было логично рисовать с визуальным размещением типов и функций внутри. Даже не знаю, что тут лучше предложить. Возможно большой такой прямоугольник, в котором одна часть отделена для списка функций, а в другой свободно располагаются типы (в виде значков классов).
Именно так визуализирует вложенные классы автоматический построитель диаграмм, который в составе Visual Studio.
_>Что касается стереотипов в ООП, то они не меняют базовые свойства сущности "класс", а только добавляют какие-то уточнения.
Странно, стереотипы — рекомендованный инструмент для добавления вышеупомянутых интерфейсов, стат.классов и делегатов.
_>Стрелочка будет нужна в случае честного раздельного рисования модулей (и соответственно списка функций в них) и типов, чтобы указать инкапсуляцию.
Можно обойтись пометкой, что отношение обозначает вложение.
_>Ещё раз: или вы рисуете виртуальное ООП (никаких модулей; типы значками классов; и функции, работающие с этими типами, внутри этих значков классов) или же вам надо разрабатывать дополнительные значки, связи и т.п.
Ложная альтернатива. Выше описано как все можно сделать ничего в UML не добавляя.
_>Ну так код, использующий map, знает какие параметры он в него передаёт.
Нет, если он сам их извне получает. Что он конечно и делает, если это обобщенная библиотека функций.
_>Тут дело не в том хорошо это или плохо. Главное, что именно это является объективной реальность для большинства программистов на планете. А вовсе не ваши взгляды.
То, что сложение плавучки неассоциативно — тоже объективная реальность, проявляющаяся в головной боли и всяких трюках. Так и с map — в большинстве языков он такой же ущербный с аналогичными последствиями, ну так это только повод сделать мап лучше. Что в некоторых языках и сделано.
_>Дело не в том что передаём в map, а в том, что возвращаем из него. В D map всегда возвращает диапазон.
"Мап", который возвращает не тот контейнер, который в него передают — тем более никакого отношения к мапу не имеет.
_>Да, всё правильно. Только возвращаясь к нашему равенству... Вы здесь его переделали уже в вид map f.g = map f . h . map f, что собственно никто и не гарантировал даже для чистых функций. )
Разумеется, это выполняется если h — это id. Всякие форсирующие-кеширующие ф-и в конвейерах так и должны себя вести, но для нас это недоступно, если нет контроля над эффектами. А значит ф-я, которая не должна менять результат — будет его менять, причем от самой функции это никак не зависит.
Это просто пример проблемы, которая возникает, если полагаться на какой-то неявный порядок вычислений, который на самом деле никто не гарантирует.
_>Спасибо, понятно. Тем более удивительно, что этот ваш пример целиком отстаёт в разы от вариантов на D.
Непонятно, откуда вы взяли это отставание "в разы".
Я сравнил производительность кода для нескольких примеров на Win 8.1 i7-3770. Чтоб снизить влияние бекенда я компилировал все компиляторами с одним и тем же бекендом LLVM 3.3 x86, это, соответственно GHC 7.6.3 (-O2) и LDC2 0.12.1 (-O3). Вот что у меня получилось.
Вариант на D без конвейера:
отрабатывает в среднем за 1.86 сек. Пусть это будет 1.
Мутабельный вариант на хаскеле (аналог которого на Ди вы почему-то считаете иммутабельным)
import Control.Applicative
import Control.Monad
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M
data Buffer m a = Buffer { len :: !Int, buf :: !(M.MVector m a) }
over f (Buffer c b) = f . U.take c <$> U.unsafeFreeze b
(Buffer c b) <| a | M.length b > c = add b | otherwise = add =<< M.grow b (c*3) where
add nb = Buffer (c+1) nb <$ M.write nb c a
buffer l = flip (foldM (<|)) l . Buffer 0 =<< M.new 1000
main = print . len =<< flip (U.foldM step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24)
=<< buffer [2, 3::Int] where
step primes x = do
t <- over (U.all ((/= 0) . rem x) . U.takeWhile ((<= x) . (^2))) primes
if t then primes <| x else pure primes
работает за 2.03 сек. Что будет 1.09. Менее чем на 10% медленнее, никаких разов. Обратите внимание, что конвейер есть и успешно оптимизирован.
Дальше я замерил скорость кода, похожего на мой первый пример, в котором я дал компилятору проделать больше работы, использовав библиотеку stream-fusion, она представляет функции работы со стандартными списками с другой техникой оптимизации, не той, что в стандартной библиотеке:
Эта версия отработала за 2.40 сек. или 1.29 — менее чем 30% замедление относительно Ди-версии, при этом длинный конвейер, все иммутабельное, ленивое и т.д. Это хорошая демонстрация оптимизаций компилятора, но эта версия создает гораздо меньшую нагрузку на память (вместо десятков Гб вделяет сотни Мб) и плохо демонстрирует поддержку рантайма.
Дальше идет версия на Ди с конвейером:
Выполнилась за 3.78 сек. или 2.03. Т.е. добавление одной стадии в конвейер замедлило код в 2 раза. Печально. Что же будет при конвейере той же длины, что и на хаскеле?
Дальше идет первый пример на хаскеле, который создает нагрузку на менеджер памяти:
primes = 2:3:filter' isPrime [5,7..] :: [Int]
isPrime x = all' (/= 0) . map (x `rem`) . takeWhile' ((<= x) . (^2)) $ primes
main = print . length . takeWhile' (<= 2^24) $ primes
step p res x | p x = (x:) | otherwise = res
takeWhile' p = foldr (step p $ const []) []
all' f = foldr (&&) True . map f
filter' p = foldr (step p id) []
Это 6.99 сек. или 3.76. Тормозной, но для того и написан.
_>Интересная формулировка. т.е. вот для того примера с обработкой видео вы бы лично при проектирование архитектуры приложения выбрали бы мутабельный буфер? )
Да, конечно.
_>Бррр, я же вам говорю, что даже самый самый идеальный сборщик мусора не может быть быстрее пула, просто по построению.
Может, конечно, за счет фрагментации/худшей локальности у пула, например.
_>А про стековые переменные я вообще молчу...
Стек покрывает всякие маргинальные сценарии выделения памяти, которые в высокоуровневом коде все равно почти не пригодятся.
_>Если вы про готовые библиотечные классы контейнеры и т.п., оптимизированные под такие игры, то в стандартной библиотеке их действительно нет. Однако, как вы видели по моему примеру, такие вещи легко пишутся в несколько строк. Вся необходимая поддержка для этого в языке имеется.
В вашем коде используется явное изменение на месте, так что к обсуждаемой проблеме он не имеет никакого отношения.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так это и есть результат оптимизации с помощью персистентной структуры.
Что еще за оптимизация с помощью персистентной структуры?
_>Вы же сами про них так любили говорить... ))) А если взять мой код, но без оптимизации, то там будет соответственно выделяться около гигабайта.
Что все равно очень мало.
_>При подобном условие абсолютно невозможно проводить сравнительное тестирование быстродействия.
Естественно возможно. И даже несложно. Определяете односвязный иммутабельный список, пишете нужные функции, выстраиваете конвейер из того же числа стадий, измеряете. Предлагаю вам именно этим и заняться.
_>Ваша же формулировка "создания как можно большего числа промежуточных значений" абсолютно не совместима с тестированием на быстродействие. Потому как можно всегда добавить ещё немного промежуточных — и как такое тестировать? )
Тестировать так, чтоб этих промежуточных данных было примерно одинаковое кол-во в разных примерах.
__>У нас используется контейнер IArray, который абстрагирует в себе массив int'ов размером в size (поле в контейнере). Он абсолютно иммутабельный. Мы не можем поменять в нём ни значения в массиве, ни размер массива. _>При операции a ~ v, создаётся новый иммутабельный объект типа IArray, размером a.size+1, заполненный данными из a, плюс v. Изначальный контейнер не меняется ни в чём.
Но в его реализации на Ди используется изменение массива на месте. Мой буфер из мутабельного примера аналогично реализован.
_>Если же вас почему-то смущает, что области хранения данных у старого и нового IArray частично пересекаются (в следствие частичного совпадения данных в них), то не вижу в этом ничего страшного, т.к. это же у нас иммутабельные контейнеры.
Мне не нравится явное изменение в коде.
_>Более того, это как раз и есть разновидность той самой оптимизации по иммутабельности, про которую вы всё время говорили.
Только она ручная, а не автоматическая — какое это отношение к поддержке в языке имеет?
_>Вообще то range — это просто один бегающий индекс, точно такой же как и внутри map'a. Но если это всё вас так нервирует, то для меня не проблема написать свою функцию вместо find'а, работающую без диапазонов:
Ну да, конечно. Что может быть дальше от задания "иммутабельные промежуточные данные", чем "мутабельные промежуточные данные"? Правильно: отсутствие промежуточных данных.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[99]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Конечно нет. Потому, что этим знаком обозначаются также интерфейсы, статические классы и как вы вовремя напомнили — делегаты.
Угу, которые например в C++ вообще все являются одной языковой сущностью. ))) А в других (ООП) языках отличаются по мелочам, но при этом обладают однозначным набором общих свойства.
K>Именно так визуализирует вложенные классы автоматический построитель диаграмм, который в составе Visual Studio.
Хы, а я это с ходу придумал. ) Только при таком раскладе в Хаскеле (в отличие от ООП языков со вложенными классами) будет теряться отношение инкапсуляции между типами и их функциями. Надо или новый вид связи или ещё что-то...
Да, так а что у нас имеется на тему "автоматического построителя диаграмм" для Хаскеля? ) Это я в очередной раз подчёркиваю суть проблемы — не какие-то теоретические трудности, а текущее состояние на рынке.
_>>Ну так код, использующий map, знает какие параметры он в него передаёт. K>Нет, если он сам их извне получает. Что он конечно и делает, если это обобщенная библиотека функций.
Ну так если получает извне, то именно в этой точке и можно ставить ограничение по типу. А map тут вообще ни при чём.
K>То, что сложение плавучки неассоциативно — тоже объективная реальность, проявляющаяся в головной боли и всяких трюках. Так и с map — в большинстве языков он такой же ущербный с аналогичными последствиями, ну так это только повод сделать мап лучше. Что в некоторых языках и сделано.
Вы опять же навязываете своё видение. ) Вы не подумали, что кому-то именно другая реализация может казаться идеальной, а ваша ущербной? )
K>"Мап", который возвращает не тот контейнер, который в него передают — тем более никакого отношения к мапу не имеет.
Ну а вот в D оно именно такое и при этом носит имя map. Правда это всё равно просто функция из библиотеки, а не что-то большее....
K>Непонятно, откуда вы взяли это отставание "в разы". K>Я сравнил производительность кода для нескольких примеров на Win 8.1 i7-3770. Чтоб снизить влияние бекенда я компилировал все компиляторами с одним и тем же бекендом LLVM 3.3 x86, это, соответственно GHC 7.6.3 (-O2) и LDC2 0.12.1 (-O3). Вот что у меня получилось. K>...
Для проверки правильности ваших результатов осталось (ну точнее в идеале было бы мне снова поставить себе хаскель, но что-то лень из-за форумного спора) сделать следующее:
1. Замерить производительность моего полностью иммутабельного примера из соседней ветки. Напоминаю его код:
immutable struct IArray(int L, T){
immutable auto opSlice() {return data[0..size];}
immutable auto opBinary(string op)(in T v) if(op=="~")
{
auto d=cast(T*)(data);
d[size]=v;
return immutable IArray!(L, T)(data, size+1);
}
static auto Make()
{
return immutable IArray!(L, T)(cast(immutable T*)(GC.malloc(L*T.sizeof, GC.BlkAttr.NO_MOVE)), 0);
}
private T* data;
private int size;
invariant() {assert(data!=null, "Неинициализированный объект!"); assert(size<L, "Надо бы побольше пул!");}
};
bool WhileAny(string F1, string F2, T)(immutable T[] a, T v, int i=0)
{
if(i>=a.length||binaryFun!F1(a[i], v)) return false;
if(binaryFun!F2(a[i], v)) return true;
return WhileAny!(F1, F2)(a, v, i+1);
}
T Primes(int M, T=immutable IArray!(M, int))(T primes=T.Make()~2~3, int v=5)
{
if(v>=M) return primes;
return Primes!M(!primes[].WhileAny!(q{a^^2>b}, q{b%a==0})(v)?primes~v:primes, v+1);
}
void main()
{
Primes!(2^^24)[].length.writeln;
}
2. Замерить производительность этого http://files.rsdn.ru/98162/Test_D.exe бинарника. Это скопилированный обычным классическим dmd код выше. На случай если вы там что-то напутали с опциями компилятора...
_>>Интересная формулировка. т.е. вот для того примера с обработкой видео вы бы лично при проектирование архитектуры приложения выбрали бы мутабельный буфер? ) K>Да, конечно.
Тогда всё же не до конца понимаю вашу точку зрения... Быть может вы считаете, что подобный пример является каким-то исключением, а не характерным кодом?
K>Стек покрывает всякие маргинальные сценарии выделения памяти, которые в высокоуровневом коде все равно почти не пригодятся.
В сочетание с техникой RAII это даёт ооочень мощный инструмент...
K>В вашем коде используется явное изменение на месте, так что к обсуждаемой проблеме он не имеет никакого отношения.
Изменений сушествующих данных там нет никаких. Какое дело кому-то до модификации неразмеченной (выделенный пул используется у меня именно как голая память) области?
Кстати, а если бы выделяемые на пуле массивы не пересекались в памяти, а выделялись бы каждый раз целиком рядышком (т.е. как делает обычный ~)... Это что-то изменило бы в вашем видение? ) Замечу, что код при этом не изменился бы ни на букву (была бы та же самая модификация), просто в конструктор передавали бы другой int...
Re[101]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Естественно возможно. И даже несложно. Определяете односвязный иммутабельный список, пишете нужные функции, выстраиваете конвейер из того же числа стадий, измеряете. Предлагаю вам именно этим и заняться.
Во-первых тогда надо однозначно договориться о количестве передаваемых данных и о количестве шагов конвейера. Т.е. в конкретных цифрах.
А во-вторых стандартных средства организации конвейеров в D работают через диапазоны, которые вы типа отказываетесь считать иммутабельными структурами (когда они поверх иммутабельного контейнера) из-за некой глупой придирки. А переписывать все циклы в рекурсии (чтобы компилятор сделал обратное потом) во всей библиотеке мне как-то лень...
K>Но в его реализации на Ди используется изменение массива на месте. Мой буфер из мутабельного примера аналогично реализован.
Массив с данными не изменяется вообще. Меняется некая неразмеченная память снаружи от него. По сути происходит выделение памяти для нового контейнера, но по хитрому. Т.е. это просто особая разновидность new.
K>Только она ручная, а не автоматическая — какое это отношение к поддержке в языке имеет?
Вот, тут вы правы. Но главное что язык позволяет легко делать подобные вещи. Как вы видите, всего несколько строк и гораздо более эффективный код, чем все ваши варианты.
Re[100]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Угу, которые например в C++ вообще все являются одной языковой сущностью.
Непонятно, к чему это упомянуто? Хотите сказать, что для использования с почти всеми остальными ОО-языками, где это не так, UML непригоден? Вот так сюрприз!
_>А в других (ООП) языках отличаются по мелочам, но при этом обладают однозначным набором общих свойства.
Много ли общих свойств у стат.класса и делегата? И тот и другой обозначаются одним значком с разными стереотипами.
_>Хы, а я это с ходу придумал.
Это просто показатель того как вы читаете мои ответы. Я такой вариант сразу и предложил.
_>Только при таком раскладе в Хаскеле (в отличие от ООП языков со вложенными классами) будет теряться отношение инкапсуляции между типами и их функциями. Надо или новый вид связи или ещё что-то...
Отношения инкапсуляции между типами и определенными на них функциями не существует. На практике диаграмма для хаскеля будет отличатся от диаграммы для Явы тем, что Разделение на блоки по видимостям будет только у знаков класса первого уровня. У всех вложенных разделения членов по видимости не будет.
_>Да, так а что у нас имеется на тему "автоматического построителя диаграмм" для Хаскеля? )
Как я уже говорил, ничего о таком построителе не знаю, так как никогда не возникало желания построить UML по хаскельному коду. Подозреваю, что таких построителей нет, так как запрос на такой инструментарий среди хаскелистов судя по всему отсутствует.
Технически не вижу проблемы с генерированием, какого-то входного формата для UML-инструментария из хаскельного кода.
_>Это я в очередной раз подчёркиваю суть проблемы — не какие-то теоретические трудности, а текущее состояние на рынке.
Мы вроде бы как раз теоретические трудности и обсуждали. Точнее существующую, якобы, необходимость расширить UML нестандартными средствами.
_>Ну так если получает извне, то именно в этой точке и можно ставить ограничение по типу. А map тут вообще ни при чём.
Т.е. полезность такой проверки вы все-таки не отрицаете, главное чтоб не для map-а?
_>Вы опять же навязываете своё видение. ) Вы не подумали, что кому-то именно другая реализация может казаться идеальной, а ваша ущербной? )
Я свое виденье просто декларирую, обосновываю, иллюстрирую примерами — но не навязываю. Кому-то может казаться все что угодно и кому-то даже обязательно покажется — но это проблемы этого кого-то (пока он со мной не работает).
_>Ну а вот в D оно именно такое и при этом носит имя map. Правда это всё равно просто функция из библиотеки, а не что-то большее....
Явление известное. Взять что-то, назвать "лямбда", "мап" или, еще лучше, "все_есть", а потом заявлять на форумах: "вот вы говорите, что у нас ничего нет, а у нас "все_есть" — вот она, эта функция".
_>Для проверки правильности ваших результатов осталось (ну точнее в идеале было бы мне снова поставить себе хаскель, но что-то лень из-за форумного спора) сделать следующее:
_>1. Замерить производительность моего полностью иммутабельного примера из соседней ветки. Напоминаю его код:
Замерить производительность "полностью иммутабельного" примера не получится до тех пор, пока его кто-нибудь не напишет. И на вас тут, как я понял, надеяться не приходится. Замерить производительность полностью мутабельного примера, наверное, можно но тут возникают сложности. Во-первых, код неполный, нету импортов, которые я все-таки восстановил, но и после этого скомпилированный LDC2 экзешник падает сразу после запуска. Может, оптимизация хвостовой рекурсии не работает?
_>Тогда всё же не до конца понимаю вашу точку зрения... Быть может вы считаете, что подобный пример является каким-то исключением, а не характерным кодом?
Моя точка зрения простая: я за удобный и развитый инструментарий. Я хочу использовать то, что удобнее в данном конкретном случае, а не выдумывать всякие нелепые обоснования ненужности колбасы, которой нет.
В данной конкретной дискуссии я просто выступаю за следование теме, которая заявлена как "поддержка иммутабельности". Не "ненужность иммутабельности". Не "война — это мир, иммутабельность — это мутабельность". Вам же подтвердить заявленную поддержку иммутабельности нечем, и вообще сказать по теме разговора нечего, а потому вы всеми средствами отклоняетесь от темы, набрасываете нерелевантные примеры, а меня пытаетесь выставить слепым "фанатиком иммутабельности" именно потому, что я от темы отклоняюсь неохотно.
_>В сочетание с техникой RAII это даёт ооочень мощный инструмент...
Мощный по сравнению с чем? Для высокоуровневых языков он недостаточно мощный, и даже его существенно более мощное развитие — вывод регионов — тоже, как показали эксперименты с MLKit и JHC, недостаточно мощное. Никакой практичной альтернативы ГЦ для высокоуровневых языков все еще не существует.
_>Изменений сушествующих данных там нет никаких. Какое дело кому-то до модификации неразмеченной (выделенный пул используется у меня именно как голая память) области? _>Кстати, а если бы выделяемые на пуле массивы не пересекались в памяти, а выделялись бы каждый раз целиком рядышком (т.е. как делает обычный ~)... Это что-то изменило бы в вашем видение? ) Замечу, что код при этом не изменился бы ни на букву (была бы та же самая модификация), просто в конструктор передавали бы другой int...
Нет, это не изменило бы мое виденье. Потому что вы измеряете производительность работы с мутабельным массивом, а не иммутабельными структурами данных. То, что вы его называете "пулом" после того, как я сказал о том, что размещать иммутабельные структуры можно где угодно — ничего не меняет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[102]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Естественно возможно. И даже несложно. Определяете односвязный иммутабельный список, пишете нужные функции, выстраиваете конвейер из того же числа стадий, измеряете. Предлагаю вам именно этим и заняться.
_>Во-первых тогда надо однозначно договориться о количестве передаваемых данных и о количестве шагов конвейера. Т.е. в конкретных цифрах.
Так в чем проблема? Число стадий конвейера видно в коде, объемы размещаемых данных без и с оптимизациями я дал. Какие еще цифры нужны?
_>А во-вторых стандартных средства организации конвейеров в D работают через диапазоны, которые вы типа отказываетесь считать иммутабельными структурами (когда они поверх иммутабельного контейнера) из-за некой глупой придирки.
Заключающейся в том, что они мутабельные. Действительно, нелепая придирка: говорим о поддержке иммутабельности и измеряем производительность работы с мутабельными структурами. Казалось бы, какая разница: иммутабельные или мутабельные, дядька или бузина, Киев или огород?
_>А переписывать все циклы в рекурсии (чтобы компилятор сделал обратное потом) во всей библиотеке мне как-то лень...
О лени нужно было думать, когда вы заявляли о поддержке иммутабельности в языке, для которого и библиотек с иммутабельными структурами данных нету.
Впрочем, объем труда незначительный, объявить иммутабельный список нетрудно (это не finger-tree какой-нибудь), несколько функций написать — тоже. Правда зарание понятно, что производительность всего этого будет крайне низкой, и даже такого незначительного труда на подтверждение такого очевидного факта тратить жаль.
_>Массив с данными не изменяется вообще. Меняется некая неразмеченная память снаружи от него. По сути происходит выделение памяти для нового контейнера, но по хитрому. Т.е. это просто особая разновидность new.
Если бы вы реализовали это как кастомный аллокатор для размещения явно иммутабельных данных, т.е. абстрагировали бы управление памятью от вашего прикладного кода — тогда было бы еще о чем говорить. А так можно про любую работу с массивом сказать — в моих фантазиях тут односвязные списки, просто они так размещаются.
K>>Только она ручная, а не автоматическая — какое это отношение к поддержке в языке имеет? _>Вот, тут вы правы.
Если вы сами признаете это, то тогда о чем разговор вообще? См. выделенное.
_>Но главное что язык позволяет легко делать подобные вещи.
Позволяет с мутабельными данными работать? Тоже мне бином Ньютона! И при чем тут поддержка иммутабельности-то?
_>Как вы видите, всего несколько строк и гораздо более эффективный код, чем все ваши варианты.
Т.е. есть код состоящий из изменения массива на месте на Ди, и он на 30% быстрее чем высокоуровневый код, работающий с иммутабельными списками и с длинным конвейером на хаскеле. Также известно, что если добавить в код на ди конвейер хотя-бы из 2-х стадий — он уже в полтора раза медленнее хаскельного примера станет. Какой можно вывод сделать из этого? Ну, какой-то вывод о поддержке иммутабельности в хаскеле можно сделать. Можно также сделать вывод о том, насколько хорошо компилятор ди оптимизирует код с рейнджами. А вот что можно сказать о поддержке иммутабельности в Ди? Ничего, если только не интерпретировать вашу неспособность/нежелание написать на ди релевантный пример как какие-то проблемы с ди.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[101]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Много ли общих свойств у стат.класса и делегата? И тот и другой обозначаются одним значком с разными стереотипами.
Естественно, оба же классы — могут содержать поля и методы, могут наследоваться и т.п. По нормальному я бы ещё добавил "могут иметь экземпляры", т.к. чисто статические классы в UML не входят. )
K>Отношения инкапсуляции между типами и определенными на них функциями не существует. На практике диаграмма для хаскеля будет отличатся от диаграммы для Явы тем, что Разделение на блоки по видимостям будет только у знаков класса первого уровня. У всех вложенных разделения членов по видимости не будет.
Причём тут вообще вложенные классы? ) Тем более при их забавной частоте использования в ООП... Речь о том, что если вы поставите несколько типов (и соответственно функций, работающих с их внутренностями) в один модуль Хаскеля, то визуально никак не сможете понять какие функции работают с какими типами.
K>Мы вроде бы как раз теоретические трудности и обсуждали. Точнее существующую, якобы, необходимость расширить UML нестандартными средствами.
Расширение стандарта — это как раз практическая трудность, а не непреодолимое теоретическое препятствие.
_>>Ну так если получает извне, то именно в этой точке и можно ставить ограничение по типу. А map тут вообще ни при чём. K>Т.е. полезность такой проверки вы все-таки не отрицаете, главное чтоб не для map-а?
Я вообще люблю всяческие виды проверок. Поэтому как раз и не очень люблю динамические языки. Нюанс в том, что я хочу ими управлять, а не получать их свыше (как в случае Хаскеля). Т.е. на мой вкус и большинство динамических языков и решения типа Хаскеля являются ограниченными (в сравнение с языками типа C++, D и т.п.), просто противоположными способами. Как в динамических языках мы обычно просто не можем добавить нужные ограничения на нужной стадии, так в Хаскеле мы не можем написать код без следования множеству уже введённых ограничений. А вот в нормальных языках у нас полная свобода для самовыражения. Хотим ограничить аргументы нашей функции иммутабельными параметрами или чистыми функциями — легко. Хотим работать с произвольными данными — не проблема (и без всякого изменения/усложнения кода).
K>Явление известное. Взять что-то, назвать "лямбда", "мап" или, еще лучше, "все_есть", а потом заявлять на форумах: "вот вы говорите, что у нас ничего нет, а у нас "все_есть" — вот она, эта функция".
Ну да, это следствие не до конца установившейся терминологии в индустрии. Вот только есть большой вопрос на базе чего она будет устанавливаться: на основе неких академических статей или же по принципу наиболее широкого использования в индустрии...
K>Замерить производительность "полностью иммутабельного" примера не получится до тех пор, пока его кто-нибудь не напишет. И на вас тут, как я понял, надеяться не приходится. Замерить производительность полностью мутабельного примера, наверное, можно но тут возникают сложности. Во-первых, код неполный, нету импортов, которые я все-таки восстановил, но и после этого скомпилированный LDC2 экзешник падает сразу после запуска. Может, оптимизация хвостовой рекурсии не работает?
Возможно оптимизация не работает. Что вполне характеризует выбранные вами для тестирования инструменты. ))) Что-то мешало поставить себе dmd? )
Да, а что помешало протестировать мой бинарник? )
K>Моя точка зрения простая: я за удобный и развитый инструментарий. Я хочу использовать то, что удобнее в данном конкретном случае, а не выдумывать всякие нелепые обоснования ненужности колбасы, которой нет. K>В данной конкретной дискуссии я просто выступаю за следование теме, которая заявлена как "поддержка иммутабельности". Не "ненужность иммутабельности". Не "война — это мир, иммутабельность — это мутабельность". Вам же подтвердить заявленную поддержку иммутабельности нечем, и вообще сказать по теме разговора нечего, а потому вы всеми средствами отклоняетесь от темы, набрасываете нерелевантные примеры, а меня пытаетесь выставить слепым "фанатиком иммутабельности" именно потому, что я от темы отклоняюсь неохотно.
Нюанс в том, что хотя вы сейчас заявляете разумные мысли, для тестирования поддержки иммутабельности вы предложили задачу, которую никто в своём уме не будет реализовывать через иммутабельные данные (если конечно кривой дизайн языка не принуждает к этому силой, т.к. мутабельный вариант написать сложнее). И как понимать такое несоответствие? )
K>Мощный по сравнению с чем? Для высокоуровневых языков он недостаточно мощный, и даже его существенно более мощное развитие — вывод регионов — тоже, как показали эксперименты с MLKit и JHC, недостаточно мощное. Никакой практичной альтернативы ГЦ для высокоуровневых языков все еще не существует.
Как раз в последние дни работаю с языком общего назначения, после которого Хаскель кажется очень низкоуровневым... И там вполне себе есть опция "С GC или без". )
K>Нет, это не изменило бы мое виденье. Потому что вы измеряете производительность работы с мутабельным массивом, а не иммутабельными структурами данных. То, что вы его называете "пулом" после того, как я сказал о том, что размещать иммутабельные структуры можно где угодно — ничего не меняет.
Так это опять же вопрос терминологии — в какой момент мы считаем, что выделяется память? )
К примеру если мы возьмём многие реализации сборщиков мусора или даже куч (типа как в C++), то там частенько выделяется один большой блок каким-нибудь VirtualAlloc'ом и потом уже нарезается для конкретных данных. Соответственно если считать, что выделение памяти происходит в VirtualAlloc (прямо по вашей логике в нашем примере), то окажется что у нас есть один мутабельный блок памяти, который постоянно модифицируется, и ничего иммутабельного быть не может (хотя на самом деле возможно выделяются только такие данные), в том числе и в Хаскеле. Соответственно если вы всё же не считаете подобное выделением памяти, то тогда почему не позволяете применить ту же самую логику к моему коду? ) Ведь с этой точки зрения отличие моего iarray от библиотечного new исключительно в том, что мой класс не входит в стандартную библиотеку языка.
Re[103]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Заключающейся в том, что они мутабельные. Действительно, нелепая придирка: говорим о поддержке иммутабельности и измеряем производительность работы с мутабельными структурами. Казалось бы, какая разница: иммутабельные или мутабельные, дядька или бузина, Киев или огород?
Нюанс в том, что мутабельны (с вашей точки зрения) не сами контейнеры с данными, а итераторы по ним. Причём в Хаскеле всё буквательно то же самое, после оптимизации компилятором. А вот в D прямо в исходнике записаны циклы, а не рекурсии, так что не требуется дополнительная оптимизация Очевидно, что можно без проблем переписать все циклы на рекурсии (с рассчётом на то, что компилятор переделает назад), но подобная работа будет верхом идиотизма.
K>О лени нужно было думать, когда вы заявляли о поддержке иммутабельности в языке, для которого и библиотек с иммутабельными структурами данных нету.
Не путайте просто иммутабельные структуры (которые в D легко делаются из мутабельных с помощью модификатора immutable) и оптимизированные персистентные структуры. Вот последнего в стандартное библиотеке действительно нет и именно это я и реализовал для нашего примера.
K>Впрочем, объем труда незначительный, объявить иммутабельный список нетрудно (это не finger-tree какой-нибудь), несколько функций написать — тоже. Правда зарание понятно, что производительность всего этого будет крайне низкой, и даже такого незначительного труда на подтверждение такого очевидного факта тратить жаль.
Вы так и не поняли... ) Иммутабельный список в моём коде будет работать очень быстро, т.к. он просто не будет меняться. А если у него будет потребность меняться, то значит я уже не буду применять здесь иммутабельный список.
K>Если бы вы реализовали это как кастомный аллокатор для размещения явно иммутабельных данных, т.е. абстрагировали бы управление памятью от вашего прикладного кода — тогда было бы еще о чем говорить. А так можно про любую работу с массивом сказать — в моих фантазиях тут односвязные списки, просто они так размещаются.
Ну конечно, я сейчас будут плодить целую иерархию классов ради форумного примера. ))) Достаточно уже того, что если вынести мой класс iarray в библиотеку, то клиентскому коду будут абсолютно недоступны никакие манипуляции с общим буффером — для клиентского кода операция ~ выглядит как нормальное создание нового массива.
K>Т.е. есть код состоящий из изменения массива на месте на Ди, и он на 30% быстрее чем высокоуровневый код, работающий с иммутабельными списками и с длинным конвейером на хаскеле.
Код то есть, но вы отделываетесь отговорками о неспособности его запустить из-за использования маргинального (для D) компилятора.
K>Также известно, что если добавить в код на ди конвейер хотя-бы из 2-х стадий — он уже в полтора раза медленнее хаскельного примера станет. Какой можно вывод сделать из этого? Ну, какой-то вывод о поддержке иммутабельности в хаскеле можно сделать. Можно также сделать вывод о том, насколько хорошо компилятор ди оптимизирует код с рейнджами.
Ну вообще то диапазоны D как раз очень эффективно оптимизируют именно это дело. По примеру с map'и думаю было видно. Почему это не сработало в случае пары takeUntil.Any даже не представляю (а разбираться сейчас особо желания нет), но уверен что это какая-то недоработка реализации конкретно одного из этих алгоритмов, а не проблема самого принципа диапазонов. В большинстве, встреченных мною случаев, они оптимизировали конвейер любой длинны до одного цикла.
Re[102]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Много ли общих свойств у стат.класса и делегата? И тот и другой обозначаются одним значком с разными стереотипами. _>Естественно, оба же классы — могут содержать поля и методы, могут наследоваться и т.п.
Любой стат.класс наследник object и только, по понятным причинам это никак не проявляется на практике, и нет смысла это показывать на диаграмме. Все делегаты имеют общего предка и все поля-методы что у них есть наследуют от него, новых в них не добавить, т.е. это тоже на диаграмме показывать бессмысленно.
_>По нормальному я бы ещё добавил "могут иметь экземпляры", т.к. чисто статические классы в UML не входят. )
И, следовательно, во вашей логике UML для C# использовать нельзя, правильно?
_>Причём тут вообще вложенные классы? ) Тем более при их забавной частоте использования в ООП...
Притом, что кроме отображения вложения на диаграмме вы никакой другой проблемы так и не придумали.
Частота их использования как-то на возможности UML влияет? Имеет значение то, что их вполне можно показать, а использовать или нет и насколько часто — это дело программиста.
_>Речь о том, что если вы поставите несколько типов (и соответственно функций, работающих с их внутренностями) в один модуль Хаскеля, то визуально никак не сможете понять какие функции работают с какими типами.
Если есть смысл объединить эти типы в одном модуле — то какой смысл различать, с какими типами каждая из этих функций "работает"? Обычно они будут "работать" с несколькими из этих типов.
_>Расширение стандарта — это как раз практическая трудность, а не непреодолимое теоретическое препятствие.
Ну допустим. И что?
_>Я вообще люблю всяческие виды проверок. Поэтому как раз и не очень люблю динамические языки. Нюанс в том, что я хочу ими управлять, а не получать их свыше (как в случае Хаскеля).
Противопоставление тут непонятно. Вот, к примеру, возьмем инкапсуляцию в ООП. Когда вы изолируете особенности своей реализации от пользователя класса — вы ограничениями управляете, а пользователь наоборот "получает их свыше". Если вы сами пользователь какого-то класса — то "спускают свыше" уже вам. Так и тут.
_>Т.е. на мой вкус и большинство динамических языков и решения типа Хаскеля являются ограниченными (в сравнение с языками типа C++, D и т.п.), просто противоположными способами. Как в динамических языках мы обычно просто не можем добавить нужные ограничения на нужной стадии, так в Хаскеле мы не можем написать код без следования множеству уже введённых ограничений. А вот в нормальных языках у нас полная свобода для самовыражения. Хотим ограничить аргументы нашей функции иммутабельными параметрами или чистыми функциями — легко. Хотим работать с произвольными данными — не проблема (и без всякого изменения/усложнения кода).
Ничего не понимаю. Как вы можете "ограничить аргументы вашей функции" если кто-то захочет "работать с произвольными данными"? Может ли ваш "нормальный язык" создать камень, который не сможет поднять?
_>Ну да, это следствие не до конца установившейся терминологии в индустрии. Вот только есть большой вопрос на базе чего она будет устанавливаться: на основе неких академических статей или же по принципу наиболее широкого использования в индустрии...
Нет, это не терминологическая проблема. Есть, к примеру, мнение, что песок — неважная замена овсу. Проблема не в том, что нужно договориться и всем называть песок овсом. Проблема в том, что песок неважная замена для овса. Поэтому, если кто-то вас спрашивает: "Овес будет?" и вы ответите "Да", имея в виду, что будет песок — то потом окажется, что тот кто спрашивал — он именно овес и ожидал, а не песок. Если же все будут называть песок овсом, то проблема останется, потому что овес будут другим словом называть, например сепульками, и запрос на него останется, а вы сепульками будете называть опять песок. Ну или гравий, но от этого никому легче все равно не станет.
_>Возможно оптимизация не работает. Что вполне характеризует выбранные вами для тестирования инструменты. ))) Что-то мешало поставить себе dmd? )
Я вроде написал, почему я использовал не dmd (хотя я тогда думал, что ldc2 — это и есть dmd, только с llvm-бэкендом). Для того, чтоб исключить из сравнения фактор бэкенда. Судя по всему, решение было верным.
Я поставил DMD32 D Compiler v2.065, правда уже на другой компьютер (3330), но все остальное (ghc, llvm, windows) осталось без изменений.
Компилировал с -O -inline
Результаты такие:
На первом месте теперь haskell.
Версия, аналогичная той, что вы называете иммутабельной работает за 2.52 сек. или 0.95
Дальше самая быстрая версия на Ди, та, что с find — 2.66 сек. или 1. (если не указывать -O и -inline — то 6.19 сек, так что оптимизатор что-то делает)
Дальше хаскель со stream-fusion — 3.00 или 1.13
Дальше та, что вы называете "иммутабельной". Без оптимизации она падает, кстати, и с dmd, но с оптимизацией работает выдает ответ за 3.57 сек. или 1.34. (если сравнивать с аналогом на хаскеле, в котором, кстати, конвейер и нет рукописной лапши — вообще 1.40)
Короче говоря, если для ди не использовать llvm, а для хаскеля наоборот использовать, то самая быстрая ваша мутабельная версия практически не отличается от высокоуровневой полностью иммутабельной хаскельной и медленнее хаскельной с мутабельным буфером.
Поэтому ваши претензии к тому, что я сравнивал честнее — вообще звучат странно. Судя по find-версии, кодогенератор у dmd не фонтан, а единственное, что ldc2 не соптимизировал — это рекурсия. Впрочем, рекурсивно-лапшевая версия все равно тормозная, не понятно, за что вы боролись написав столько адского кода со строковыми параметрами шаблонов вместо нормальной передачи функций, кастами иммутабельных массивов в мутабельные и прочими ужасами.
_>Да, а что помешало протестировать мой бинарник? )
Очевидно, отсутствие вредной привычки запускать бинарники полученные непонятно от кого.
_>Нюанс в том, что хотя вы сейчас заявляете разумные мысли, для тестирования поддержки иммутабельности вы предложили задачу, которую никто в своём уме не будет реализовывать через иммутабельные данные (если конечно кривой дизайн языка не принуждает к этому силой, т.к. мутабельный вариант написать сложнее). И как понимать такое несоответствие? )
Как понимать я уже написал несколько раз. Сначала я предложил протестировать несколько иммутабельных структур данных, но вы сами и отказались. Как выяснилось позднее, потому, что таких структур для Ди нет. Поэтому я сделал другое предложение.
Задача — создавать промежуточные результаты в виде иммутабельных структур данных для проверки поддержки иммутабельности. Я знаю, что вы считаете, что для проверки иммутабельности нужно изменять массив на месте без всяких промежуточных данных вообще, но это кажется настолько неадекватным, что мне довольно трудно поверить, что вы все это серьезно пишете.
Впрочем, понятно, что под "поддержкой иммутабельности" вы подразумеваете возможность кастить между мутабельным массивом и "иммутабельным" в обе стороны и на этом будете настаивать и дальше, так что спор можно закруглять.
_>Как раз в последние дни работаю с языком общего назначения, после которого Хаскель кажется очень низкоуровневым... И там вполне себе есть опция "С GC или без". )
Как мы выяснили ранее, хаскель ваших фантазий — язык крайне низкоуровневый и вообще убогий, так что ничего удивительного тут нет.
_>Так это опять же вопрос терминологии — в какой момент мы считаем, что выделяется память? )
Нет, вопрос не в том, когда выделяется память и выделяется ли вообще.
_>Ведь с этой точки зрения отличие моего iarray от библиотечного new исключительно в том, что мой класс не входит в стандартную библиотеку языка.
Нет, отличие не в этом. Иммутабельная структура данных или нет видно из ее описания в библиотеке.
К примеру, структуры данных которые участвуют в конкурсе со стороны хаскеля выглядят так:
data [] a = [] | a : [a]
-- иdata Stream a where
Stream :: Unlifted s => !(s -> Step a s) -> !s -> Stream a
data Step a s = Yield a !s | Skip !s | Done
Как видите, никаких массивов и изменений их на месте тут не просматривается. Понятно, что размещается это все в конечном итоге в некоем "мутабельном массиве" — памяти, но это не повод пропустить этот этап и заявлять, что мутабельные массивы — это и есть иммутабельные структуры данных.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[104]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нюанс в том, что мутабельны (с вашей точки зрения)
Мне понравилось про мою точку зрения. Существует, мол, такая точка зрения у Клапауция, (очевидно ошибочная) что иммутабельные данные должны быть иммутабельными. Это, конечно, узкий взгляд на проблему, иммутабельные данные, конечно, мутабельны — а иначе обосновать поддержку в Ди иммутабельности не получится.
_>не сами контейнеры с данными, а итераторы по ним.
И сами контейнеры мутабельны. И итераторы по ним мутабельны.
_>Причём в Хаскеле всё буквательно то же самое, после оптимизации компилятором.
Ваш внутренний хаскель — это просто чудо какое-то.
_>А вот в D прямо в исходнике записаны циклы, а не рекурсии, так что не требуется дополнительная оптимизация
Высокий уровень! В лучших традициях фортрана.
_>Очевидно, что можно без проблем переписать все циклы на рекурсии
Правда программа будет падать — ну это не проблема, зато быстро падать будет.
_>но подобная работа будет верхом идиотизма.
И действительно. Оптимизация не нужна — можно же сразу оптимально написать, верно?
_>Не путайте просто иммутабельные структуры (которые в D легко делаются из мутабельных с помощью модификатора immutable)
Как из слона легко делается буйвол простой заменой надписи на клетке.
_>и оптимизированные персистентные структуры.
Так легко, что за это никто не берется — настоящие программисты легких путей не ищут!
_>Вот последнего в стандартное библиотеке действительно нет и именно это я и реализовал для нашего примера.
Но злые люди, по всей видимости, как только вы отвернулись на секунду, заменили эту реализацию на нечто малорелевантное и оно ушло на форум уже в таком виде.
_>Вы так и не поняли... ) Иммутабельный список в моём коде будет работать очень быстро, т.к. он просто не будет меняться. А если у него будет потребность меняться, то значит я уже не буду применять здесь иммутабельный список.
Чего уж тут непонятного? Очередное обоснование ненужности иммутабельности. Зачем список, который не меняется? Правильно, он бесполезен, а значит и иммутабельные структуры вообще.
_>Ну конечно, я сейчас будут плодить целую иерархию классов ради форумного примера.
В общем-то, если заявляется поддержка иммутабельности, то хотя-бы что-то такое уже должно быть, разве нет?
_>Достаточно уже того, что если вынести мой класс iarray в библиотеку, то клиентскому коду будут абсолютно недоступны никакие манипуляции с общим буффером — для клиентского кода операция ~ выглядит как нормальное создание нового массива.
Видимо "неклиентсвий" код никто не пишет. Погодите-ка. Вот вы же только что написали.
_>Код то есть,
Правда, к обсуждаемому вопросу никакого отношения не имеет, ну да ничего — можно ведь написать 256 постов в которых утверждать, что таки имеет. Потому, что иммутабельность — это мутабельность, свобода — это рабство и так далее.
_>но вы отделываетесь отговорками о неспособности его запустить из-за использования маргинального (для D) компилятора.
Как оказалось, компилятор, который генерирует более быстрый код в Ди маргинален — и правильно, жизнь медом казаться не должна.
_>Ну вообще то диапазоны D как раз очень эффективно оптимизируют именно это дело.
Оно и видно. (Ирония-иронией, но это действительно не самых плохой инструмент для построения конвейеров, к примеру дотнетный IEnumerable — значительно тормознее. Но и до хаскельных инструментов (у которых куча проблем и недоделок), как оказалось, не дотягивает)
_>Почему это не сработало в случае пары takeUntil.Any даже не представляю
Любые средства фьюжена имеют принципиальные ограничения и не справляются с устранением промежуточных данных для некоторых классов стадий конвейера. Они обычно классифицируются как хорошие/плохие продьюсеры/консьюмеры для данного метода фьюжена, это все разобрано в статьях и документировано. А для дишных рейнджей такие описания существуют?
_>но уверен что это какая-то недоработка реализации конкретно одного из этих алгоритмов, а не проблема самого принципа диапазонов.
Такие недоработки тоже бывают. К примеру, функция takeWhile из стандартной хаскельной библиотеки реализована так, что не участвует в фьюжене, не потому, что такой комбинатор невозможно реализовать правильным образом, а просто у авторов руки не дошли. Если его переписать, то стандартные функции работали бы так же быстро как те, что в примере с использованием stream-fusion, нагрузка на память была бы куда ниже и пришлось бы придумывать другой пример.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[103]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И, следовательно, во вашей логике UML для C# использовать нельзя, правильно?
Вообще то тут речь о поддерживаемых языком парадигмах, а не подобном. А так то можно же спокойно написать на нормальном C++ (не на C) нормальную программу без единого класса. И соответственно описать её архитектуру с помощью UML нормально не получится. Но это же не значит что UML не применим в C++.
Т.е. у нас есть:
1. Языки с жёстко зашитой ООП парадигмой (типа Java/C#) — в них надо ещё очень постараться (например использовать только те самые статические классы) написать программу не подходящую под описание с помощью основной структурной UML диаграммы. Но при этом в любом случае там ещё будут полезны две основные диаграммы поведения.
2. Языки поддерживающие ООП парадигму (типа Питон/C++). Тут программа без ООП пишется легко и удобно, но эта возможность не часто используется для больших проектов. Так что в большинстве серьёзных случаев архитектуру удобно отображать в UML, ну а для мелочей в этом и так нет смысла. И опять же две важные диаграммы поведения очень полезны и без ООП.
3. Императивные языки не поддерживающие ООП (типа C или старого Фортрана). Архитектуру тут на UML вообще не нарисуешь. Но диаграммки поведения всё ещё весьма полезны.
4. Языки типа Хаскеля (и без ООП и с декларативностью/ленивостью). Тут ни архитектуру приложения на UML не нарисуешь (без придумывания виртуального ООП в языке), ни поведение не опишешь.
K>Если есть смысл объединить эти типы в одном модуле — то какой смысл различать, с какими типами каждая из этих функций "работает"? Обычно они будут "работать" с несколькими из этих типов.
Что значит с несколькими? ) Полиморфизм подразумевается?
K>Противопоставление тут непонятно. Вот, к примеру, возьмем инкапсуляцию в ООП. Когда вы изолируете особенности своей реализации от пользователя класса — вы ограничениями управляете, а пользователь наоборот "получает их свыше". Если вы сами пользователь какого-то класса — то "спускают свыше" уже вам. Так и тут.
Я могу не использовать этот класс, если он мне не нравится. )
K>Ничего не понимаю. Как вы можете "ограничить аргументы вашей функции" если кто-то захочет "работать с произвольными данными"? Может ли ваш "нормальный язык" создать камень, который не сможет поднять?
Ещё раз: в D мы можем потребовать принимать в качестве параметра только чистую функцию, а можем и не требовать этого (и соответственно принимать любые). В динамических языках и в языках типа Хаскеля такое не выйдет, правда по совершенно разным причинам.
K>Нет, это не терминологическая проблема. Есть, к примеру, мнение, что песок — неважная замена овсу. Проблема не в том, что нужно договориться и всем называть песок овсом. Проблема в том, что песок неважная замена для овса. Поэтому, если кто-то вас спрашивает: "Овес будет?" и вы ответите "Да", имея в виду, что будет песок — то потом окажется, что тот кто спрашивал — он именно овес и ожидал, а не песок. Если же все будут называть песок овсом, то проблема останется, потому что овес будут другим словом называть, например сепульками, и запрос на него останется, а вы сепульками будете называть опять песок. Ну или гравий, но от этого никому легче все равно не станет.
Не совсем так. Всё зависит от распространённости. К примеру если "истинный овёс" будет нужен только 0,01% специалистов, то вся индустрия спокойно будет использовать "овёсопесок" и все будут довольны, в том смысле что будут отлично понимать друг друга. А проблемы при этом будут только у явного меньшинства, которое возможно и захочет придумать свою новую терминологию (те же сепульки), но вряд ли она станет общепринятой.
K>Я вроде написал, почему я использовал не dmd (хотя я тогда думал, что ldc2 — это и есть dmd, только с llvm-бэкендом). Для того, чтоб исключить из сравнения фактор бэкенда. Судя по всему, решение было верным.
С чего бы это его исключать? ) Программисты то работают именно с реальными компиляторами.
K>Я поставил DMD32 D Compiler v2.065, правда уже на другой компьютер (3330), но все остальное (ghc, llvm, windows) осталось без изменений. K>Компилировал с -O -inline
А надо как минимум с "-O -release -inline", т.к. иначе куча всего лишнего выполняется. Причём даже прямо в том моём классе — на каждый вызов функции-члена iarray происходит тестирование инвариантов класса.
K>Поэтому ваши претензии к тому, что я сравнивал честнее — вообще звучат странно. Судя по find-версии, кодогенератор у dmd не фонтан, а единственное, что ldc2 не соптимизировал — это рекурсия. Впрочем, рекурсивно-лапшевая версия все равно тормозная, не понятно, за что вы боролись написав столько адского кода со строковыми параметрами шаблонов вместо нормальной передачи функций, кастами иммутабельных массивов в мутабельные и прочими ужасами.
У меня этот код работает быстрее всех остальных вариантов. Не знаю что вы там тестировали и как.
_>>Да, а что помешало протестировать мой бинарник? ) K>Очевидно, отсутствие вредной привычки запускать бинарники полученные непонятно от кого.
Уууу программист не имеющий ни одной виртуалки — это забавно в наше время. Похоже я когда-то давно угадал насчёт теоретиков и практиков. )
K>Задача — создавать промежуточные результаты в виде иммутабельных структур данных для проверки поддержки иммутабельности. Я знаю, что вы считаете, что для проверки иммутабельности нужно изменять массив на месте без всяких промежуточных данных вообще, но это кажется настолько неадекватным, что мне довольно трудно поверить, что вы все это серьезно пишете.
Для меня настолько же неадекватно выглядит идея связывать тестирование сборщика мусора, с поддержкой иммутабельности в языке.
K>Как мы выяснили ранее, хаскель ваших фантазий — язык крайне низкоуровневый и вообще убогий, так что ничего удивительного тут нет.
По сравнению с тем же Прологом он действительно таким ощущается. )))
K>Нет, отличие не в этом. Иммутабельная структура данных или нет видно из ее описания в библиотеке. K>К примеру, структуры данных которые участвуют в конкурсе со стороны хаскеля выглядят так: K>... K>Как видите, никаких массивов и изменений их на месте тут не просматривается. Понятно, что размещается это все в конечном итоге в некоем "мутабельном массиве" — памяти, но это не повод пропустить этот этап и заявлять, что мутабельные массивы — это и есть иммутабельные структуры данных.
Я правильно понял, что если я вытащу (сделаю скажем глобальной функцией или ещё что-то) из того моего класса оператор "~", то резко станет соответствовать вашим представлениям об иммутабельных структурах? )
Re[105]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И сами контейнеры мутабельны. И итераторы по ним мутабельны.
Контейнеры не могут быть мутабельны, если мы используем модификатор immutable.
_>>Причём в Хаскеле всё буквательно то же самое, после оптимизации компилятором. K>Ваш внутренний хаскель — это просто чудо какое-то.
А в вашем внутреннем хаскеле не происходит оптимизация рекурсий в циклы? )
K>Высокий уровень! В лучших традициях фортрана.
Возможность записать явный цикл — это у нас теперь уже признак низкого уровня? ) А на мой взгляд цикл является более естественной вещью, чем рекурсия.
K>Чего уж тут непонятного? Очередное обоснование ненужности иммутабельности. Зачем список, который не меняется? Правильно, он бесполезен, а значит и иммутабельные структуры вообще.
Ну если вы не понимаете зачем в программе могут быть нужные неизменные данные, то мне тут даже и сказать нечего...
K>Любые средства фьюжена имеют принципиальные ограничения и не справляются с устранением промежуточных данных для некоторых классов стадий конвейера. Они обычно классифицируются как хорошие/плохие продьюсеры/консьюмеры для данного метода фьюжена, это все разобрано в статьях и документировано. А для дишных рейнджей такие описания существуют?
http://dlang.org/phobos/std_algorithm.html тут довольно подробно описаны все эти алгоритмы, включая оценки быстродействия и т.п. Но никаких упоминаний, почему сочетание until.any работает не оптимально, там нет. Видимо надо в исходниках смотреть, а мне как-то лень.
Кстати, замечу, что в реальном проекте (нашем тестовом на D), у нас кажется не встречается вообще ни одного конвейера. Не потому что не оптимально, а потому что просто нет таких задач.
Re[104]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то тут речь о поддерживаемых языком парадигмах
Возможность использования диаграммы классов с поддержкой парадигм связано слабо. Чтоб можно было UML использовать нужны 1) способы организации кода (функции/методы) 2) Способы группировки функций с функциями/данных с данными/данных с функциями 3) Нетривиальные отношения между получаемыми группами вроде наследования/вложения. Все. В большинстве языков все это есть, в том числе и в хаскеле.
_>Что значит с несколькими? ) Полиморфизм подразумевается?
Нет, подразумевается группа совместно используемых АлгТД, например АСТ какое-нибудь.
_>Я могу не использовать этот класс, если он мне не нравится. )
И в чем отличие от функции, которую вы тоже можете не использовать?
K>>Ничего не понимаю. Как вы можете "ограничить аргументы вашей функции" если кто-то захочет "работать с произвольными данными"? Может ли ваш "нормальный язык" создать камень, который не сможет поднять?
_>Ещё раз: в D мы можем потребовать принимать в качестве параметра только чистую функцию, а можем и не требовать этого (и соответственно принимать любые)
Но какая от этого практическая польза, если все что делает ваша "любая" функция, может делать и чистая?
_>Не совсем так. Всё зависит от распространённости. К примеру если "истинный овёс" будет нужен только 0,01% специалистов
В данном случае все эти рассуждения про одну сотую процента — не более чем попытка себя утешить принадлежностью к большинству. Вроде "у нас лямбд нету, зато нас легион!". На практике же соотношение часто бывает совсем иным. К примеру, программисты на практически всех языках с ГЦ ожидают от "лямбды" большего, чем может дать C++ под этой вывеской. И не смотря на то, что C++ действительно популярный язык — все эти программисты не на C++ составляют куда больше 0.01%.
_>и все будут довольны
Тут довольно трудно оценить сколько будут действительно довольны, а сколько просто уверять себя, что виноград — зелен.
_>С чего бы это его исключать? ) Программисты то работают именно с реальными компиляторами.
У вас отчетливо прослеживается тенденция сравнивать всякие плохо сравнимые вещи и оправдывать их какой-то "реальностью". Исключать надо вот почему: мы сравниваем производительность кода на двух языках, создаваемых на коленке горсткой энтузиастов. И если с одной стороны просить на весы бразиллион человекочасов вложенные в индустриального уровня бэкенд, то все противостояние этих двух кучек отойдет на второй план — это будет наколеночное ремесленничество против индустрии с понятным исходом.
Если дишный компилятор с LLVM бэкендом использовать нельзя или что вы там подразумевали под словом "нереален", то могу только посочувствовать.
_>А надо как минимум с "-O -release -inline"
А как оптимум? Эти ключи военная тайна какая-то? Почему бы вам с самого начала не дать всю информацию, необходимую для воспроизведения результата?
_>т.к. иначе куча всего лишнего выполняется.
Сюрприз: в хаскеле тоже проверяется "инвариант" и индексация массива. Там еще и буфер растущий по мере необходимости.
ОК, отключаем проверки, теперь хаскель версия с фиксированным буфером и без проверок
import Control.Applicative
import Control.Monad
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M
import Control.Exception
data Buffer m a = Buffer { len :: !Int, buf :: !(M.MVector m a) }
over f (Buffer c b) = f . U.take c <$> U.unsafeFreeze b
(Buffer c b) <| a = Buffer (assert(M.length b > c)(c+1)) b <$ M.unsafeWrite b c a
buffer l n = flip (foldM (<|)) l . Buffer 0 =<< M.new n
main = print . len =<< flip (U.foldM step) (U.takeWhile (<= 2^24) . U.enumFromStepN (5::Int) 2 $ 2^24)
=<< buffer [2, 3::Int] (2^24) where
step primes x = do
t <- over (U.all ((/= 0) . (rem x)) . U.takeWhile ((<= x) . (^2))) primes
if t then primes <| x else pure primes
считает за 2.38, дишная find версия считает за 2.52, как хаскельная с изменяемым буфером с проверками и дишная рекурсивная версия за 2.6. Поскольку она все равно несколько медленнее find-версии, похоже, что какие-то секретные ключи вы все еще не выдали. Что там еще писать-то? -flamewar? -please?
Также нужно отметить, что производительность для хаскельного кода я измеряю диагностическими средствами рантайма (+RTS -s), а ди — утилитой time, т.к. более точного средства для ди не знаю. (впрочем, для хаскеля это дает расхождения где-то в 0.05сек, так что на практике, похоже, ничего не меняет).
_>Причём даже прямо в том моём классе — на каждый вызов функции-члена iarray происходит тестирование инвариантов класса.
Да, дишные инварианты в рекурсивном примере — это просто чудо какое-то. Ни хаскельная версия, ни find так здорово от отключения проверок не прибавили.
_>У меня этот код работает быстрее всех остальных вариантов. Не знаю что вы там тестировали и как.
Что я тестировал и как вы как раз знаете: я привожу полный код примеров, ключи компиляторов, версии компиляторов, ОС и модели процессоров. А вот я как раз не знаю, что вы тестировали и как. В этом и проблема. Мне и код нужно дописывать и ключи компилятора самому подбирать.
_>Уууу программист не имеющий ни одной виртуалки — это забавно в наше время.
Вы меня разоблачили. На самом деле я не программист, просто несколько лет назад начал претворяться программистом, чтоб поддержать разговор на rsdn. Так с тех пор и не могу остановиться.
Запускание вашего бинарника технически, конечно, осуществимо, только непонятно зачем его запускать. (В ожидании новых разоблачений основанных на том, что я не спешу анализировать бинарный код, а настоящий программист, конечно всегда предпочтет это чтению исходника и т.д.)
_>Похоже я когда-то давно угадал насчёт теоретиков и практиков. )
Насчет теоретиков — вы мне льстите.
_>Для меня настолько же неадекватно выглядит идея связывать тестирование сборщика мусора, с поддержкой иммутабельности в языке.
Это очевидно следует из того, что вы считаете, что "для проверки иммутабельности нужно изменять массив на месте без всяких промежуточных данных вообще". Было бы странно, если бы вы это восприняли иначе.
_>По сравнению с тем же Прологом он действительно таким ощущается. )))
У вас помимо воображаемого хаскеля еще и воображаемый пролог есть?
_>Я правильно понял, что если я вытащу (сделаю скажем глобальной функцией или ещё что-то) из того моего класса оператор "~",
Если вы сделаете это глобальной функцией ничего не изменится. Проблема в том, что для оценки производительности при работе с иммутабельными данными вы измеряете производительность при изменении массива на месте.
_>то резко станет соответствовать вашим представлениям об иммутабельных структурах? )
Не нужно делать что-то "соответствующее моим представлениям", используйте иммутабельную структуру. Отговорка про 0.01% тут не подойдет, потому что программистов, например, на JVM/CLR языках больше чем C++ программистов.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[106]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Контейнеры не могут быть мутабельны, если мы используем модификатор immutable.
Предположение о том, что запощенный от вашего имени код написали злые люди, похоже, подтвердилось. Потому, что в нем "иммутабельный" контейнер легко меняется:
auto d=cast(T*)(data);
d[size]=v;
return immutable IArray!(L, T)(data, size+1);
_>>>Причём в Хаскеле всё буквательно то же самое, после оптимизации компилятором. K>>Ваш внутренний хаскель — это просто чудо какое-то. _>А в вашем внутреннем хаскеле не происходит оптимизация рекурсий в циклы? )
Не знаю, о каком моем внутреннем хаскеле вы говорите, но в известных мне реально существующих имплементациях хаскеля после оптимизации кода на хаскеле получается не код на хаскеле, а на других языках/промежуточных представлениях.
_>Возможность записать явный цикл — это у нас теперь уже признак низкого уровня? )
Ну да. А по-вашему чего это признак?
_>А на мой взгляд цикл является более естественной вещью, чем рекурсия.
Видимо вы считаете, что высокоуровневость — это то, что вы считаете "более естественной вещью".
_>Ну если вы не понимаете зачем в программе могут быть нужные неизменные данные, то мне тут даже и сказать нечего...
Раньше я это знал, но вы рассеяли морок моего знания и сейчас я, как и вы, уже не знаю этого.
_>Кстати, замечу, что в реальном проекте (нашем тестовом на D), у нас кажется не встречается вообще ни одного конвейера.
Я это понял еще когда вы написали, что у вас не было проблем с фьюженом конвейеров в один цикл. Собственно, "у меня не было проблем с X" и следует понимать как "я не пользовался X" для любого X (но не наоборот!)
_>Не потому что не оптимально, а потому что просто нет таких задач.
Это точно, задачи "сделай мне все замечательно" бывают, а вот "сделай мне все замечательно с использованием конвейера" — нет. Правда задач "сделай мне все замечательно с использованием цикла" не бывает тоже, так что и циклы вы, наверное, не используете.
А инлайн-брейнфак в Ди есть?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[106]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Высокий уровень! В лучших традициях фортрана.
_>Возможность записать явный цикл — это у нас теперь уже признак низкого уровня? ) А на мой взгляд цикл является более естественной вещью, чем рекурсия.
Цикл некорректно сравнивать с рекурсией. Не ясно, что брать за критерий естественности. Если формулы из книжки по математики, то здесь, внезапно, рекурсия именно то и есть, типа f(x) = ля-ля-ля f(x-1)
А если брать в рассчет именно вычислитель, то именно здесь и появляется цыкл. Но фокус в том, что для тот же io фактически асинхронный вычислитель, и твоих классных циклов просто не будет, а будет нечто, которое выглядит, цветет и пахнет как та самая рекурсия.
_>Кстати, замечу, что в реальном проекте (нашем тестовом на D), у нас кажется не встречается вообще ни одного конвейера. Не потому что не оптимально, а потому что просто нет таких задач.
Пудозреваю, вы не знаете как им пользоваться.
Re[105]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Ещё раз: в D мы можем потребовать принимать в качестве параметра только чистую функцию, а можем и не требовать этого (и соответственно принимать любые)
K>Но какая от этого практическая польза, если все что делает ваша "любая" функция, может делать и чистая?
Не может. Выше уже было показано, как требовать strict purity, полностью аналогичную хаскелевой (с иммутабельными параметрами).
Re[105]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Возможность использования диаграммы классов с поддержкой парадигм связано слабо. Чтоб можно было UML использовать нужны 1) способы организации кода (функции/методы) 2) Способы группировки функций с функциями/данных с данными/данных с функциями 3) Нетривиальные отношения между получаемыми группами вроде наследования/вложения. Все. В большинстве языков все это есть, в том числе и в хаскеле.
В теории всё верно. На практике же, если взглянуть на текущую версию стандарта UML, требуется поддержка именно ООП (для большей части структурных) и императивного кода (для большей части поведенческих).
K>Нет, подразумевается группа совместно используемых АлгТД, например АСТ какое-нибудь.
А будут ли вообще при таком раскладе функции специфичные для конкретного типа? Если нет, то тогда эти типы сводятся к аналогам обычных структур из C и соответственно говорить о какой-то инкапсуляции тут вообще странно.
_>>Я могу не использовать этот класс, если он мне не нравится. ) K>И в чем отличие от функции, которую вы тоже можете не использовать?
Вы не поняли, я не противопоставляю классы и функции. Речь о том, что в Хаскеле имеется большой ряд ограничений встроенных в сам язык (т.е. вне зависимости от каких-то библиотек и т.п.). В динамических языках у нас обычно нет даже возможности встроить подобные ограничения. А вот в языка типа D изначально практически никаких ограничений нет, но имеется набор инструментов для их создание, причём любой сложности (включая и все хаскелевские варианты).
K>Но какая от этого практическая польза, если все что делает ваша "любая" функция, может делать и чистая?
С чего бы это? )
K>В данном случае все эти рассуждения про одну сотую процента — не более чем попытка себя утешить принадлежностью к большинству. Вроде "у нас лямбд нету, зато нас легион!". На практике же соотношение часто бывает совсем иным. К примеру, программисты на практически всех языках с ГЦ ожидают от "лямбды" большего, чем может дать C++ под этой вывеской. И не смотря на то, что C++ действительно популярный язык — все эти программисты не на C++ составляют куда больше 0.01%.
Откуда это "в данном случае" возникли лямбды, если мы говорили про функцию map? )
Что касается лямбд, то это же всего навсего анонимный функтор — что там такого можно ожидать то? ))) Оно во всех языках одинаковое и отличается только набором обрамляющих знаков.
K>Тут довольно трудно оценить сколько будут действительно довольны, а сколько просто уверять себя, что виноград — зелен.
Я бы сказал, что большинство просто не в курсе при этом про какие-то другие варианты. )))
K>У вас отчетливо прослеживается тенденция сравнивать всякие плохо сравнимые вещи и оправдывать их какой-то "реальностью". Исключать надо вот почему: мы сравниваем производительность кода на двух языках, создаваемых на коленке горсткой энтузиастов. И если с одной стороны просить на весы бразиллион человекочасов вложенные в индустриального уровня бэкенд, то все противостояние этих двух кучек отойдет на второй план — это будет наколеночное ремесленничество против индустрии с понятным исходом. K>Если дишный компилятор с LLVM бэкендом использовать нельзя или что вы там подразумевали под словом "нереален", то могу только посочувствовать.
Если на D требуется достичь максимального быстродействия, то просто берётся gdc — думаю к его бекэнду никаких вопросов нет? ))) Но он по слухам (да и я натыкался помнится один раз) не очень стабилен под Windows, а мы занимаемся разработкой именно под ней, поэтому предпочитаем канонический dmd2. Он весьма стабильный под всеми платформами и в большинстве случаев не сильно проигрывает gdc.
K>А как оптимум? Эти ключи военная тайна какая-то? Почему бы вам с самого начала не дать всю информацию, необходимую для воспроизведения результата?
Достаточно написать в командной строке dmd и будут видны все опции (там нет такого беспредела с миллионом вариантов, как у gcc). Кстати там есть ещё много интересных, типа -unittest и т.п.
K>Сюрприз: в хаскеле тоже проверяется "инвариант" и индексация массива. Там еще и буфер растущий по мере необходимости.
Какой ещё инвариант проверяется в Хаскеле? ) Не стоит путать некоторые проверки нормального времени исполнения и по сути отладочный режим, который сыпит assert'ами. Вот как раз последнее и отключает -release. И как раз несколько таких assert'ов я для красоты и вставил в свой класс.
K>ОК, отключаем проверки, теперь хаскель версия с фиксированным буфером и без проверок K>...
Ох, жуть какая. ) Кстати, не принимайте подобные мои комментарии на свой счёт. Они относятся не непосредственно к вашему коду, а скорее к языку. Подозреваю, что ни один мастер не сможет написать на нём приемлемо выглядящий мутабельный код. )
K>считает за 2.38, дишная find версия считает за 2.52, как хаскельная с изменяемым буфером с проверками и дишная рекурсивная версия за 2.6. Поскольку она все равно несколько медленнее find-версии, похоже, что какие-то секретные ключи вы все еще не выдали. Что там еще писать-то? -flamewar? -please?
Да, странно. Остаются варианты: версия компилятора и способ измерения времени...
K>Также нужно отметить, что производительность для хаскельного кода я измеряю диагностическими средствами рантайма (+RTS -s), а ди — утилитой time, т.к. более точного средства для ди не знаю. (впрочем, для хаскеля это дает расхождения где-то в 0.05сек, так что на практике, похоже, ничего не меняет).
Я измерял так:
auto t=TickDuration.currSystemTick();
Primes!(2^^24)[].length.writeln;
writeln((TickDuration.currSystemTick()-t).msecs()/1000.0);
Предлагаю вам повторить измерения с таким способом. Думаю написать аналогичных код для Хаскеля не проблема? )
K>Да, дишные инварианты в рекурсивном примере — это просто чудо какое-то. Ни хаскельная версия, ни find так здорово от отключения проверок не прибавили.
Рекурсия тут ни при чём. Просто я для демонстрации приёмов контрактного программирования в D вставил в iarray несколько подобных проверок. Но надо не забывать, что эти проверки относятся по сути к отладочному режиму.
K>Что я тестировал и как вы как раз знаете: я привожу полный код примеров, ключи компиляторов, версии компиляторов, ОС и модели процессоров. А вот я как раз не знаю, что вы тестировали и как. В этом и проблема. Мне и код нужно дописывать и ключи компилятора самому подбирать.
Похоже проще мне снова поставить себе Хаскель и на этом закончить это бесконечное обсуждение с сомнительными измерениями. )))
K>У вас помимо воображаемого хаскеля еще и воображаемый пролог есть?
Не, Пролог у меня самый классический) Правда он встроен в приложение на C++ и умеет управлять микроконтроллерами в реальном времени.... )))
K>Если вы сделаете это глобальной функцией ничего не изменится. Проблема в том, что для оценки производительности при работе с иммутабельными данными вы измеряете производительность при изменении массива на месте.
Это оптимизация с помощью персистентной структуры. Вы же сами писали, что любите их. )
K>Не нужно делать что-то "соответствующее моим представлениям", используйте иммутабельную структуру. Отговорка про 0.01% тут не подойдет, потому что программистов, например, на JVM/CLR языках больше чем C++ программистов.
Вот уж кому говорить про иммутабельность, но не Java/С#. ))) Там у них даже с const напряги. )))
Re[107]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Предположение о том, что запощенный от вашего имени код написали злые люди, похоже, подтвердилось. Потому, что в нем "иммутабельный" контейнер легко меняется: K>
А где здесь изменений контейнера? ) Я вижу только создание нового.
K>Видимо вы считаете, что высокоуровневость — это то, что вы считаете "более естественной вещью".
О, кстати довольно интересный вопрос... А что собственно вы называете высокоуровневостью? ) Уже предчувствую очередное интересное открытие... )))
Re[107]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Цикл некорректно сравнивать с рекурсией. Не ясно, что брать за критерий естественности. Если формулы из книжки по математики, то здесь, внезапно, рекурсия именно то и есть, типа f(x) = ля-ля-ля f(x-1) I>А если брать в рассчет именно вычислитель, то именно здесь и появляется цыкл. Но фокус в том, что для тот же io фактически асинхронный вычислитель, и твоих классных циклов просто не будет, а будет нечто, которое выглядит, цветет и пахнет как та самая рекурсия.
Не, это не похоже на рекурсию, потому как там есть изменяемое состояние. А у рекурсии (настоящей, а не оптимизированной в цикл) этого как раз нет — там всё в стеке.
I>Пудозреваю, вы не знаете как им пользоваться.
Ну расскажи как пользоваться конвейерами в коде вида:
Кстати про код. Этот кусочек кода в переводе на веб-технологии означает вещи примерно 15-18 летней давности — все делается по месту и явно обычным императивным подходом.
Из истории известно, что этот подход был сменен на разные mvc и более декларативный вид. Причины простые — если такого кода достаточно много, его адски тяжело майнтейнить. Поменять структуру реквестов, пакетов и тд и тд — почти невозможно.
Так что та самая революция о окторой ты говоришь, может и не наступить, потому что вы будете изобретать весь веб, только на С++.
Re[106]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
K>>Но какая от этого практическая польза, если все что делает ваша "любая" функция, может делать и чистая? DM>Не может. Выше уже было показано, как требовать strict purity, полностью аналогичную хаскелевой (с иммутабельными параметрами).
Да нет, тут недопонимание. Я тут не про контроль чистоты в ди, с ним все понятно. Чистая функция в хаскеле делающая то же, что и "любая" в Ди.
Т.е. мой оппонент пишет:
Ещё раз: в D мы можем потребовать принимать в качестве параметра только чистую функцию, а можем и не требовать этого (и соответственно принимать любые). В динамических языках и в языках типа Хаскеля такое не выйдет, правда по совершенно разным причинам.
что в ди можно проверять чистая ли функция, а можно не проверять, а в хаскеле нельзя. Это верно, потому, что в хаскеле чистота функции не проверяется в смысле Ди — т.е. компайл-тайм рефлексией сигнатур и т.д., там функции чистые по построению. Но с практической точки зрения это не имеет значения, потому что за счет использования IO/ST чистые по построению функции могут делать то же самое что и те в Ди, для которых ничего не проверяется. Т.е. в mapM во время маппинга коллекции функция может делать все то же, что и в "непроверяющем" дишном map.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[109]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>У тебя последовательные вычисления с двумя if. Т.е. фактически, ты привел код y = f(x), что, очевидно, именно то что нужно для конвеера.
I>Твой код один к одному переписывается в монаду и вот у тебя практически тот самый конвейер.
Ну так покажи пример, как это стало бы выглядеть...
Re[106]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В теории всё верно. На практике же, если взглянуть на текущую версию стандарта UML, требуется поддержка именно ООП (для большей части структурных) и императивного кода (для большей части поведенческих).
Как раз наоборот. В теории — что-то там может и требуется, но на практике это никого не волнует.
_>А будут ли вообще при таком раскладе функции специфичные для конкретного типа?
Если тот, кто строит диаграмму решит, что будут — значит будут.
_>Если нет, то тогда эти типы сводятся к аналогам обычных структур из C и соответственно говорить о какой-то инкапсуляции тут вообще странно.
Инкапсуляция на уровне модулей все равно.
_>Вы не поняли, я не противопоставляю классы и функции. Речь о том, что в Хаскеле имеется большой ряд ограничений встроенных в сам язык (т.е. вне зависимости от каких-то библиотек и т.п.).
Что за ограничения встроенне в язык?
_>А вот в языка типа D изначально практически никаких ограничений нет, но имеется набор инструментов для их создание, причём любой сложности (включая и все хаскелевские варианты).
Разница с хаскелем в том, что для него уже написана библиотека с контролем эффектов, построенная с использованием "инструментов для создания", а для Ди такой инфраструктуры пока нет, есть инструменты и ее "можно сделать".
_>С чего бы это? )
С того, что на хаскеле можно написать код с из чистых по построению функций, который будет делать то же, что и код на ди из "любых" функций без всякого контроля эффектов.
_>Откуда это "в данном случае" возникли лямбды, если мы говорили про функцию map? )
Возникли из моей фразы, на которую вы отвечаете:
Явление известное. Взять что-то, назвать "лямбда", "мап" или, еще лучше, "все_есть", а потом заявлять на форумах: "вот вы говорите, что у нас ничего нет, а у нас "все_есть" — вот она, эта функция".
иду прямо по списку. Популярность лямбды никак не повлияла на то, что под видом лямбды предлагается нечто недоделанное. Поэтому все рассуждения про то, что что-то там нужно 0.01% и в этом-то все дело не имеют никакого отношения к реальности: процент тех, кто видит разницу между овсом и песком никак не влияет на стремление предлагать песок тому, кому овес нужен.
_>Что касается лямбд, то это же всего навсего анонимный функтор — что там такого можно ожидать то? )))
Можно ожидать решенную UFP, например, а не путанные оправдания о том, что UFP одновременно и решена и ее решение не нужно.
_>Оно во всех языках одинаковое и отличается только набором обрамляющих знаков.
Почти во всех языках оно примерно одинаковое, с решенной UFP, а в плюсах — нет. В этом и дело.
_>Я бы сказал, что большинство просто не в курсе при этом про какие-то другие варианты. )))
Ну да. И если они вдруг что-то слаще моркови попробуют — у них и потребности соответствующие появятся.
_>Если на D требуется достичь максимального быстродействия, то просто берётся gdc — думаю к его бекэнду никаких вопросов нет? ))) Но он по слухам (да и я натыкался помнится один раз) не очень стабилен под Windows, а мы занимаемся разработкой именно под ней, поэтому предпочитаем канонический dmd2. Он весьма стабильный под всеми платформами и в большинстве случаев не сильно проигрывает gdc.
Замечательно. Есть ldc, но его использовать нельзя. Зато есть gdc, но его использовать нельзя. Зато есть dmd, который не сильно проигрывает (на самом деле заметно).
_>Достаточно написать в командной строке dmd и будут видны все опции (там нет такого беспредела с миллионом вариантов, как у gcc).
Конечно будут видны все. А не те, что вы использовали. Но нужно то знать те, которые вы использовали для замеров.
K>>Сюрприз: в хаскеле тоже проверяется "инвариант" и индексация массива. Там еще и буфер растущий по мере необходимости.
_>Какой ещё инвариант проверяется в Хаскеле? )
Да тот же самый, что позиция "курсора" не превышает длины буфера.
_>Ох, жуть какая. ) Кстати, не принимайте подобные мои комментарии на свой счёт. Они относятся не непосредственно к вашему коду, а скорее к языку. Подозреваю, что ни один мастер не сможет написать на нём приемлемо выглядящий мутабельный код. )
Конечно жуть. Ни циклов, ни рекурсивной лапши, ни даже передачи лямбд в текстовом виде! Просто кошмар какой-то.
_>Да, странно. Остаются варианты: версия компилятора и способ измерения времени...
Т.е. никаких больше ключей не было. К чему же было загадочное "как минимум"? Еще могу предположить, что вы взяли наихудший результат для find и наилучший для рекурсивной версии, а я беру средние.
_>Предлагаю вам повторить измерения с таким способом.
так рекурсивный вариант — 2.48, а с find — 2.42. Как я и предполагал — нет принципиальной разницы с результатами time.
_>Думаю написать аналогичных код для Хаскеля не проблема? )
Не вижу особого смысла. Я же говорю, там есть статистика от рантайма, в том числе и время работы.
_>Рекурсия тут ни при чём.
Да это понятно, я просто называю его рекурсивным чтоб было понятно о каком примере речь идет.
_>Просто я для демонстрации приёмов контрактного программирования в D вставил в iarray несколько подобных проверок.
Вы говорили что инвариант проверяется при каждом вызове метода класса. Т.е. не только при движении курсора, но и при каждом чтении элемента при обходе массива при поиске? Если так, то понятно, откуда тормоза. Миллион проверок при движении курсора погоды не сделают, а такие вот проверки — легко.
_>Похоже проще мне снова поставить себе Хаскель и на этом закончить это бесконечное обсуждение с сомнительными измерениями. )))
Ну, если вы будете выдавать сомнительные измерения — то обсуждение на этом не закончится. А в чем сомнительность моих измерений? Началось все с того, что вы заявили о разнице "в разы" (так и не понял, откуда вы ее взяли) при том, что конвейер у меня превращается в один цикл. И что это странно.
На что я ответил, что никакой разницы в разы нет и соответственно и странного ничего нет.
Что теперь-то вам кажется сомнительным?
_>Не, Пролог у меня самый классический) Правда он встроен в приложение на C++ и умеет управлять микроконтроллерами в реальном времени.... )))
Классический пролог — довольно слабый язык без типов и вообще интересных выразительных средств с необходимостью для чего-то нетривиального использовать хаки от красных катов до переписывания базы предикатов во время выполнения, что заставляет распрощаться с декларативной семантикой и думать в императивной, о том как решатель деревья обходит.
_>Это оптимизация с помощью персистентной структуры. Вы же сами писали, что любите их. )
1) Это ручная оптимизация, и следовательно не имеет отношения к поддержке иммутабельности языком.
2) Я ничего не говорил про "оптимизацию с помощью персистентной структуры", я говорил про оптимизации, которые позволяют персистентным структурам работать с приемлемой скоростью.
_>Вот уж кому говорить про иммутабельность, но не Java/С#. )))
В Java/С# иммутабельные данные применяются в более-менее заметных масштабах. Что возможно как раз потому, что нормальный ГЦ есть.
_>Там у них даже с const напряги. )))
Конечно. Но плюсовой const имеет весьма отдаленное отношение к иммутабельности, так что какие проблемы?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[108]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А где здесь изменений контейнера? ) Я вижу только создание нового.
d[size]=v;
K>>Видимо вы считаете, что высокоуровневость — это то, что вы считаете "более естественной вещью".
_>О, кстати довольно интересный вопрос... А что собственно вы называете высокоуровневостью? ) Уже предчувствую очередное интересное открытие... )))
Ну, если учесть, что я на этот вопрос вам в этой ветке уже отвечал — открытие вам показалось не очень интересным. Иначе запомнилось бы.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[109]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Кстати про код. Этот кусочек кода в переводе на веб-технологии означает вещи примерно 15-18 летней давности — все делается по месту и явно обычным императивным подходом.
Что значит по месту? ) Это же серверный код.
Да, и это классическая архитектура большинства популярных веб-фреймворков. Типа там всяких Django, RoR, Node.js.
I>Так что та самая революция о окторой ты говоришь, может и не наступить, потому что вы будете изобретать весь веб, только на С++.
1. Не на C++, а на D. )
2. Изобретаем не мы — мы только пользуемся, и то в тестовом стажёрском проекте.
3. Модность их проекта в оригинальных компилируемых шаблонах, дающих одновременно и удобство и гарантии и огромное быстродействие (кстати все остальные компоненты заточены под это же, в том числе и на базе твоей любимой асинхронщины). А в реакции на ajax запросы там ничего инновационного нет, если конечно не считать того, что это происходит на статически типизированном нативном языке.
Re[110]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Кстати про код. Этот кусочек кода в переводе на веб-технологии означает вещи примерно 15-18 летней давности — все делается по месту и явно обычным императивным подходом.
_>Что значит по месту? ) Это же серверный код.
И что с того ?
_>Да, и это классическая архитектура большинства популярных веб-фреймворков. Типа там всяких Django, RoR, Node.js.
Нет, это не классическая архитектура. Это веб давности 15-18 лет, когда ты напрямую читаешь из реквеста и пишешь в респонс. то есть, тупо самый нижний уровень
Ты видишь здесь реквест, респонс ? Что характерно, издержек около нуля, в пересчете на затраты на диспетчеризацию из нижнего уровня в такой вот вид.
_>3. Модность их проекта в оригинальных компилируемых шаблонах, дающих одновременно и удобство и
Из твоего кода не видно, что вы используете шаблоны. Видно что вы изобретаете веб конца прошлого века.
>А в реакции на ajax запросы там ничего инновационного нет, если конечно не считать того, что это происходит на статически типизированном нативном языке.
Судя по коду, вся ваша инновация заключается в бинарном варианте json. Такой фокус есть в питоне, и в ноде и где угодно.
Re[110]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так покажи пример, как это стало бы выглядеть...
В монадическом виде не нужны проверки на нулл. Отсюда надо
1. извлечь lang из req.form
2. извлечь юзера
3. послать все это функции для обновления состояния
4. сформировать результат
Здравствуйте, Klapaucius, Вы писали:
K>Как раз наоборот. В теории — что-то там может и требуется, но на практике это никого не волнует.
Ну да, потому что практики в общем то и нет. По вашему же признанию (что в мире хаскеле uml'ем практически не пользуются) кстати.
K>Что за ограничения встроенне в язык?
Мы же это уже пережёвывали в этой темке не раз. Надо повторять снова про невозможность написания кода для реальных приложений без уродливых монад? )
K>Разница с хаскелем в том, что для него уже написана библиотека с контролем эффектов, построенная с использованием "инструментов для создания", а для Ди такой инфраструктуры пока нет, есть инструменты и ее "можно сделать".
Совершенно верно. Правда для начала надо доказать полезность подобного. ) Этот вопрос тут уже обсуждался, но почему-то ответ пытался дать совершенно другой участник. А от вас так ни одного аргумента и не поступило.
K>С того, что на хаскеле можно написать код с из чистых по построению функций, который будет делать то же, что и код на ди из "любых" функций без всякого контроля эффектов.
Ага, в страшных монадах. ))) А можно и вообще обозвать (аналог магии каста в C++) любую внешнюя функцию чистой (даже если она при этом диски форматирует) и вообще никаких проблем. )))
K>Возникли из моей фразы, на которую вы отвечаете: K>
Явление известное. Взять что-то, назвать "лямбда", "мап" или, еще лучше, "все_есть", а потом заявлять на форумах: "вот вы говорите, что у нас ничего нет, а у нас "все_есть" — вот она, эта функция".
Это всё понятно. Но я не понял куда собственно делось обсуждение map'а? ) Или вам так неприятно узнавать, что в индустрии обычно подразумевают под этим понятием совсем не то, что вы? )
K>Можно ожидать решенную UFP, например, а не путанные оправдания о том, что UFP одновременно и решена и ее решение не нужно.
UFP относится к замыканиям, а не к лямбдам. Это конечно вещи связанные, но совсем не синонимы. Снова у вас какая-то путаница в терминологии.
_>>Какой ещё инвариант проверяется в Хаскеле? ) K>Да тот же самый, что позиция "курсора" не превышает длины буфера.
Выход за границы массива — это другое. И кстати в D тоже умеет проверяться автоматом (в срезах тех самых). А у меня был инвариант проверяющий, что грубо говоря не кончилась свободная память (пул в нашем случае). Ну и плюс ещё один, проверяющий что у нас вообще выделена память (дело в том, что D не позволяет запретить публичный конструктор для структур, в отличие от классов, т.е. там всегда доступен некий дефолтный init).
K>Т.е. никаких больше ключей не было. К чему же было загадочное "как минимум"? Еще могу предположить, что вы взяли наихудший результат для find и наилучший для рекурсивной версии, а я беру средние.
Ого. Т.е. вы даже не знаете самых элементарных принципов подобного тестирования? Что надо всегда проводить серию тестов и брать минимальное значение для каждого испытуемого.
Даже не знаю теперь о чём вообще говорить ещё при таком раскладе...
K>так рекурсивный вариант — 2.48, а с find — 2.42. Как я и предполагал — нет принципиальной разницы с результатами time.
У меня рекурсивный вариант стабильно быстрее. В среднем процентов на 8. Причём это так должно быть и с теоретической точки зрения, т.к. find генерирует промежуточную структуру в результате своей деятельности, а не индекс или самое значение (оно потом получается дополнительным вызовом к этой структуре).
Ваши же результаты весьма загадочны.
K>Не вижу особого смысла. Я же говорю, там есть статистика от рантайма, в том числе и время работы.
Для чистоты сравнения. Мало ли что там ваш рантайм показывает. )))
K>Ну, если вы будете выдавать сомнительные измерения — то обсуждение на этом не закончится. А в чем сомнительность моих измерений?
Они не совпадают ни с моими результатами (хотя бы в сравнение двух версий кода на D), ни с результатами D. Mon'а (у него было вменяемое сравнение кода на D с кодом на Хаскеле), на которые я и ориентировался при своих оценках.
K>Классический пролог — довольно слабый язык без типов и вообще интересных выразительных средств с необходимостью для чего-то нетривиального использовать хаки от красных катов до переписывания базы предикатов во время выполнения, что заставляет распрощаться с декларативной семантикой и думать в императивной, о том как решатель деревья обходит.
В любом случае он находится явно на более высоком уровне абстракции, чем Хаскель, т.к. у него хотя бы уже есть этот решатель. )))
Re[109]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нет, это не классическая архитектура. Это веб давности 15-18 лет, когда ты напрямую читаешь из реквеста и пишешь в респонс. то есть, тупо самый нижний уровень
I>Классика нынче вот такая I>
I>Ты видишь здесь реквест, респонс ? Что характерно, издержек около нуля, в пересчете на затраты на диспетчеризацию из нижнего уровня в такой вот вид.
И в чём разница? ) Ты просто разделил ту функцию на две, первую из которых не показал (подразумевая что она заложена во фреймворк видимо?). Кстати, а если у нас обрабатывается формочка с десятком полей, то и функция в твоём варианте будет со страшнейшим прототипом? )
I>Из твоего кода не видно, что вы используете шаблоны. Видно что вы изобретаете веб конца прошлого века.
Так а откуда шаблоны в коде ajax реакции? ) Они в выдаче самих страниц. )
I>Судя по коду, вся ваша инновация заключается в бинарном варианте json. Такой фокус есть в питоне, и в ноде и где угодно.
Не, бинарный json это потому что MongoDB, а не потому что D. )
Re[111]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В монадическом виде не нужны проверки на нулл. Отсюда надо I>1. извлечь lang из req.form I>2. извлечь юзера I>3. послать все это функции для обновления состояния I>4. сформировать результат
I>{lang:req.form.lang, user:userFromCookie} | updateUser | resultJson 0
В том коде updateUser вызывается при наличие и lang и user. А resultJson вызывается если есть хотя бы lang. Где эта логика указана в твоём коде?
Re[112]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>{lang:req.form.lang, user:userFromCookie} | updateUser | resultJson 0
_>В том коде updateUser вызывается при наличие и lang и user. А resultJson вызывается если есть хотя бы lang. Где эта логика указана в твоём коде?
Это несущественные детали. Конвейер при внятной реализации умеет работать с нулевыми значениями и ошибками. Скажем на проверку нулевого значения добавляется комбинатор notNull
В твоём случае на самом деле конвейер не нужен. Если у тебя весь код такой, то конечно конвейеры не нужны. Они хорошо работают в обработке данных. Для твоего примера тебе нужен тот вариант, который я показал в соседнем сообщении.
Re[112]: Есть ли вещи, которые вы прницпиально не понимаете...
I>>Ты видишь здесь реквест, респонс ? Что характерно, издержек около нуля, в пересчете на затраты на диспетчеризацию из нижнего уровня в такой вот вид.
_>И в чём разница? ) Ты просто разделил ту функцию на две, первую из которых не показал
Ты для начала ответь на вопрос — где ты видишь реквест и респонс.
>(подразумевая что она заложена во фреймворк видимо?).
Разумеется, фремворк. И если мне, скажем, придется перейти ну скажем на Named Pipe, то у меня будет просто, код практически без изменений. А тебе придется думать, как избавиться от httpRequest и httpResponse. Надо объяснять, что их не будет в случае с пайпами ?
>Кстати, а если у нас обрабатывается формочка с десятком полей, то и функция в твоём варианте будет со страшнейшим прототипом? )
Не будет никаких страшных прототипов, а будет ровно один параметр.
_>Так а откуда шаблоны в коде ajax реакции? ) Они в выдаче самих страниц. )
Я и говорю — это изобретение веба. От силы asp.net 1.0, там тоже есть шаблоны, кстати говоря.
_>Не, бинарный json это потому что MongoDB, а не потому что D. )
Значит просто изобретение веба.
Re[108]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну да, потому что практики в общем то и нет. По вашему же признанию (что в мире хаскеле uml'ем практически не пользуются) кстати.
Практики как раз достаточно. Я про практику применения с языками, в которых есть расширения "классического" ООП. Т.е. почти всеми языками.
_>Мы же это уже пережёвывали в этой темке не раз. Надо повторять снова про невозможность написания кода для реальных приложений без уродливых монад? )
Но в языке нет таких ограничений. Можно хоть с функторами, хоть со стрелками, хоть с неуродливыми монадами.
_>Совершенно верно. Правда для начала надо доказать полезность подобного.
Вам что-ли?
_>Этот вопрос тут уже обсуждался, но почему-то ответ пытался дать совершенно другой участник. А от вас так ни одного аргумента и не поступило.
Так от вас на обсуждаемую тему тоже ни одного аргумента не поступило.
_>Ага, в страшных монадах. )))
Чем они страшнее передачи лямбд через параметры шаблонов в текстовом виде, например?
_>А можно и вообще обозвать (аналог магии каста в C++) любую внешнюя функцию чистой (даже если она при этом диски форматирует) и вообще никаких проблем. )))
С помощью аналога "магии каста" можно делать все что угодно в любом языке.
_>Это всё понятно. Но я не понял куда собственно делось обсуждение map'а? ) Или вам так неприятно узнавать, что в индустрии обычно подразумевают под этим понятием совсем не то, что вы? )
Обсуждение мапа продолжается. Вы утвеждали, что в "индустрии" недомап называют мапом потому, что нормальный мап никто не видел. Я же привел контрпример, когда даже узнав что такое лямбда продолжают называть лямбдой недолямбду. Т.е. это никак не связано с неизведанностью чего-то для мейнстрима, а связано с желанием убедить себя в том, что у вас есть то, чего у вас на самом деле нет и не будет.
_>UFP относится к замыканиям, а не к лямбдам. Это конечно вещи связанные, но совсем не синонимы. Снова у вас какая-то путаница в терминологии.
Из того, что я пишу никак не следует, что это синонимы.
K>>Да тот же самый, что позиция "курсора" не превышает длины буфера. _>А у меня был инвариант проверяющий, что грубо говоря не кончилась свободная память (пул в нашем случае)
Про это я и говорю.
_>Ого. Т.е. вы даже не знаете самых элементарных принципов подобного тестирования? Что надо всегда проводить серию тестов и брать минимальное значение для каждого испытуемого.
В отличие от вас, как раз знаю. Минимальное значение можно брать только тогда, когда точность измерения времени достаточно высокая, чтоб ей пренебречь и считать, что любое значение кроме минимального будет просто выбросом. Но с точностью на виндоус серьезные проблемы. time даст точность никак не лучше 0.02сек, так что минимальное значение можно было бы брать если бы мы запускали примеры, работающие десятки, а лучше сотни секунд, но у нас — единицы.
В счастливые времена одноядерных процессоров с не изменяющейся постоянно частотой можно было просто перф. каунтер использовать, но сейчас им такого можно намерять, что мало не покажется.
Самое главное, что эта побочная тема про точность за которую вы ужватились все равно никак не приведет к тому, что разница "в разы" окажется.
_>Даже не знаю теперь о чём вообще говорить ещё при таком раскладе...
Как обычно, о ваших фантазиях.
_>У меня рекурсивный вариант стабильно быстрее. В среднем процентов на 8.
Ну допустим. Взятой вами с потолка разницы "в разы" это все равно не даст.
_>Для чистоты сравнения. Мало ли что там ваш рантайм показывает. )))
И действительно, мало ли что он показывает? Наверное специально заниженные данные выдает, чтоб вас позлить. Замерил перф.каунтером — 2.39сек.
_>Они не совпадают ни с моими результатами (хотя бы в сравнение двух версий кода на D)
Допустим. А ваши результаты не совпадают с моими. И не в порядке они, я думаю, у того, кто постоянно скрывает информацию, необходимую для воспроизведения замеров. И это точно не я.
_>ни с результатами D. Mon'а (у него было вменяемое сравнение кода на D с кодом на Хаскеле), на которые я и ориентировался при своих оценках.
что ли? Ну так там сравниваются не те примеры, которые мы сейчас сравниваем.
_>В любом случае он находится явно на более высоком уровне абстракции, чем Хаскель, т.к. у него хотя бы уже есть этот решатель. )))
Решатель есть — вот это да! А у хаскеля тайпчекер и вычислитель есть.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[110]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В твоём случае на самом деле конвейер не нужен. Если у тебя весь код такой, то конечно конвейеры не нужны. Они хорошо работают в обработке данных. Для твоего примера тебе нужен тот вариант, который я показал в соседнем сообщении.
Вот вот, я с самого начала и сказал, что не нужны.
Кстати, а в наших основных делах (которые на C++) конвейеры как раз частенько встречаются. Только они выглядят не совсем так банально. В начале настраивается сложный (и очень эффективный) конвейер, а потом через него в реальном времени гонятся гигабайты. )
Re[113]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты для начала ответь на вопрос — где ты видишь реквест и респонс.
Какая разница упакованы параметры в дополнительную структуру или же передаются явно в функцию? )
Да, а по поводу возвращаемого значения вообще подход со спец. структурой (вместо возвращаемого из функции значения) намного удобнее, т.к. можно осуществлять многоразовое добавление в вывод (ну по типу yield).
I>Разумеется, фремворк. И если мне, скажем, придется перейти ну скажем на Named Pipe, то у меня будет просто, код практически без изменений. А тебе придется думать, как избавиться от httpRequest и httpResponse. Надо объяснять, что их не будет в случае с пайпами ?
Какие ещё Named Pipe, если у нас тут веб-фреймвор со встроенным в него (причём это не опционально, а единственный вариант, но зато такой, что уже никакие nginx'ы в качестве фронтенда не нужны) сервером? )
I>Не будет никаких страшных прототипов, а будет ровно один параметр.
Что за параметр? ) Твой пример показывает передачу значения поля формы в виде параметра функции. Так а что будет в случае нескольких полей?
I>Я и говорю — это изобретение веба. От силы asp.net 1.0, там тоже есть шаблоны, кстати говоря.
Шаблоны то и в php есть))) Но не компилируемые (и не на базе статически типизированного нативного языка) в бинарник...
Re[109]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Практики как раз достаточно. Я про практику применения с языками, в которых есть расширения "классического" ООП. Т.е. почти всеми языками.
Ну так а в Хаскеле то у нас что? ) Там же нечего расширять. )
K>Но в языке нет таких ограничений. Можно хоть с функторами, хоть со стрелками, хоть с неуродливыми монадами.
О да, конечно))) И все примеры работы с мутабельными данными из этой темке это конечно же "подтверждают"... )
_>>Совершенно верно. Правда для начала надо доказать полезность подобного. K>Вам что-ли?
кто-то хотя бы попытался привести примеры. Хотя в итоге продемонстрировать ничего не удалось, но хотя бы была попытка. А вот вы, постоянно кидаясь фразой о "контроле эффектов", так ни разу и не привели ни единого примера.
K>Так от вас на обсуждаемую тему тоже ни одного аргумента не поступило.
Эммм, а какие аргументы от меня требуются? ) Я же ничего не утверждаю, а наоборот прошу показать мне правильные примеры. Вот если никто так и не приведёт ни одного реального, тогда я наверное уже начнут утверждать, что это всё сомнительная и не нужная на практике вещь... )
K>Чем они страшнее передачи лямбд через параметры шаблонов в текстовом виде, например?
1. А какая разница, если всё это компилируется статически и соответственно сообщение об ошибке будет как и для обычной функции?
2. Можно и не текстом (так просто короче на несколько символов). Но компилируется это в тот же самый код.)))
K>Обсуждение мапа продолжается. Вы утвеждали, что в "индустрии" недомап называют мапом потому, что нормальный мап никто не видел. Я же привел контрпример, когда даже узнав что такое лямбда продолжают называть лямбдой недолямбду. Т.е. это никак не связано с неизведанностью чего-то для мейнстрима, а связано с желанием убедить себя в том, что у вас есть то, чего у вас на самом деле нет и не будет.
Нет, в индустрии называют map'ом определённую конструкцию (которая с вашей точки зрения не настоящий map) потому, что она такова в наиболее популярных языках. Вот и всё.
K>В отличие от вас, как раз знаю. Минимальное значение можно брать только тогда, когда точность измерения времени достаточно высокая, чтоб ей пренебречь и считать, что любое значение кроме минимального будет просто выбросом. Но с точностью на виндоус серьезные проблемы. time даст точность никак не лучше 0.02сек, так что минимальное значение можно было бы брать если бы мы запускали примеры, работающие десятки, а лучше сотни секунд, но у нас — единицы.
Из вашего потока слов я так и не понял, как факт наличия погрешности измерения времени в несколько процентов (хотя на самом деле меньше, но это не принципиально) обосновывает необходимость усреднять результаты (и тем самым учитывать влияние каких-нибудь там сервисных процессов ОС, включившихся не вовремя).
K>Самое главное, что эта побочная тема про точность за которую вы ужватились все равно никак не приведет к тому, что разница "в разы" окажется.
Согласен. Но это является для меня существенным маркером на тему доверия вашим измерениям. )
K>Допустим. А ваши результаты не совпадают с моими. И не в порядке они, я думаю, у того, кто постоянно скрывает информацию, необходимую для воспроизведения замеров. И это точно не я.
что ли? Ну так там сравниваются не те примеры, которые мы сейчас сравниваем.
Не те, но я абсолютно точно знаю во сколько раз обсуждаемая версия кода на D быстрее измеренной там версии с until.all. А так же вы сами выкладывали тут свои измерения о том, во сколько раз мутабельный код на хаскеле быстрее иммутабельного. Соответственно простейшая пропорция даёт нам преимущество у D кода где-то в 1,8 раза.
K>Решатель есть — вот это да! А у хаскеля тайпчекер и вычислитель есть.
Этого добра везде полно. )))
Re[111]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И какая разница? Вы все равно измеряете скорость работы с мутабельным массивом, а не графом неизменяемых объектов.
Набор не изменяемых объектов создаётся в данном примере в другом месте (на стеке), но вы его в упор не замечаете. А пул используется исключительно для хранения int'ов, а не иммутабельных объектов.
Re[114]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Кстати, а в наших основных делах (которые на C++) конвейеры как раз частенько встречаются. Только они выглядят не совсем так банально. В начале настраивается сложный (и очень эффективный) конвейер, а потом через него в реальном времени гонятся гигабайты. )
То есть всё таки нужны ? Не пойму чтото.
Re[114]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Ты для начала ответь на вопрос — где ты видишь реквест и респонс.
_>Какая разница упакованы параметры в дополнительную структуру или же передаются явно в функцию? )
Нет никакой упаковки и ничего из этого явно не передается в функцию. Так понятно ?
_>Какие ещё Named Pipe, если у нас тут веб-фреймвор со встроенным в него (причём это не опционально, а единственный вариант, но зато такой, что уже никакие nginx'ы в качестве фронтенда не нужны) сервером? )
Вот я и говорю — изобретаете веб.
I>>Не будет никаких страшных прототипов, а будет ровно один параметр.
_>Что за параметр? ) Твой пример показывает передачу значения поля формы в виде параметра функции. Так а что будет в случае нескольких полей?
Обычный объект.
I>>Я и говорю — это изобретение веба. От силы asp.net 1.0, там тоже есть шаблоны, кстати говоря.
_>Шаблоны то и в php есть))) Но не компилируемые (и не на базе статически типизированного нативного языка) в бинарник...
Судя по коду, что ты показал, в тех шаблонах ничего интересного не будет.
Re[115]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, alex_public, Вы писали:
_>>Кстати, а в наших основных делах (которые на C++) конвейеры как раз частенько встречаются. Только они выглядят не совсем так банально. В начале настраивается сложный (и очень эффективный) конвейер, а потом через него в реальном времени гонятся гигабайты. )
I>То есть всё таки нужны ? Не пойму чтото.
В том тестовом проекте на D ни разу не понадобилось. ) Хотя средства организации таких дел в D отличные.
А в наших обычных делах на C++ конвейеры частенько встречаются. Только выглядят несколько иначе — это не какая-то фигня с банальными контейнерами и алгоритмами, а что-то вроде: "renderer<<recorder<<recognizer<<filter<<source; source.play();". Причём это всё работает в нескольких параллельных потока и обрабатывает гигабайты в реальном времени. )
Re[115]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Вот я и говорю — изобретаете веб.
У того же node.js всё буквально точно такое же, только заметно медленее.
I>Обычный объект.
В твоём примере не было никаких объектов, а передавался сразу string. Ну хорошо, пусть будет некий объект. И чем он тогда принципиально отличается от объекта HTTPRequest? )
I>Судя по коду, что ты показал, в тех шаблонах ничего интересного не будет.
Я вообще ничего не показывал на тему шаблонов. Ну а если уж говорить о них, то они опять же точно такие же (потому как просто скопированы оттуда) как в node.js (jade), только вместо JS там D.
Re[116]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Вот я и говорю — изобретаете веб.
_>У того же node.js всё буквально точно такое же, только заметно медленее.
Здесь целых три утверждения и все ложные.
I>>Обычный объект.
_>В твоём примере не было никаких объектов, а передавался сразу string. Ну хорошо, пусть будет некий объект. И чем он тогда принципиально отличается от объекта HTTPRequest? )
Про то и речь — string. Где ты в стринге хочешь найти HTTPRequest ?
_>Я вообще ничего не показывал на тему шаблонов. Ну а если уж говорить о них, то они опять же точно такие же (потому как просто скопированы оттуда) как в node.js (jade), только вместо JS там D.
Jade это аккурат asp.net 1.0, только синтаксического шума меньше — странная идея работать с декларативным представлением императивным способом.
Современные темплейты в JS это, в частности, Angular или Knockout.
Re[117]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Про то и речь — string. Где ты в стринге хочешь найти HTTPRequest ?
Ну так я тебя и спрашиваю, что будет если у нас в форме не одно поле, а десять — функция, у которой в прототипе десять string'ов? )
I>Jade это аккурат asp.net 1.0, только синтаксического шума меньше — странная идея работать с декларативным представлением императивным способом.
Ну расскажи тогда какие сейчас существуют современные способы формирования страниц на сервере.
I>Современные темплейты в JS это, в частности, Angular или Knockout.
Что-то у тебя какая-то каша в голове. Angular и т.п. — это браузерные фреймворки, работающие на клиентских машинах. А мы здесь обсуждаем серверный код. Кстати, в том проекте на D у нас естественно тоже используются некие js фреймворки (только заметно более легковесные, чем Angular) для работы на клиентской машине. Только непонятно какое это всё имеет отношение к серверному коду на D. )
Re[111]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нет, это не классическая архитектура. Это веб давности 15-18 лет, когда ты напрямую читаешь из реквеста и пишешь в респонс. то есть, тупо самый нижний уровень
I>Классика нынче вот такая I>
Здравствуйте, alex_public, Вы писали:
_>Ну так а в Хаскеле то у нас что? )
А в хаскеле у нас вот что: если делать выводы из опыта использования UML с ООЯ с расширениями, то никаких проблем с использованием UML и для хаскеля не будет. Если, конечно, кто-нибудь захочет это сделать.
_>О да, конечно))) И все примеры работы с мутабельными данными из этой темке это конечно же "подтверждают"... )
Ну да. В том и дело, что все примеры кода на хаскеле в этой теме, где работа с мутабельными данными есть, смотрятся не хуже, а даже лучше, чем код на C++/D. Именно потому, что в последних языках полно как всякой синтаксической шелухи, так и костылей, которые в нормальных языках не нужны.
Если сравнивать хаскель с каким-нибудь нормальным языком без контроля эффектов вроде окамла, то там хаскель-код будет хуже выглядеть из-за синтаксического штрафа за монадический/аппликативный код там, где на окамле можно без него обойтись. Но C++-образные языки обычно настолько страшные, что этот самый "синтаксический штраф" все равно погоды не сделает.
_>>>Правда для начала надо доказать полезность подобного. K>>Вам что-ли? _>Ну вот например здесь http://rsdn.ru/forum/philosophy/5420829
кто-то хотя бы попытался привести примеры. Хотя в итоге продемонстрировать ничего не удалось, но хотя бы была попытка. А вот вы, постоянно кидаясь фразой о "контроле эффектов", так ни разу и не привели ни единого примера.
Я, например, приводил примеры преобразований кода, доступных благодаря контролю эффектов. 1) Правда вы забывали о них через два-три поста и утверждали что не было ничего, ничего не было. 2) После многочисленных повторов все-таки называли их выдуманными, что следовало из некоего "отставания в разы", которое никто не измерял. 3) Когда замеры показали, что отставания в разы нет, утверждали что замеры проведены неправильно, потому что должно же быть отставание в разы. 4) В конце концов выяснилось что оптимизации не нужны, потому что комбинации комбинаторов вы никогда не используете. 5) А потом из буфера в n сообщений последние мои посты вытиснились и опять оказалось , что не было ничего, ничего не было.
С учетом этого опыта, я могу только констатировать что ничего ни доказать, ни продемонстрировать я вам не смогу.
K>>Так от вас на обсуждаемую тему тоже ни одного аргумента не поступило.
_>Эммм, а какие аргументы от меня требуются? )
Ладно аргументы — это громко сказано. Вы так ни разу не сказали чем конкретно вам не нравится монадический код и так ни разу и не показали, как такой код по-вашему должен выглядеть. Монады по вашим утверждениям всегда ужасны потому, что ужасны. (на самом деле, наверное, все-таки хаскельная система контроля за эффектами, потому что говоря "монады" вы подразумеваете именно ее)
_>Я же ничего не утверждаю
Вы много чего утверждаете.
K>>Чем они страшнее передачи лямбд через параметры шаблонов в текстовом виде, например? _>1. А какая разница, если всё это компилируется статически и соответственно сообщение об ошибке будет как и для обычной функции?
Разница такая, что это требует "технической обвязки" гораздо более навороченной и страшной, чем контроль эффектов a-la хаскель, который вы считаете абсолютным злом.
_>2. Можно и не текстом (так просто короче на несколько символов). Но компилируется это в тот же самый код.)))
Видимо вы так пишите чтоб мне подыграть и сделать код на ди пострашнее. Понятно-понятно.
_>Нет, в индустрии называют map'ом определённую конструкцию (которая с вашей точки зрения не настоящий map) потому, что она такова в наиболее популярных языках. Вот и всё.
Ну да. В индустрии некоторые виды недомапов называют мапами (а некоторые — не называют) если таковые недомапы вообще есть (в некоторых популярных языках их нет/не было в самом недавнем времени), потому что в индустриальных языках настоящий мап в настоящий момент нереализуем. Это нормальный подход, пока индустриальный разработчик осознает подводные грабли недомапа (и нормальный разработчик как раз их осознает). Похожая история, например с недосложением плавучки, которое из-за неассоциативности строго говоря сложением не является но называется таковым, а прилагающиеся к нему подводные грабли полностью осознаются.
_>Из вашего потока слов я так и не понял, как факт наличия погрешности измерения времени в несколько процентов (хотя на самом деле меньше, но это не принципиально) обосновывает необходимость усреднять результаты
Действительно, откуда следует, что при сравнении интервалов времени, отличающихся на единицы процентов нужно учитывать погрешность измерения времени в единицы процентов? Непонятно.
_>и тем самым учитывать влияние каких-нибудь там сервисных процессов ОС, включившихся не вовремя).
Разумеется, "выбросы" учитывать не надо.
_>Согласен. Но это является для меня существенным маркером на тему доверия вашим измерениям. )
Пока мои факты не совпадают с вашими теориями, моим фактам ничего доверия не добавит. Наоборот, все что угодно будет только убавлять.
K>>Допустим. А ваши результаты не совпадают с моими. И не в порядке они, я думаю, у того, кто постоянно скрывает информацию, необходимую для воспроизведения замеров. И это точно не я. _>О да, я так скрываю, что специально собрал и выложил exe для теста. )))
Который никак не поможет воспроизвести замер.
_>Не те, но я абсолютно точно знаю во сколько раз обсуждаемая версия кода на D быстрее измеренной там версии с until.all.
Вы знаете, насколько 64-х битная версия примера написанная так, чтоб побольше памяти выделять медленнее дишной версии, которая этого не делает. 64-х битная версия по понятным причинам выделяет существенно больше памяти, чем 32-х бинтая, время которой измерял я. С очевидными последствиями для времени выполнения. Кстати, сколько байтов в дишном int на x64? В хаскельном Int — 8.
K>>Решатель есть — вот это да! А у хаскеля тайпчекер и вычислитель есть. _>Этого добра везде полно. )))
Кое-где есть, да. Но в прологе с этим добром дела обстоят очень плохо.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[112]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Набор не изменяемых объектов создаётся в данном примере в другом месте (на стеке), но вы его в упор не замечаете.
Про то, что я это не замечаю — это, конечно, неправда. Мы даже уже осудили смехотворный объем этих размещений выше по ветке.
_>А пул используется исключительно для хранения int'ов, а не иммутабельных объектов.
Замечательно. Как насчет того, чтоб перейти наконец к написанию примера, адекватного поставленной задаче? А то это ваше лирическое отступление уже порядком затянулось.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[112]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>Подобные вещи в vibe.d тоже давно есть, когда из простого класса/интерфейса с аннотациями автоматически генерится REST сервис, просто alex_public их не использует у себя. DM>Пример использования такой генерации клиента и сервера: DM>https://github.com/rejectedsoftware/vibe.d/blob/master/tests/restclient/source/app.d
Ну да, собственно вот http://vibed.org/api/vibe.web.web/registerWebInterface прямо в документации есть подходящий пример. Только вот мне не кажутся удобными эти url'ы, размазанные по всему коду. Гораздо удобнее, когда это всё задаётся в одном месте (в router'е, в главном файле приложения). А уж если приделывать свою автоматическую систему перевода, то вообще ничего хорошего не выйдет с таким подходом.
Re[118]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>Про то и речь — string. Где ты в стринге хочешь найти HTTPRequest ?
_>Ну так я тебя и спрашиваю, что будет если у нас в форме не одно поле, а десять — функция, у которой в прототипе десять string'ов? )
I>>Jade это аккурат asp.net 1.0, только синтаксического шума меньше — странная идея работать с декларативным представлением императивным способом.
_>Ну расскажи тогда какие сейчас существуют современные способы формирования страниц на сервере.
Как бы уже.
I>>Современные темплейты в JS это, в частности, Angular или Knockout.
_>Что-то у тебя какая-то каша в голове.
Не у меня, а у тебя. Ты показал и назвал вещи, котороые родом из прошлого века.
>Angular и т.п. — это браузерные фреймворки, работающие на клиентских машинах.
Правильно. Все что нужно ангуляру — источник данных в любом формате — xml, json и тд.
>А мы здесь обсуждаем серверный код.
Серверный код не должен смешивать данные с их представлением, что бы отдать это клиенту. Идея таких темплейтов аккурат из прошлого века.
Современный веб это отделение данных от их представления, чего в твоих темплейтах нет, ибо сервер отдаёт всё. Поменялась строчка — сервер отдаст новую html страницу. А это как раз и не нужно,.
Re[111]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>А в хаскеле у нас вот что: если делать выводы из опыта использования UML с ООЯ с расширениями, то никаких проблем с использованием UML и для хаскеля не будет. Если, конечно, кто-нибудь захочет это сделать.
Не вижу логической связи между утверждениями в конце фразы и в начале. Фраза теоретически могла бы быть справедливой при одном из двух условий:
1. Хаскель — это ООЯ с расширениями.
2. В ООЯ с расширениями только эти расширения и используют, а классической частью вообще не пользуются.
Но насколько я знаю, оба эти утверждения не верны.
K>Ну да. В том и дело, что все примеры кода на хаскеле в этой теме, где работа с мутабельными данными есть, смотрятся не хуже, а даже лучше, чем код на C++/D. Именно потому, что в последних языках полно как всякой синтаксической шелухи, так и костылей, которые в нормальных языках не нужны. K>Если сравнивать хаскель с каким-нибудь нормальным языком без контроля эффектов вроде окамла, то там хаскель-код будет хуже выглядеть из-за синтаксического штрафа за монадический/аппликативный код там, где на окамле можно без него обойтись. Но C++-образные языки обычно настолько страшные, что этот самый "синтаксический штраф" все равно погоды не сделает.
О, вы уже начинаете признавать то, о чём я говорил всё это время...
И похоже что лучше всего использовать тут в аргументации OCaml (кстати один из моих фаворитов когда-то, но у него такие проблемы с многопоточностью...).
K>Я, например, приводил примеры преобразований кода, доступных благодаря контролю эффектов.
Ну так тогда вас не затруднит кинуть ссылку на конкретное сообщение ваше сообщение? )
K>С учетом этого опыта, я могу только констатировать что ничего ни доказать, ни продемонстрировать я вам не смогу.
Хорошая отмазка. ))) Может тогда стоит вообще прекратить дискуссию? )
K>Ладно аргументы — это громко сказано. Вы так ни разу не сказали чем конкретно вам не нравится монадический код и так ни разу и не показали, как такой код по-вашему должен выглядеть. Монады по вашим утверждениям всегда ужасны потому, что ужасны. (на самом деле, наверное, все-таки хаскельная система контроля за эффектами, потому что говоря "монады" вы подразумеваете именно ее)
А вот как раз это мы действительно уже обсуждали и я уже отвечал) Но могу повториться — мне не нравится что это навязанное ограничение (тем более оно выглядит глупо, т.к. при переходе от академических задач к практике, 90% кода уплывает в монады). Никто не мешал добавить в язык те же самые возможности, но опционально. Как в том же D. Хотя в нём это направление совсем не разработано, но я не вижу никаких теоретических препятствий на пути к достижению в точности хаскелевских результатов, но при этом без всяких "синтаксических пенальти". )
K>Видимо вы так пишите чтоб мне подыграть и сделать код на ди пострашнее. Понятно-понятно.
Ну лично мне кажется, что красивее написать q{a>b} или даже "a>b", но естественно можно и (x, y)=> x>y, если вам почему-то нравится только такой вариант. Как видите опять же полная свобода в языке.
K>Ну да. В индустрии некоторые виды недомапов называют мапами (а некоторые — не называют) если таковые недомапы вообще есть (в некоторых популярных языках их нет/не было в самом недавнем времени), потому что в индустриальных языках настоящий мап в настоящий момент нереализуем. Это нормальный подход, пока индустриальный разработчик осознает подводные грабли недомапа (и нормальный разработчик как раз их осознает). Похожая история, например с недосложением плавучки, которое из-за неассоциативности строго говоря сложением не является но называется таковым, а прилагающиеся к нему подводные грабли полностью осознаются.
Думаю, что часть осознаёт, а часть нет. Однако при этом большинство в любом случае подразумевают один и тот же объект при упоминание данного термина. )))
K>Действительно, откуда следует, что при сравнении интервалов времени, отличающихся на единицы процентов нужно учитывать погрешность измерения времени в единицы процентов? Непонятно.
Если результат измерения производительности будет отличаться на пару процентов, то можно смело считать производительность равной. )))
_>>Не те, но я абсолютно точно знаю во сколько раз обсуждаемая версия кода на D быстрее измеренной там версии с until.all.
K>Вы знаете, насколько 64-х битная версия примера написанная так, чтоб побольше памяти выделять медленнее дишной версии, которая этого не делает. 64-х битная версия по понятным причинам выделяет существенно больше памяти, чем 32-х бинтая, время которой измерял я. С очевидными последствиями для времени выполнения. Кстати, сколько байтов в дишном int на x64? В хаскельном Int — 8.
Ооо, кстати, действительно разница в результатах может быть от игр с разрядностью. Там и компиляторы по разному работают... В идеале надо отдельно проводить два тестирования:
1. компилировать в 32 битный код и запускать на машине с 32 битной ОС. Кстати, свои измерения для D я как раз так и делал.
2. компилировать в 64 битный код и запускать на машине с 64 битной ОС.
Причём результаты могут сильно отличаться. Например, помнится ещё недавно было время, когда gcc ощутимо обгонял VC на 64 битном кода и при этом проигрывал на 32 битном.
Кстати, у компилятора dmd есть ключики: -m32 и -m64. Всё очень удобно.
K>Кое-где есть, да. Но в прологе с этим добром дела обстоят очень плохо.
Ну так в моём то случае это не принципиально, т.к. все подобные вещи решает крутой C++ код, который мы прячем за соответствующими встроенными предикатами. )
Re[113]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Про то, что я это не замечаю — это, конечно, неправда. Мы даже уже осудили смехотворный объем этих размещений выше по ветке.
Объём действительно не большой, т.к. большего для данной задачки и не надо. И его всегда можно увеличить, если очень надо. Но мы в данном случае спорили совсем о другом. Так вы наконец то признаёте, что в том моём решение выделялось около миллиона полноценный иммутабельных объектов? )
Re[119]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
_>>Ну расскажи тогда какие сейчас существуют современные способы формирования страниц на сервере. I>Как бы уже.
Ты показывал пример реакции на ajax запрос. А ты мне покажи где собственно страница создаётся, с которой этот запрос пришёл.
I>Правильно. Все что нужно ангуляру — источник данных в любом формате — xml, json и тд.
Не только. Ещё ему нужно:
1. Как-то оказаться на компьютер пользователя.
2. Иметь декларативное описание (html тэги с их добавками) дизайна страницы.
Или по твоему эти два пункта какой-то магией реализуются? )
I>Современный веб это отделение данных от их представления, чего в твоих темплейтах нет, ибо сервер отдаёт всё. Поменялась строчка — сервер отдаст новую html страницу. А это как раз и не нужно,.
Ну так и чем это плохо на практике? )
Re[120]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
... I>>Современный веб это отделение данных от их представления, чего в твоих темплейтах нет, ибо сервер отдаёт всё. Поменялась строчка — сервер отдаст новую html страницу. А это как раз и не нужно,.
_>Ну так и чем это плохо на практике? )
Точно. Задолбали уже своими макросами.
Re[120]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ты показывал пример реакции на ajax запрос. А ты мне покажи где собственно страница создаётся, с которой этот запрос пришёл.
На клиенте. Клиент получает шаблон, js, css, картинки — всё это статика. Сервер тупо отдаёт статику без какой либо самодеятельности.
_>Не только. Ещё ему нужно: _>1. Как-то оказаться на компьютер пользователя. _>2. Иметь декларативное описание (html тэги с их добавками) дизайна страницы.
Это статика. Её даже полу-сервер на джаваскрипте отдаёт быстрее, чем твоя генерированая по шаблону страница.
I>>Современный веб это отделение данных от их представления, чего в твоих темплейтах нет, ибо сервер отдаёт всё. Поменялась строчка — сервер отдаст новую html страницу. А это как раз и не нужно,.
_>Ну так и чем это плохо на практике? )
Тормоза. Конский трафик. Долгое время обновления UI.
Re[121]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>На клиенте. Клиент получает шаблон, js, css, картинки — всё это статика. Сервер тупо отдаёт статику без какой либо самодеятельности.
ОК, понятно, шаблоны статичные. А на каком языке ты их пишешь? На голом html?
I>Это статика. Её даже полу-сервер на джаваскрипте отдаёт быстрее, чем твоя генерированая по шаблону страница.
А вот и нет. Выдача информации, генерируемой статическим кодом, в сеть работает быстрее, чем поиск информации на диске, чтение её и только потом выдача в сеть. Можно конечно попытаться оптимизировать выдачу статических страниц, разместив их где-то типа ram диска, ну или использовать всякие там memcached... Тогда возможно скорость станет близкой, но всё равно не факт что догонит. Естественно мы говорим о варианте страниц без каких-то дополнительных вычислений (типа обращений к базам данных и т.п.)
I>Тормоза. Конский трафик. Долгое время обновления UI.
Я говорю не о реакциях на нажатия кнопок на странице (отменять ajax глупо, скорее наоборот можно его больше внедрить в браузер), а о первоначальной загрузке страницы. Тебе нравится вариант, в котором грузится статическая страница с шаблоном и js скриптом, которая потом самая запрашивает себе данные. Так вот объясни какие преимущества привносит этот вариант с дополнительным запросом, в сравнение с вариантом, когда у нас отдаётся сразу страница и с шаблоном и с js и с данными (а вот при щелчках на ней уже работает ajax и нет никаких обновлений всей страницы).
Re[122]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>На клиенте. Клиент получает шаблон, js, css, картинки — всё это статика. Сервер тупо отдаёт статику без какой либо самодеятельности.
_>ОК, понятно, шаблоны статичные. А на каком языке ты их пишешь? На голом html?
На каком хочешь, на таком и пиши. Важно, что они отдаюся как статика, а процессятся на клиенте за смешное количество времени.
I>>Это статика. Её даже полу-сервер на джаваскрипте отдаёт быстрее, чем твоя генерированая по шаблону страница.
_>А вот и нет. Выдача информации, генерируемой статическим кодом, в сеть работает быстрее, чем поиск информации на диске, чтение её и только потом выдача в сеть.
Алё — я тебе о чем и говорю — статика отдаётся быстрее всего. Отдавать статику тупо статическим кодом это всего лишь один из сотен возмножных вариантов оптимизации, а есть еще серверные кеши, клиентские, промежуточные, CDN и всякая хрень.
>Можно конечно попытаться оптимизировать выдачу статических страниц, разместив их где-то типа ram диска, ну или использовать всякие там memcached... Тогда возможно скорость станет близкой, но всё равно не факт что догонит.
Не смеши. Ты хочешь процессить шаблон на лету, а это значит, что надо откуда то подтянуть все нужные данные. Наприер из базы и тд. Опаньки !
I>>Тормоза. Конский трафик. Долгое время обновления UI.
_>Я говорю не о реакциях на нажатия кнопок на странице (отменять ajax глупо, скорее наоборот можно его больше внедрить в браузер), а о первоначальной загрузке страницы. Тебе нравится вариант, в котором грузится статическая страница с шаблоном и js скриптом, которая потом самая запрашивает себе данные. Так вот объясни какие преимущества привносит этот вариант с дополнительным запросом, в сравнение с вариантом, когда у нас отдаётся сразу страница и с шаблоном и с js и с данными (а вот при щелчках на ней уже работает ajax и нет никаких обновлений всей страницы).
Очевидно — время первоначальной загрузки меньше. Стилей, скриптов и картинок одинаково в обоих случаях, а моем будет загружен шаблон в пару килобайт, а у тебя полноценный html и чем больше размер страницы, тем сильнее будет тормозить твой вариант.
Re[123]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>На каком хочешь, на таком и пиши. Важно, что они отдаюся как статика, а процессятся на клиенте за смешное количество времени.
Ну так на том же jade их гораздо приятнее писать, даже если они и будут статическими файлами на сервере. Ну и кстати если использовать шаблонизатор типа того, что в vibe.d, то это получается быстрее, чем отдача статического файла!
Т.е. вообще говоря идея в vibe.d не противоречит никакому варианту клиентского программирования. Мы можем хоть страницы с данными генерировать, хоть шаблоны для js фреймворка и реакции на ajax запросы за данными. И это будет в большинстве случаев быстрее аналогичных решений.
_>>А вот и нет. Выдача информации, генерируемой статическим кодом, в сеть работает быстрее, чем поиск информации на диске, чтение её и только потом выдача в сеть. I>Алё — я тебе о чем и говорю — статика отдаётся быстрее всего. Отдавать статику тупо статическим кодом это всего лишь один из сотен возмножных вариантов оптимизации, а есть еще серверные кеши, клиентские, промежуточные, CDN и всякая хрень.
Ты не правильно прочитал фразу... ))) "Выдача информации, генерируемой статическим кодом" — это как раз работа шаблонизатора того фреймворка в D. А "поиск информации на диске, чтение её и только потом выдача в сеть" — это как раз отдача статического файла с диска.
I>Не смеши. Ты хочешь процессить шаблон на лету, а это значит, что надо откуда то подтянуть все нужные данные. Наприер из базы и тд. Опаньки !
Речь была про выдачу статической страницы (в смысле без информации из бд и т.п.), но с помощью шаблонизатора. Если же ты хочешь привлечь сюда и базу данных, то тогда уж сравнивай один такой запрос к шаблонизатору (работающему с бд) с двумя последовательными запросами (в начале за статическим шаблоном, а потом ajax запрос за данными из бд). И весьма сомневаюсь, что сравнение будет в пользу второго варианта...
I>Очевидно — время первоначальной загрузки меньше. Стилей, скриптов и картинок одинаково в обоих случаях, а моем будет загружен шаблон в пару килобайт, а у тебя полноценный html и чем больше размер страницы, тем сильнее будет тормозить твой вариант.
А с чего это ты не учитываешь последующий запрос за данными в твоём варианте? ) Зачем нам нужна страница без данных? )
Re[124]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так на том же jade их гораздо приятнее писать, даже если они и будут статическими файлами на сервере. Ну и кстати если использовать шаблонизатор типа того, что в vibe.d, то это получается быстрее, чем отдача статического файла!
jade это asp.net 1.0 толко без скобочек. Ты точно думаешь, что вещица 13 летней давности это прорыв ?
_>Т.е. вообще говоря идея в vibe.d не противоречит никакому варианту клиентского программирования. Мы можем хоть страницы с данными генерировать, хоть шаблоны для js фреймворка и реакции на ajax запросы за данными. И это будет в большинстве случаев быстрее аналогичных решений.
Нет, не будет.
I>>Алё — я тебе о чем и говорю — статика отдаётся быстрее всего. Отдавать статику тупо статическим кодом это всего лишь один из сотен возмножных вариантов оптимизации, а есть еще серверные кеши, клиентские, промежуточные, CDN и всякая хрень.
_>Ты не правильно прочитал фразу... ))) "Выдача информации, генерируемой статическим кодом" — это как раз работа шаблонизатора того фреймворка в D. А "поиск информации на диске, чтение её и только потом выдача в сеть" — это как раз отдача статического файла с диска.
Покажи, где я говорю что статику надо отдавать не иначе как с диска ? Это ты себе какую то мантру придумал. Статика в большинстве случаев отдаётся напрямую или почти напрямую из RAM, например(например) это варианты кешей.
_>Речь была про выдачу статической страницы (в смысле без информации из бд и т.п.), но с помощью шаблонизатора.
Ты в самом деле думаешь, что генерировать и отдавать конскую страницу это быстрее, чем такую же статическую информацию но в пару килобайт кода ?
>Если же ты хочешь привлечь сюда и базу данных, то тогда уж сравнивай один такой запрос к шаблонизатору (работающему с бд) с двумя последовательными запросами (в начале за статическим шаблоном, а потом ajax запрос за данными из бд). И весьма сомневаюсь, что сравнение будет в пользу второго варианта...
"два последовательных запроса" — тут я смеялся. У тебя и так будут последовательные запросы, например скрипты, стили, картинки.
Если всунешь это в один кусок, внезапно, последующие запросы будут педалить.
А вообще время первого открытие страницы имеет большое значение только для сайтов, которые пользователь открывает раз в год.
_>А с чего это ты не учитываешь последующий запрос за данными в твоём варианте? ) Зачем нам нужна страница без данных? )
Наоборот, я всё учитываю.
Re[125]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>jade это asp.net 1.0 толко без скобочек. Ты точно думаешь, что вещица 13 летней давности это прорыв ?
Ну во-первых не просто без скобочек, ну да ладно, не будем вникать в мелкие детали. А почему обязательно прорыв то? ) Просто удобный инструмент. Это если мы говорим про jade (инструмент из node.js). А если говорить про Diet (аналог jade из vibe.d), то там действительно небольшой прорыв в связи с быстродействием этого решения.
I>Покажи, где я говорю что статику надо отдавать не иначе как с диска ? Это ты себе какую то мантру придумал. Статика в большинстве случаев отдаётся напрямую или почти напрямую из RAM, например(например) это варианты кешей.
Вообще то все http-демоны отдают статику как раз с диска. И решения типа размещения этого диска в оперативке я довольно редко вижу. Чаще применяются прокси между демоном и сетью, кэширующие запросы в оперативке. Но в любом случае это всё чуть уступает по скорости прямой записи как в vibe.d. Ну ты же сам должен понимать это. Смотри, если по показывать по упрощённой аналогии, то аналог обычного сервера это:
Как ты думаешь, какой код эффективнее? ) Да, и понятно что писать код типа 3-го варианта руками — это бред. Но вот если научить компилятор генерировать его автоматически по некоторому удобному шаблону, то...
I>Ты в самом деле думаешь, что генерировать и отдавать конскую страницу это быстрее, чем такую же статическую информацию но в пару килобайт кода ?
Я что-то не понял откуда у нас берётся конская страница, если она по сути состоит из того же шаблона (который на пару килобайт по твоим словам) и тех же данных (которые ты получаешь следующим запросом в твоём варианте).
Re[126]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>jade это asp.net 1.0 толко без скобочек. Ты точно думаешь, что вещица 13 летней давности это прорыв ?
_>Ну во-первых не просто без скобочек, ну да ладно, не будем вникать в мелкие детали. А почему обязательно прорыв то? ) Просто удобный инструмент. Это если мы говорим про jade (инструмент из node.js). А если говорить про Diet (аналог jade из vibe.d), то там действительно небольшой прорыв в связи с быстродействием этого решения.
Нет там никакого прорыва. jade и его аналоги это конец прошлого века. Вещи навроде MVC гораздо более удобны.
I>>Покажи, где я говорю что статику надо отдавать не иначе как с диска ? Это ты себе какую то мантру придумал. Статика в большинстве случаев отдаётся напрямую или почти напрямую из RAM, например(например) это варианты кешей.
_>Вообще то все http-демоны отдают статику как раз с диска.
... _>Как ты думаешь, какой код эффективнее? ) Да, и понятно что писать код типа 3-го варианта руками — это бред. Но вот если научить компилятор генерировать его автоматически по некоторому удобному шаблону, то...
Я вижу, что статика почти с любого сервера отдаётся практически мгновенно, а всё остальное требует времени.
I>>Ты в самом деле думаешь, что генерировать и отдавать конскую страницу это быстрее, чем такую же статическую информацию но в пару килобайт кода ?
_>Я что-то не понял откуда у нас берётся конская страница, если она по сути состоит из того же шаблона (который на пару килобайт по твоим словам) и тех же данных (которые ты получаешь следующим запросом в твоём варианте).
А ты покажи, как ты будешь отдавать и шаблон и данные для него в одном респонсе.
Re[126]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то все http-демоны отдают статику как раз с диска. И решения типа размещения этого диска в оперативке я довольно редко вижу. Чаще применяются прокси между демоном и сетью, кэширующие запросы в оперативке. Но в любом случае это всё чуть уступает по скорости прямой записи как в vibe.d.
ОМГ. А как насчёт отдачи статики без выхода из нулевого кольца? Добро пожаловать в мир http.sys.
Одно переключение в юзермоду для вызова вашего vibe.d будет стоить больше, чем всё время его работы.
Надо понимать, что редкий сайт сейчас хранит гигабайты статики (если мы не говорим про специализированные контент-хостинги); это означает, что коробочная Windows Server 2012 Web Edition способна отдавать HTML быстрее, чем любые ваши интерпретируемые фреймворки.
Искренне советую перед рассуждениями космического масштаба подучить матчасть.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[127]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>А ты покажи, как ты будешь отдавать и шаблон и данные для него в одном респонсе.
теоретически всё можно получить на основе src="data:".
Но на практике я бы повнимательнее присмотрелся к вопросам кэширования: склеивание высокодинамичных (данные) и низкодинамичных (шаблон) видов контента выглядит не очень многообещающе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[127]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Нет там никакого прорыва. jade и его аналоги это конец прошлого века. Вещи навроде MVC гораздо более удобны.
Ты всё время путаешь клиентский код и серверный. И плюс тебе похоже кажется, что возможен только один вариант. Так что в упор не видишь вариантов, о которых я тебе говорю. Вполне реально могут сосуществовать в одном проекте и серверные и клиентские шаблоны. Причём одни могут генерировать другие.
I>А ты покажи, как ты будешь отдавать и шаблон и данные для него в одном респонсе.
А в чём проблема то? ) Вот тебе примерчик простейший на тему шаблонов, данных и т.п:
- data=[]; for(var i=0; i<5; i++) data.push({name: "n"+i, value: "v"+i});
html(ng-app="Test")
head
script(src="angular.js")
script
| angular.module('Test', []).controller('TestCtrl', function($scope){
| $scope.data=!{JSON.stringify(data)};
| });
body(ng-controller="TestCtrl")
ul
li(ng-repeat="d in data")
{{d.name}}:{{d.value}}
Здесь jade шаблон генерирует на сервере страницу, содержащую angular шаблон и данные для него. Да, кстати, а data вполне может быть взято из базы данных (локальной в данном случае, т.к. это серверный код), а не создано на ходу, как в примере.
Re[128]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ты всё время путаешь клиентский код и серверный. И плюс тебе похоже кажется, что возможен только один вариант. Так что в упор не видишь вариантов, о которых я тебе говорю. Вполне реально могут сосуществовать в одном проекте и серверные и клиентские шаблоны. Причём одни могут генерировать другие.
I>>А ты покажи, как ты будешь отдавать и шаблон и данные для него в одном респонсе.
_>А в чём проблема то? ) Вот тебе примерчик простейший на тему шаблонов, данных и т.п:
Проблема в том, шаблон и данные меняются с различной частотой. Данные могут меняться несколько раз в секунду, а шаблон сильно вряд ли будет меняться хотя бы раз в день.
_>Здесь jade шаблон генерирует на сервере страницу, содержащую angular шаблон и данные для него. Да, кстати, а data вполне может быть взято из базы данных (локальной в данном случае, т.к. это серверный код), а не создано на ходу, как в примере.
То есть, ты собираешься каждый раз вместе с данными отдавать еще и шаблон, и скрипты и прочую хрень ?
Re[127]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>ОМГ. А как насчёт отдачи статики без выхода из нулевого кольца? Добро пожаловать в мир http.sys. S>Одно переключение в юзермоду для вызова вашего vibe.d будет стоить больше, чем всё время его работы. S>Надо понимать, что редкий сайт сейчас хранит гигабайты статики (если мы не говорим про специализированные контент-хостинги); это означает, что коробочная Windows Server 2012 Web Edition способна отдавать HTML быстрее, чем любые ваши интерпретируемые фреймворки.
О, ну так раз вы так разбираетесь, то конечно же без проблем озвучите среднее время необходимое на переключение в нулевое кольцо и среднее время необходимое для считывания одного кластера данных со стандартного жёсткого диска? )
S>Искренне советую перед рассуждениями космического масштаба подучить матчасть.
Ага, ага. Видимо её надо подучить и подавляющему большинству проектировщиков высоконагруженных систем, т.к. они все почему-то сидят на nginx или собственных велосипедах, а не на "Windows Server 2012 Web Edition". )
Re[129]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Проблема в том, шаблон и данные меняются с различной частотой. Данные могут меняться несколько раз в секунду, а шаблон сильно вряд ли будет меняться хотя бы раз в день.
Ну так а следующие запросы к данным же идут через ajax, а не через обновление страницы. )
Re[130]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Проблема в том, шаблон и данные меняются с различной частотой. Данные могут меняться несколько раз в секунду, а шаблон сильно вряд ли будет меняться хотя бы раз в день.
_>Ну так а следующие запросы к данным же идут через ajax, а не через обновление страницы. )
То есть, писать нужно всё, что и в моём случае, плюс дополнительную страницу, которая будет перезагружаться каждый раз когда юзер будет открывать закладку. Экономия, теоретически, от силы пару секунд на первом посещении сайта.
Это если использовать Ангуляр. А что твоими темплейтами ? Они ведь "как jade", то есть ничего подобного ангуляру не умеют и работают на сервере.
Re[131]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, писать нужно всё, что и в моём случае, плюс дополнительную страницу, которая будет перезагружаться каждый раз когда юзер будет открывать закладку. Экономия, теоретически, от силы пару секунд на первом посещении сайта.
Не дополнительную — начальная страница нужна и в твоём варианте. Вопрос только в том, размещаем мы в ней собственно данные или же она является статическим шаблоном.
I>Это если использовать Ангуляр. А что твоими темплейтами ? Они ведь "как jade", то есть ничего подобного ангуляру не умеют и работают на сервере.
Ещё раз, фреймворк vibe.d не имеет никакого отношения к работе на клиенте. Так же как скажем и node.js. Это серверный фреймворк, который может работать в паре с любым клиентским js фреймворком (а можно и вообще без него в случае простого отображения).
Re[128]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>О, ну так раз вы так разбираетесь, то конечно же без проблем озвучите среднее время необходимое на переключение в нулевое кольцо и среднее время необходимое для считывания одного кластера данных со стандартного жёсткого диска? )
на P4 переключение колец занимает ~500 тактов. Переключений между tcpip.sys и vibe.d будет несколько — детали зависят от того, что написано в коде страницы.
Считывание одного кластера с типичного винта — 5мс. Нерелевантно обсуждаемому вопросу, т.к. cache miss может случиться как для статики, так и для динамики (ведь скрипт откуда-то берётся, правда?). Речь идёт об отдаче контента из прогретого кэша, когда важен каждый context switch. В https.sys при наличии респонса в кэше его адрес, грубо говоря, напрямую уезжает в DMA для отправки в сетевую карту. Порвать его по производительности при помощи велосипеда — дохлый номер.
_>Ага, ага. Видимо её надо подучить и подавляющему большинству проектировщиков высоконагруженных систем, т.к. они все почему-то сидят на nginx или собственных велосипедах, а не на "Windows Server 2012 Web Edition". )
По лицензионным, а не архитектурным соображениям. И кроме nginx есть ещё несколько решений. Вообще, их существование в основном обеспечено крайне позорной архитектурой апача — дефолтного веб сервера в линукс мире. Про велосипеды у меня есть мнение, но оно нецензурное, и озвучивать я его не буду.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[127]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Одно переключение в юзермоду для вызова вашего vibe.d будет стоить больше, чем всё время его работы. S>Надо понимать, что редкий сайт сейчас хранит гигабайты статики (если мы не говорим про специализированные контент-хостинги); это означает, что коробочная Windows Server 2012 Web Edition способна отдавать HTML быстрее, чем любые ваши интерпретируемые фреймворки.
Не надо переоценивать хаки в Windows. А отдача HTML прямо из ядра — это ни что иное, как грязный хак.
Nginx использует намного более вменяемую архитектуру — чтение и разбор HTTP-заголовка требует примерно одного системного вызова (чтение пары килобайт в буфер в userspace). Затем если nginx внутри себя находит закэшированные данные, то он их отдаёт в сокет через sendfile (в Винде есть аналог TransmitFile). Данные идут прямо из страниц файлового кэша — быстрее некуда.
Есть ещё HAProxy, специально заточенный на передвижение гигабайтов данных. Там используется чуть более продвинутый системный вызов — splice(2). В результате, при использовании карт с TCP Segmentation Offload и правильным DMA можно коммутировать потоки по 10Гб на одном ядре: http://www.haproxy.org/#perf ( http://www.haproxy.org/10g.html )
Это НАМНОГО более прямой подход, так как единственно критичный по скорости примитив (передача потенциально большого буфера) ускоряется с помощью специализированного механизма, доступного всем. Так что я могу реализовать свой протокол (SPDY или HTTP2), который будет сравним в скорости с http.sys, не дожидаясь пока Microsoft проснётся.
Sapienti sat!
Re[128]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Cyberax, Вы писали:
C>Это НАМНОГО более прямой подход, так как единственно критичный по скорости примитив (передача потенциально большого буфера) ускоряется с помощью специализированного механизма, доступного всем. Так что я могу реализовать свой протокол (SPDY или HTTP2), который будет сравним в скорости с http.sys, не дожидаясь пока Microsoft проснётся.
Давайте вернёмся на шаг назад.
Обсуждается вопрос скорости отдачи в HTTP статики по сравнению со скриптовыми фреймворками. Вопрос передачи гигабайтных пакетов по TCP/IP тут неинтересен — мы не будем переизобретать веб.
Речь идёт не о типичном для соврменных веб-приложений ворклоаде: миллионы запросов, где response size в пределах десятка-сотни килобайт.
Вот, собственно, релевантный кусок чуши:
Вообще то все http-демоны отдают статику как раз с диска. И решения типа размещения этого диска в оперативке я довольно редко вижу. Чаще применяются прокси между демоном и сетью, кэширующие запросы в оперативке. Но в любом случае это всё чуть уступает по скорости прямой записи как в vibe.d.
Я пытаюсь объяснить, что "отдача статики с диска" — адски оптимизированная операция. Есть разные стратегии оптимизации — http.sys, сплайсы, sendfile.
Порвать это при помощи шаблонизатора с "прямой записью" — дохлый номер.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[132]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Ikemefula, Вы писали:
I>>То есть, писать нужно всё, что и в моём случае, плюс дополнительную страницу, которая будет перезагружаться каждый раз когда юзер будет открывать закладку. Экономия, теоретически, от силы пару секунд на первом посещении сайта.
_>Не дополнительную — начальная страница нужна и в твоём варианте. Вопрос только в том, размещаем мы в ней собственно данные или же она является статическим шаблоном.
Именно дополнительную. У меня эта страница просто статика, а тебе надо писать код что бы её отдавать.
I>>Это если использовать Ангуляр. А что твоими темплейтами ? Они ведь "как jade", то есть ничего подобного ангуляру не умеют и работают на сервере.
_>Ещё раз, фреймворк vibe.d не имеет никакого отношения к работе на клиенте. Так же как скажем и node.js. Это серверный фреймворк, который может работать в паре с любым клиентским js фреймворком (а можно и вообще без него в случае простого отображения).
У меня ощущение что ты не читаешь. Я как раз и говорю про "не имеет никакого отношения к работе на клиенте"
Покажи как ты будешь отдавать свои темплейты которые "никакого отношения к работе на клиенте" да вместе с данными.
P.S. Node.js это просто платформа, не надо её тащить этот баззворд во все мессаги, это базовый функционал операционной системы. node.js может и умеет рабоать по разному. Шаблоны можно процессить на сервере ,а можно и на клиенте. Оба варианта ничем не противоречат node.js
Re[112]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Не вижу логической связи между утверждениями в конце фразы и в начале. Фраза теоретически могла бы быть справедливой при одном из двух условий: _>1. Хаскель — это ООЯ с расширениями. _>2. В ООЯ с расширениями только эти расширения и используют, а классической частью вообще не пользуются. _>Но насколько я знаю, оба эти утверждения не верны.
Нет, ни первого ни второго для этого не нужно. Достаточно чтоб все, что требовалось для отображения на диаграммах хаскеля покрывалось средствами испытанными в разных языках с расширениями ООП. А так оно и есть.
_>О, вы уже начинаете признавать то, о чём я говорил всё это время...
Я это и сказал в самом начале.
Я не согласен, что это выглядит намного страшнее, чем в других языках (если не считать упомянутые мной "карательные" наименования, которые легко исправить). Монадический код часто, но не всегда, требует синтаксической обвязки для "стыковки" в отличие от функций вида a -> b в хаскеле, и потому код с мутабельными ссылками/массивами может выглядеть многословнее, чем хаскель-код с иммутабельными. Но в большинстве языков обычно наворочено столько синтаксического мусора без всякого смысла вообще, что на этом фоне и монадический хаскель-код выглядит вполне пристойно. <...>
Т.е. раз у хаскеля нерастраченный на всякую ерунду синтаксический бюджет — какие-то редкие уродства погоды не делают, особенно если сравнивать с языком, сыплющим всюду синтаксический мусор лопатой. Поскольку С++ как раз такой, код на нем даже в тех областях, где он силен смотрится страшнее, чем хаскель-код, демонстрирующий самые неприглядные стороны хаскеля.
Гипотетическую возможность сделать синтаксис лучше, чем в хаскеле я, разумеется, не отрицаю.
<...>
Я пишу не о том, что код синтаксически лучше выглядит в какой-то другой области, а о том, что даже тот самый код, про который вы говорите "весь в большой монаде", если я, конечно, правильно понял, что вы имели в виду, синтаксически лучше, чем код на типичном императивном языке, синтаксис которого как будто придуман, чтоб покарать любого, кто захочет на этом языке что-то написать, не говоря уж о том, чтоб прочесть.
_>И похоже что лучше всего использовать тут в аргументации OCaml (кстати один из моих фаворитов когда-то
OCaml, конечно, лучше подавляющего большинства языков, и устаревший по сравнению с языками, которые можно по пальцам если не одной, то двух рук точно пересчитать (причем подавляющее большинство помимо авторов никто не знает). Это, однако, больше говорит не о качествах окамла, а о плачевном положении в области разработки языков и об удручающей неграмотности и узком кругозоре типичного автора языка программирования.
_>но у него такие проблемы с многопоточностью...
Окамл приличный язык, но именно и только как язык. Про имплементацию окамла и особенно его рантайм сказать что-то хорошее уже труднее, разве что она все равно лучше, чем у большинства так называемых "динамических языков", но на фоне скриптов что угодно хорошо смотрится. Вообще создание нормального рантайма неподъемная по требуемым человекочасам задача для типичного коллектива, разрабатывающего ФЯ.
_>Ну так тогда вас не затруднит кинуть ссылку на конкретное сообщение ваше сообщение? )
K>>С учетом этого опыта, я могу только констатировать что ничего ни доказать, ни продемонстрировать я вам не смогу. _>Хорошая отмазка. )))
Это констатация фактов.
_>Может тогда стоит вообще прекратить дискуссию? )
Дискуссию на заявленные темы мы еще и не начали. Вообще, дискуссия предполагает 1) реакцию на ответ, а не полное его игнорирование и простое повторение вопроса, на который уже ответили. 2) адекватную реакцию на вопрос, а не ответ на вопрос, который никто не задавал.
_>А вот как раз это мы действительно уже обсуждали и я уже отвечал) Но могу повториться — мне не нравится что это навязанное ограничение (тем более оно выглядит глупо, т.к. при переходе от академических задач к практике, 90% кода уплывает в монады).
Как раз наоборот, при написании вычислителей факториалов и чисел Фибоначчи хаскель не имеет принципиального преимущества перед ML-ями. Ну ладно, имеет благодаря ленивости, и это даже в некотором смысле благодаря IO, но сейчас разговор не об этом. При работе с таким кодом и в ML-ях применим equational reasoning (с оговорками, но это и в хаскеле так, их там немногим меньше), и вообще это, в основном, хороший ФП код.
Совсем другое дело, когда дело доходит до решения системных задач. Тут разница принципиальна и выразительность и контроль над сложностью у хаскеля существенно выше, чем у языков, где контроля эффектов нет. Потому, что в хаскеле эффекты первоклассны, типизированны (не достаточно легковесно, правда) и комбинируемы (с оговорками, как принципиального характера, так и связанными с убогостью хаскеля — его системы типов в первую очередь). Поймите меня правильно, система контроля за эффектами хаскеля имеет множество недостатков, критиковать ее можно и нужно, но с позиции других, превосходящих систем контроля за эффектами, а не с позиции отсутствия такой системы. Тут разница, как между языками типизированными и бестиповыми — это разные лиги, тут даже сравнивать нечего.
_>Никто не мешал добавить в язык те же самые возможности, но опционально.
В данном случае практически значимой разницы между "опциональность" и "отсутствие возможности" нет.
_>Как в том же D. Хотя в нём это направление совсем не разработано,
Ну так в том и дело, что нет никакого использования сведений о чистоте рантаймом, например.
_>но я не вижу никаких теоретических препятствий на пути к достижению в точности хаскелевских результатов,
Достижение хаскельных результатов затруднительно хотя-бы потому, что не планируется.
Хорошая функция вычисляет факториал — она ведет себя как функция. Мы можем как-то о ней рассуждать и т.д. "Нехорошая функция" возвращает случайное число. Она не только сама не функция, и не позволяет о себе рассуждать но и заражает все, где используется. Делает все функции с которыми контактирует "нехорошими". Хуже того, она еще и труднораспознаваема и претворяется хорошей.
Одна из основных инноваций хаскеля и задумка авторов как раз в том, чтоб "нехороших функций" вообще не было. И не в том смысле в каком это было до хаскеля, когда было просто нельзя делать что-то. Хорошие функции могут делать все то же самое, что и "плохие функции", но при этом остаются хорошими. Все функции хорошие (точнее, считаются таковыми).
Т.е. хаскель делался не для красивого вычисления факториалов — это просто и почти везде возможно, а для того, чтоб о функциях, делающих что-то полезное, можно было рассуждать как о функциях в математическом смысле. В языках без контроля эффектов такая возможность, начинаясь с факториалов как в хаскеле, на факториалах же и заканчивается.
Тут нужно скорректировать утверждение, потому что система контроля эффектов в Ди есть, она позволяет отличать "хорошую" функцию от "плохой", но достижение состояния "все хорошие" не предполагается. Функция putStrLn в хаскеле — "хорошая". В Ди ее аналог не может быть "хорошей", хотя то, что она "плохая" можно проверить во время компиляции.
_>но при этом без всяких "синтаксических пенальти". )
В подходе как в Ди пенальти все равно есть — это аннотации чистоты.
_>Ну лично мне кажется, что красивее написать q{a>b} или даже "a>b", но естественно можно и (x, y)=> x>y, если вам почему-то нравится только такой вариант. Как видите опять же полная свобода в языке.
Мне не нравится, не это, а вот это:
bool WhileAny(string F1, string F2, T)(immutable T[] a, T v, int i=0)
{
if(i>=a.length||binaryFun!F1(a[i], v)) return false;
if(binaryFun!F2(a[i], v)) return true;
return WhileAny!(F1, F2)(a, v, i+1);
}
_>Думаю, что часть осознаёт, а часть нет.
Это только та часть не осознает, которая конвейеры не использует.
_>Однако при этом большинство в любом случае подразумевают один и тот же объект при упоминание данного термина. )))
С этим у мейнстрим-терминологии как раз проблемы. Когда два мейнстрим-программиста используют один термин, можно вполне рассчитывать на то, что подразумевают они разные объекты.
_>Если результат измерения производительности будет отличаться на пару процентов, то можно смело считать производительность равной. )))
Да можно и при 10% равной считать.
_>Ооо, кстати, действительно разница в результатах может быть от игр с разрядностью. Там и компиляторы по разному работают...
Тут большее значение имеет не то, что компиляторы по разному компилируют (на x64 регистров больше и т.д.) а то, что на x64 программа на хаскеле просто выделяет больше памяти из-за того, что "нативные" типы там всегда равны машинному слову и все "объекты" соотвествующим образом выровнены в памяти. На практически важный вопрос о том, что из себя int в Ди на x64 представляет вы, кстати, не ответили.
_>В идеале надо отдельно проводить два тестирования: _>1. компилировать в 32 битный код и запускать на машине с 32 битной ОС. Кстати, свои измерения для D я как раз так и делал. _>2. компилировать в 64 битный код и запускать на машине с 64 битной ОС.
Не вижу смысла в замерах на 32 битной виндоус. Достаточно разные рерсии на 64-х битной запускать.
И тут еще забавно, что на первоначальное мое предложение замерять релевантные примеры в двух версиях (32 и 64) вы ответили, что слишком много работы, а к замерам разных версий совершенно нерелевантных примеров с таким энтузиазмом отнеслись. Вы для начала напишите пример соответствующий заданию и его измерьте.
_>Ну так в моём то случае это не принципиально, т.к. все подобные вещи решает крутой C++ код, который мы прячем за соответствующими встроенными предикатами. )
Пролог в качестве встроенного ДСЛ — это уже другая история. Но говорить о какой-то особой можности пролога как ЯП общего назначения — достаточно смешно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[114]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Объём действительно не большой
Ну так о чем тогда разговор? Все эти размещения — на грани погрешности измерения. То, что тест действительно измеряет — скорость изменения мутабельного массива, т.е. к поддержке иммутабельности никакого отношения не имеет.
_>т.к. большего для данной задачки и не надо.
Надо. Прямо в формулировке задачи и написано что надо больше.
_>И его всегда можно увеличить, если очень надо.
Ну так увеличте до 300 гигов и посмотрим, 1) уменьшит ли этот объем оптимизации до 16 2) с какой скоростью все будет работать при 16 ГБ иммутабельных объектов.
_>Но мы в данном случае спорили совсем о другом. Так вы наконец то признаёте, что в том моём решение выделялось около миллиона полноценный иммутабельных объектов? )
С самого начала признавал, что некая нагрузка на память размещением ничтожного числа "иммутабельных" (довольно сложно считать объект иммутабельным, если он ссылку на мутабельный массив хранит) объектов тут имитируется, но на производительность примера это все почти никак не влияет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[129]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>на P4 переключение колец занимает ~500 тактов. Переключений между tcpip.sys и vibe.d будет несколько — детали зависят от того, что написано в коде страницы. S>Считывание одного кластера с типичного винта — 5мс.
Ага, т.е. даже считывание одного кластера (а обращений к диску будет много — см. ниже) в десятки раз затратнее, чем переключение в нулевое кольцо.
S>Нерелевантно обсуждаемому вопросу, т.к. cache miss может случиться как для статики, так и для динамики (ведь скрипт откуда-то берётся, правда?).
Нет, в случае vibe.d "скрипт" — это нативный бинарный код, вкопилированный в http сервер.
S>Речь идёт об отдаче контента из прогретого кэша, когда важен каждый context switch. В https.sys при наличии респонса в кэше его адрес, грубо говоря, напрямую уезжает в DMA для отправки в сетевую карту. Порвать его по производительности при помощи велосипеда — дохлый номер.
Только вот http серверы то так не работают... Для начала они должны определить местанохождение целевого файла (а для этого обычно надо прочитать с диска и исполнить всякие конфиги, типа .htaccess с rewrite правилами), проверить его наличие (а иначе выдать сообщение об ошибке) и соблюдение прав доступа. И только после всего этого можно давать команду на его отправку сеть. Сколько у нас тут набирается обращений к диску? ))) И кстати, даже если взять самый упрощённый сервер вообще без изменяемых конфигов и т.п., то всё равно потребуется не один запрос, т.к. поработать с файловой системой всё равно придётся. )
S>По лицензионным, а не архитектурным соображениям. И кроме nginx есть ещё несколько решений. Вообще, их существование в основном обеспечено крайне позорной архитектурой апача — дефолтного веб сервера в линукс мире. Про велосипеды у меня есть мнение, но оно нецензурное, и озвучивать я его не буду.
Гугловские велосипеды тоже подходят под нецензурное? )
Re[133]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Именно дополнительную. У меня эта страница просто статика, а тебе надо писать код что бы её отдавать.
В том то и дело, что не надо. Ну если конечно ты не называешь кодом jade шаблон. Просто многие используют их и для генерации статики, потому что намного удобнее работать с ним, чем с чистым html. Т.е. грубо говоря, если сами шаблоны мы делаем на jade (или аналоге), то с помощью vibe.d переделка статики в динамику будет стоить ровно 0 усилий.
I>Покажи как ты будешь отдавать свои темплейты которые "никакого отношения к работе на клиенте" да вместе с данными.
Не понял, какие шаблоны ты хочешь увидеть и где? )
I>P.S. Node.js это просто платформа, не надо её тащить этот баззворд во все мессаги, это базовый функционал операционной системы. node.js может и умеет рабоать по разному. Шаблоны можно процессить на сервере ,а можно и на клиенте. Оба варианта ничем не противоречат node.js
Естественно. Только вот работа на клиенте находится уже не в компетенции node.js (так же как и вне компетенции vibe.d).
Re[113]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Нет, ни первого ни второго для этого не нужно. Достаточно чтоб все, что требовалось для отображения на диаграммах хаскеля покрывалось средствами испытанными в разных языках с расширениями ООП. А так оно и есть.
Только т.к. в этих языках это является мелкими дополнениями вокруг главного ядра uml, то в Хаскеле мы соответственно только эту обёртку и получим, без всей мощи ядра. И это ещё речь только про одну (пусть и главную) структурную диаграмму, а у главных диаграмм поведение с Хаскелем вообще нет шансов (ну это мы уже обсудили, я просто напоминаю, а то вы же не уточняете выше, что говорите только про диаграмму классов).
_>>Ну так тогда вас не затруднит кинуть ссылку на конкретное сообщение ваше сообщение? ) K>Ну вот об этом я и говорю. Ведь мы же эти преобразования буквально в предыдущем посте обсуждали. K>http://rsdn.ru/forum/philosophy/5624883.1
Так это вы про map p.q говорили? ))) Дааа, бедненько с примерами... Ну и кстати в случае map'а я так и не увидел примера практической пользы от контроля эффектов в данном случае.
_>>Как в том же D. Хотя в нём это направление совсем не разработано, K>Ну так в том и дело, что нет никакого использования сведений о чистоте рантаймом, например.
Это как-то доказывает теоретическую невозможность повторения всех возможностей Хаскеля, но без обязательности ограничений (и соответственно без синтаксического пенальти)?
K>Это только та часть не осознает, которая конвейеры не использует.
Конвейеры очень разные бывают...
_>>Если результат измерения производительности будет отличаться на пару процентов, то можно смело считать производительность равной. ))) K>Да можно и при 10% равной считать.
Тогда к чему разговор о "страшной" погрешности измерения в 2% и обоснование этим усреднения результатов, вместо выборки минимального?
K>Тут большее значение имеет не то, что компиляторы по разному компилируют (на x64 регистров больше и т.д.) а то, что на x64 программа на хаскеле просто выделяет больше памяти из-за того, что "нативные" типы там всегда равны машинному слову и все "объекты" соотвествующим образом выровнены в памяти. На практически важный вопрос о том, что из себя int в Ди на x64 представляет вы, кстати, не ответили.
В D int равен 32 битам. И дело не только в регистрах, а просто в том что разные алгоритмы используются (с разной степенью вылизанности).
K>Не вижу смысла в замерах на 32 битной виндоус. Достаточно разные рерсии на 64-х битной запускать.
Так 32 битный код имеет пенальти на 64 битной системе. Лучше измерять по чистому, тем более если задача такова, что 32 битный код может оказаться абсолютным лидером в сравнение. )
K>И тут еще забавно, что на первоначальное мое предложение замерять релевантные примеры в двух версиях (32 и 64) вы ответили, что слишком много работы, а к замерам разных версий совершенно нерелевантных примеров с таким энтузиазмом отнеслись. Вы для начала напишите пример соответствующий заданию и его измерьте.
Ну так в начале была речь просто о каких-то измерениях — лень естественно. А потом пошло уже несоответствие (причём не в процентах, а принципиальное!) в разных результатах измерений — с таким уже любопытно разобраться. Откуда взялось и т.п.
K>Пролог в качестве встроенного ДСЛ — это уже другая история. Но говорить о какой-то особой можности пролога как ЯП общего назначения — достаточно смешно.
Зато поработав с ним сразу ощущается что такое настоящий высокий уровень... )
Re[115]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну так увеличте до 300 гигов и посмотрим, 1) уменьшит ли этот объем оптимизации до 16 2) с какой скоростью все будет работать при 16 ГБ иммутабельных объектов.
Я не очень понимаю смысл в гонке виртуальных гигабайтов. Но если вы так хотите... Я там поставил счётчик в операторе ~ и получил, что суммарно он выделил в том нашем тесте 2323609629564 байт. Так кто тут у нас отстающий по виртуальным выделениям? )))
K>С самого начала признавал, что некая нагрузка на память размещением ничтожного числа "иммутабельных" (довольно сложно считать объект иммутабельным, если он ссылку на мутабельный массив хранит) объектов тут имитируется, но на производительность примера это все почти никак не влияет.
Я не про нагрузку на память, а про принципиальный факт использования иммутабельных объектов. А то ведь вы помнится и с этим спорили...
Re[113]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Ну лично мне кажется, что красивее написать q{a>b} или даже "a>b", но естественно можно и (x, y)=> x>y, если вам почему-то нравится только такой вариант. Как видите опять же полная свобода в языке.
K>Мне не нравится, не это, а вот это: K>
Здравствуйте, alex_public, Вы писали:
_>В том то и дело, что не надо. Ну если конечно ты не называешь кодом jade шаблон. Просто многие используют их и для генерации статики, потому что намного удобнее работать с ним, чем с чистым html. Т.е. грубо говоря, если сами шаблоны мы делаем на jade (или аналоге), то с помощью vibe.d переделка статики в динамику будет стоить ровно 0 усилий.
Каким образом динамика на серверной стороне будет стоить 0 усилий ?
I>>Покажи как ты будешь отдавать свои темплейты которые "никакого отношения к работе на клиенте" да вместе с данными.
_>Не понял, какие шаблоны ты хочешь увидеть и где? )
Те что "как jade", про которые ты говорил или vibe.d.
_>Естественно. Только вот работа на клиенте находится уже не в компетенции node.js (так же как и вне компетенции vibe.d).
Это как бы очевидно, потому совершенно не ясно, для чего ты тащишь баззворд в каждое сообщение.
Re[130]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>Речь идёт об отдаче контента из прогретого кэша, когда важен каждый context switch. В https.sys при наличии респонса в кэше его адрес, грубо говоря, напрямую уезжает в DMA для отправки в сетевую карту. Порвать его по производительности при помощи велосипеда — дохлый номер.
_>Только вот http серверы то так не работают...
И давно IIS перестал быть http сервером ?
>Для начала они должны определить местанохождение целевого файла (а для этого обычно надо прочитать с диска и исполнить всякие конфиги, типа .htaccess с rewrite правилами), проверить его наличие (а иначе выдать сообщение об ошибке) и соблюдение прав доступа.
Один раз, потом все это попадает в кеш и далее смотри у Синклера после "при наличии респонса в кеше"
> И только после всего этого можно давать команду на его отправку сеть. Сколько у нас тут набирается обращений к диску? ))) И кстати, даже если взять самый упрощённый сервер вообще без изменяемых конфигов и т.п., то всё равно потребуется не один запрос, т.к. поработать с файловой системой всё равно придётся. )
Судя по нагрузочным тестам, мой HDD каким то образом ухитряется читать кластеры за 0мс. Не подскажешь, что за чудо ? И да, "кластеры", это не ошибка.
_>Гугловские велосипеды тоже подходят под нецензурное? )
У гугла нет велосипедов и все работает очень похоже на http.sys, только в профиль.
Re[130]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, в случае vibe.d "скрипт" — это нативный бинарный код, вкопилированный в http сервер.
Вы понимаете, что если у нас весь контент сайта весит 1GB, то нативного бинарного кода, "вкомпилированного в http сервер", будет тоже 1GB + исполняемый код? И что дисковая активность в обоих случаях определяется соотношением этого размера и размера доступной памяти? Или вы те уроки в школе, где рассказывали про swap и виртуальную память, прогуляли?
_>Только вот http серверы то так не работают... Для начала они должны определить местанохождение целевого файла (а для этого обычно надо прочитать с диска и исполнить всякие конфиги, типа .htaccess с rewrite правилами), проверить его наличие (а иначе выдать сообщение об ошибке) и соблюдение прав доступа.
Ещё раз: мы говорим о прогретом кэше. В этом случае всё, что "проверяет" веб-сервер — это наличие готового response в памяти. После чего отдаёт адрес этого response в драйвер http или tcp, который без участия CPU запихивает респонс в сеть. _>И только после всего этого можно давать команду на его отправку сеть. Сколько у нас тут набирается обращений к диску? ))) И кстати, даже если взять самый упрощённый сервер вообще без изменяемых конфигов и т.п., то всё равно потребуется не один запрос, т.к. поработать с файловой системой всё равно придётся. )
Столько обращений к диску, сколько произошло cache miss. В современном мире это часто означает "никогда".
_>Гугловские велосипеды тоже подходят под нецензурное?
Не переживайте — рядовому разработчику достичь уровня гугловских велосипедов не светит.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Каким образом динамика на серверной стороне будет стоить 0 усилий ?
Ну так если статические страницы генерируются у нас jade'ом (где-то на компьютере разработчика) и потом отдаются с сервера каким-нибудь nginx'ом, то переход к динамике с помощью vibe.d не будет стоить практически ничего.
I>Те что "как jade", про которые ты говорил или vibe.d.
Так я же уже показывал или там было что-то непонятное?
_>>Естественно. Только вот работа на клиенте находится уже не в компетенции node.js (так же как и вне компетенции vibe.d). I>Это как бы очевидно, потому совершенно не ясно, для чего ты тащишь баззворд в каждое сообщение.
Потому как я не пойму с чего ты постоянно приплетаешь клиентские js фреймворки в тему про vibe.d.
Re[131]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Вы понимаете, что если у нас весь контент сайта весит 1GB, то нативного бинарного кода, "вкомпилированного в http сервер", будет тоже 1GB + исполняемый код? И что дисковая активность в обоих случаях определяется соотношением этого размера и размера доступной памяти? Или вы те уроки в школе, где рассказывали про swap и виртуальную память, прогуляли?
Ну во-первых как раз размеры то у шаблонизаторов и результатов их работы по любому разные и в таком диком случае это явно очень хорошо проявилось бы. Но мне по любому сложно представить себе нормальный сайт с гигабайтом статических html страниц, так что боюсь это в любом случае гипотетические рассуждения. )))
S>Ещё раз: мы говорим о прогретом кэше. В этом случае всё, что "проверяет" веб-сервер — это наличие готового response в памяти. После чего отдаёт адрес этого response в драйвер http или tcp, который без участия CPU запихивает респонс в сеть.
Вы собственно про какой кэш то? ) Если про аппаратный в дисках, то это действительно очень эффективная вещь, только вот маленький он. А если вы про некое подобие, организуемое операционной системой в оперативной памяти, то тут уже совершенно другой расклад. Причём в случае винды там совсем всё мрачно... )))
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Каким образом динамика на серверной стороне будет стоить 0 усилий ?
_>Ну так если статические страницы генерируются у нас jade'ом (где-то на компьютере разработчика) и потом отдаются с сервера каким-нибудь nginx'ом, то переход к динамике с помощью vibe.d не будет стоить практически ничего.
Это враньё.
I>>Те что "как jade", про которые ты говорил или vibe.d.
_>Так я же уже показывал или там было что-то непонятное?
Ты ничего не показал. Я вот никак не могу понять, что же будет отдаваться на клиент — html со всеми данными, просто темплейт или какие то данные вместе с темплейтом.
Судя по твоим косвенным намёкам, отдавать надо Html со всеми данными. А это, внезапно, исключает 90% оптимизаций. А следовательно "не будет стоить практически ничего" есть просто враньё.
I>>Это как бы очевидно, потому совершенно не ясно, для чего ты тащишь баззворд в каждое сообщение.
_>Потому как я не пойму с чего ты постоянно приплетаешь клиентские js фреймворки в тему про vibe.d.
Для сравнения. Работа с темплейтами на клиенте означает, что серверу надо исключительно данные отдавать.
Если на серверве, то отдавать надо в сотни раз больше чисто из за того, что данные унуте html. Кроме того, это вызывает проблемы например с кешированием, делает невозможным использование большинтсва других оптимизаций. Например, CDN тебе так же не поможет.
Re[132]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну во-первых как раз размеры то у шаблонизаторов и результатов их работы по любому разные и в таком диком случае это явно очень хорошо проявилось бы. Но мне по любому сложно представить себе нормальный сайт с гигабайтом статических html страниц, так что боюсь это в любом случае гипотетические рассуждения. )))
Ну да, в среднем это гораздо больше будет. Я вот книги в epub формате вижу, около 100мб в зипе. Надо объяснять, что зип жмёт текст примерно 10 к 1 ?
Книг может быть очень много. Вопрос — обо что встанет сделать веб-интерфейс для небольшой библиотеки, скажем в 1-10 тыс книжек ?
S>>Ещё раз: мы говорим о прогретом кэше. В этом случае всё, что "проверяет" веб-сервер — это наличие готового response в памяти. После чего отдаёт адрес этого response в драйвер http или tcp, который без участия CPU запихивает респонс в сеть.
_>Вы собственно про какой кэш то? )
Да любой кеш не в твою пользу. С правильной статикой запросы вообще могут и не доходить до сервера, их будет отдавать ктото из посредников в цепочке или CDN, а в твоём случае этого нет и быть не может.
>Если про аппаратный в дисках, то это действительно очень эффективная вещь, только вот маленький он. А если вы про некое подобие, организуемое операционной системой в оперативной памяти, то тут уже совершенно другой расклад. Причём в случае винды там совсем всё мрачно... )))
Здравствуйте, alex_public, Вы писали: _>Ну во-первых как раз размеры то у шаблонизаторов и результатов их работы по любому разные и в таком диком случае это явно очень хорошо проявилось бы.
Мы, вроде бы, говорим про server-side шаблонизатор vs client-side. Для client-side шаблон является "статическим файлом", достаточно маленького размера. Его очень легко держать в кэше, как на клиентской стороне, так и на серверной. Для server-side шаблон существует только в памяти сервера, при отдаче он умножается на размер данных. Его нельзя кэшировать на клиенте, т.к. он "размазан" по результату.
_>Но мне по любому сложно представить себе нормальный сайт с гигабайтом статических html страниц, так что боюсь это в любом случае гипотетические рассуждения. )))
Ок, отлично, этот вопрос можно закрыть. Давайте представим себе "нормальный сайт", который влезает в лимиты ваших представлений. Пусть это будет 25MB.
Вам понятно, что в современном мире он весь сидит в кэше? Поэтому рассуждать о временах доступа к диску — это бравировать некомпетентностью.
_>Вы собственно про какой кэш то? ) Если про аппаратный в дисках, то это действительно очень эффективная вещь, только вот маленький он. А если вы про некое подобие, организуемое операционной системой в оперативной памяти, то тут уже совершенно другой расклад.
Я — про http кэш, который является частью любого современного сервера. В винде, начиная емнип с 2003, этот кэш работает в режиме ядра. В lighttpd и nginx он работает в юзермоде, но тоже очень неплохо. На случай промаха мимо http-кэша (например, из-за неудачного vary-by), пойдёт обращение к файловой системе, а там свой кэш. И в случае хоть винды, хоть невинды, там всё очень даже хорошо — для характерных размеров сайтов, как мы выяснили в предыдущем абзаце, 100% контента уже лежит в памяти. Даже если это VPS с 500MB памяти.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[129]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Я пытаюсь объяснить, что "отдача статики с диска" — адски оптимизированная операция. Есть разные стратегии оптимизации — http.sys, сплайсы, sendfile. S>Порвать это при помощи шаблонизатора с "прямой записью" — дохлый номер.
В такой формулировке согласен. Но приведу интересный пример — нам в проекте надо добавить репозиторий для бинарных артефактов (образы Docker, характерный размер в 100-200Мб).
Задача достаточно обычная и решение очевидное — поставить nginx и из динамического кода просто перенаправлять на нужный статический файл. Но сначала сделали простенькую реализацию на Питоне (+PyPy) из 10 строк кода, чисто для эксперимента, пока я допиливаю развёртывание nginx.
Вот только оказалось, что эта детская версия работает почти с такой же скоростью, что и nginx. Splice творит чудеса.
Sapienti sat!
Re[130]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Cyberax, Вы писали:
C>Вот только оказалось, что эта детская версия работает почти с такой же скоростью, что и nginx. Splice творит чудеса.
Конечно. Но эти чудеса, собственно, требуют наличия двух "файловых дескрипторов". То, что IO стек в современных осях позволяет оффлоадить взаимодействие диск-сеть и диск-диск за пределы CPU — это прекрасно. Весь выигрыш, собственно, и достигается за счёт а) отсутствия переключений контекста в процессе передачи и б) возможности выдвинуть всю коммуникацию между физическими устройствами за пределы процессора.
Как только мы попробуем запихивать те же данные в сокет из нашего юзермодного приложения мелкими порциями — грубо говоря, построчно — как вся магия тут же развеется.
Поэтому романтизировать compile-time шаблонизаторы — бессмысленное занятие. С точки зрения сетевой карты, они почти столь же неэффективны, как и "медленные" скрипты. Стоимость склейки строк, происходящей между вызовами socket.Send(), пренебрежимо мала по сравнению с самими вызовами.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[137]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты ничего не показал. Я вот никак не могу понять, что же будет отдаваться на клиент — html со всеми данными, просто темплейт или какие то данные вместе с темплейтом.
I>Судя по твоим косвенным намёкам, отдавать надо Html со всеми данными. А это, внезапно, исключает 90% оптимизаций. А следовательно "не будет стоить практически ничего" есть просто враньё.
Уже в который раз повторяю: это зависит от выбранной стратегии на клиенте, а не от vibe.d. Ты можешь отдавать на клиента статические js шаблоны плюс данные через ajax. Можешь отдавать js шаблоны + данные внутри одной html страницы. А можешь отдавать уже готовые html страницы без всяких скриптов, как в старом веб'е. Выбор на твой вкус, а vibe.d будет одинаково эффективно поддерживать любой из этих сценариев.
I>Для сравнения. Работа с темплейтами на клиенте означает, что серверу надо исключительно данные отдавать. I>Если на серверве, то отдавать надо в сотни раз больше чисто из за того, что данные унуте html. Кроме того, это вызывает проблемы например с кешированием, делает невозможным использование большинтсва других оптимизаций. Например, CDN тебе так же не поможет.
Так сравнивать то надо конкурирующие между собой вещи, а это дополняющие друг друга... )
Re[133]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ну да, в среднем это гораздо больше будет. Я вот книги в epub формате вижу, около 100мб в зипе. Надо объяснять, что зип жмёт текст примерно 10 к 1 ? I>Книг может быть очень много. Вопрос — обо что встанет сделать веб-интерфейс для небольшой библиотеки, скажем в 1-10 тыс книжек ?
Ой, да я таких ссылок с любым результатом могу столько накидать... ))) Меня больше убеждают вот такие картинки:
Кстати, в контексте нашей дискуссии небезынтересно взглянуть и на поведение "Other"...
Re[133]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Мы, вроде бы, говорим про server-side шаблонизатор vs client-side. Для client-side шаблон является "статическим файлом", достаточно маленького размера. Его очень легко держать в кэше, как на клиентской стороне, так и на серверной. Для server-side шаблон существует только в памяти сервера, при отдаче он умножается на размер данных. Его нельзя кэшировать на клиенте, т.к. он "размазан" по результату.
Нет, разговор, в который вы вмешались, был о сравнение отдачи клиентского js шаблона в виде статического файла и отдаче его же через работу серверного шаблона (типа jade). Сравнения же реальной динамики (с обращением к базам данных и т.п.) со статикой очевидно абсолютно глупое занятие и никто тут этим не занимался.
S>Вам понятно, что в современном мире он весь сидит в кэше? Поэтому рассуждать о временах доступа к диску — это бравировать некомпетентностью.
Как теперь понятно по тексту ниже, вы подразумевали везде output caching http демонов. Это сразу вызывает множество комментариев:
1. Вообще то подобный кэш всегда умеет работать и для статических файлов и для динамического контента (причём в контексте нашего обсуждения, контент на самом деле даже не динамический, а просто генерируется на ходу, но всегда один и тот же). Так что совершенно непонятно привлечение его в качестве аргументации в противопоставление шаблонизаторов и статических файлов.
2. Даже если предположить, что для шаблонизатора вы почему-то отключаете кэш, а для статики нет, то всё равно выдача происходит почти одинаковым образом — копирование одного куска оперативной памяти в другой. Максимум разницы, это в случае IIS на один переход в нулевое кольцо больше, что просто смешно, как мы уже увидели из ваших же цифр. И это всё говорилось для случая "прогретого кэша", а если учитывать ещё и отсутствие данных в кэше (они кстати туда не обязательно после первого запроса попадают), то...
3. Настройки кэшей у всех серверов конечно же разные... Но если взять скажем ваш любимый IIS, то уже видно http://www.iis.net/learn/manage/managing-performance-settings/configure-iis-7-output-caching что там далеко не всё так радужно с кэшированием. И отсутствие обращений к файловой системе является преувеличением. И в режиме ядра умеет кэшировать далеко не всё. И с настройками этого дела не всё так тривиально (я не про сложность, а про вообще возможность получить то, что хочешь).
Вообще странно, что вы изначально не вспомнили такие инструменты как memcached, и nginx в режиме прокси (как его очень часто используют)и т.п... Это всё действительно будет обходить по скорости всяческие шаблонизаторы (голые). Может дело в том, что это всё опять же вполне применимо (и не только в теории, но так обычно и делают, правда не с обсуждаемым в этой темке шаблонизатором, т.к. он и сам быстрый) и поверх шаблонизаторов? )))
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, разговор, в который вы вмешались, был о сравнение отдачи клиентского js шаблона в виде статического файла и отдаче его же через работу серверного шаблона (типа jade).
А я-то думал вы тут рассказываете про военные чудеса фреймворков на D, которые пытаются генерировать разметку на сервере по шаблонам, скомпилированным на D.
_>Сравнения же реальной динамики (с обращением к базам данных и т.п.) со статикой очевидно абсолютно глупое занятие и никто тут этим не занимался.
_>Как теперь понятно по тексту ниже, вы подразумевали везде output caching http демонов. Это сразу вызывает множество комментариев: _>1. Вообще то подобный кэш всегда умеет работать и для статических файлов и для динамического контента (причём в контексте нашего обсуждения, контент на самом деле даже не динамический, а просто генерируется на ходу, но всегда один и тот же). Так что совершенно непонятно привлечение его в качестве аргументации в противопоставление шаблонизаторов и статических файлов.
Просто для статических файлов "подобный кэш" очень хорошо умеет инвалидироваться, поэтому он в среднем лучше хэндлит Conditional Get.
_>2. Даже если предположить, что для шаблонизатора вы почему-то отключаете кэш, а для статики нет, то всё равно выдача происходит почти одинаковым образом — копирование одного куска оперативной памяти в другой. Максимум разницы, это в случае IIS на один переход в нулевое кольцо больше, что просто смешно, как мы уже увидели из ваших же цифр. И это всё говорилось для случая "прогретого кэша", а если учитывать ещё и отсутствие данных в кэше (они кстати туда не обязательно после первого запроса попадают), то...
Если мы хотим учесть отсутствие данных в кэше, то мы с тем же успехом можем учесть отсутствие бинарного кода в кэше. Как мы знаем, современные ОС не загружают весь исполняемый файл — вместо этого они включают memory mapping, и при исполнении кода страницы поднимаются с диска в память "на общих основаниях".
_>3. Настройки кэшей у всех серверов конечно же разные... Но если взять скажем ваш любимый IIS, то уже видно http://www.iis.net/learn/manage/managing-performance-settings/configure-iis-7-output-caching что там далеко не всё так радужно с кэшированием. И отсутствие обращений к файловой системе является преувеличением. И в режиме ядра умеет кэшировать далеко не всё. И с настройками этого дела не всё так тривиально (я не про сложность, а про вообще возможность получить то, что хочешь).
Конечно. Просто в случае велосипеда, который чего-то там пишет в Response.OutputStream, даже этого "не всё так радужно" достичь очень тяжело.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Sinclair, Вы писали:
S>>Мы, вроде бы, говорим про server-side шаблонизатор vs client-side. Для client-side шаблон является "статическим файлом", достаточно маленького размера. Его очень легко держать в кэше, как на клиентской стороне, так и на серверной. Для server-side шаблон существует только в памяти сервера, при отдаче он умножается на размер данных. Его нельзя кэшировать на клиенте, т.к. он "размазан" по результату.
_>Нет, разговор, в который вы вмешались, был о сравнение отдачи клиентского js шаблона в виде статического файла и отдаче его же через работу серверного шаблона (типа jade). Сравнения же реальной динамики (с обращением к базам данных и т.п.) со статикой очевидно абсолютно глупое занятие и никто тут этим не занимался.
S>>Вам понятно, что в современном мире он весь сидит в кэше? Поэтому рассуждать о временах доступа к диску — это бравировать некомпетентностью.
_>Как теперь понятно по тексту ниже, вы подразумевали везде output caching http демонов. Это сразу вызывает множество комментариев: _>1. Вообще то подобный кэш всегда умеет работать и для статических файлов и для динамического контента (причём в контексте нашего обсуждения, контент на самом деле даже не динамический, а просто генерируется на ходу, но всегда один и тот же). Так что совершенно непонятно привлечение его в качестве аргументации в противопоставление шаблонизаторов и статических файлов.
Динамический контент на то и динамический, что меняется. Если его кешировать, то надо знать когда сбрасывать кеш или как кеш варьировать, это все снижает Hit-Miss Ratio.
Теперь банальный расчет — предположим удалось сделать кеш для динамического контента, который с вероятностью 50% попадает. Средний размер страницы — 60кб. Шаблонизатор работает 1 мсек.
Приходит 1М запросов — это 500 секунд работы шаблонизатора и около 28 гб трафика.
Переносим шаблонизатор на клиент — шаблон весит 60кб, отдается один раз и лежит в кеше (ядра или reverse proxy). Данные для работы шаблонизатора — 5кб, при этом можно подобрать гранулярность запросов данных, чтобы повысить hit-miss ratio. Предположим удалось 60% сделать. Тот же 1М запросов — время на сервере — 0, трафик — 3гб, так еще и к внешнем данным обращаться реже надо из-за более удачного кеширования.
В реальном же случает кшировать генерируемые на сервере страницы нереально, слишком изменчивы и слишком сложно вычислять когда сбрасывать кеш. А для ajax запросов данных совсем наоборот.
Так что с точки зрения кеша клиентская шаблонизация рулит. Фактичекси рулит она почти всегда, кроме слабых устройств обходчиков поиска.
_>3. Настройки кэшей у всех серверов конечно же разные... Но если взять скажем ваш любимый IIS, то уже видно http://www.iis.net/learn/manage/managing-performance-settings/configure-iis-7-output-caching что там далеко не всё так радужно с кэшированием. И отсутствие обращений к файловой системе является преувеличением. И в режиме ядра умеет кэшировать далеко не всё. И с настройками этого дела не всё так тривиально (я не про сложность, а про вообще возможность получить то, что хочешь).
Статику как раз в режиме ядра кеширует. Динамику — в памяти приложения.
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>А я-то думал вы тут рассказываете про военные чудеса фреймворков на D, которые пытаются генерировать разметку на сервере по шаблонам, скомпилированным на D.
Да, именно. Но я так и не понял почему некоторые, считают подобную технологию в чём-то противопоставленной клиентским js скриптам, в то время как очевидно, что это дополняющие друг друга технологии. В частности вполне можно генерировать клиентские js шаблоны с помощью серверных шаблонов (кстати, с помощью того же jade частенько генерируют и полностью статические страницы, просто это происходит на компьютере разработчика, а не на сервере в реальном времени).
S>Если мы хотим учесть отсутствие данных в кэше, то мы с тем же успехом можем учесть отсутствие бинарного кода в кэше. Как мы знаем, современные ОС не загружают весь исполняемый файл — вместо этого они включают memory mapping, и при исполнении кода страницы поднимаются с диска в память "на общих основаниях".
Только правила разные. Если взглянуть на описание того же IIS, то там вполне указано, что не каждый запрос попадает в кэш...
S>Конечно. Просто в случае велосипеда, который чего-то там пишет в Response.OutputStream, даже этого "не всё так радужно" достичь очень тяжело.
Ну вообще то vibe.d был создан совсем не для того, чтобы соревноваться с http серверами в отдаче статики. Он предназначен для обгона совсем других конкурентов — см. первые же диаграммы тут http://dconf.org/2013/talks/panteleev.pdf. Более того, он естественно умеет отдавать статические страницы обычным образом (из файлов), а не только через шаблонизатор. ))) Так что никакого позиционирования на конкуренцию со статическими серверами нет. Просто я отметил в одном месте Ikemefula, что подобный шаблонизатор может обойти по быстродействию даже отдачу шаблона из статического файла (при условии, что шаблонизатор отдаёт такую же страницу, а не какую-то динамику с данными из базы). А вы прицепились к этой фразе и начали строить теории про велосипеды. )))
Re[131]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
C>>Вот только оказалось, что эта детская версия работает почти с такой же скоростью, что и nginx. Splice творит чудеса. S>Конечно. Но эти чудеса, собственно, требуют наличия двух "файловых дескрипторов".
Необязательно. Сплайсы можно делать прямо из куска памяти (выравненного по границе страницы). Sendfile — это просто частный случай, когда страницы просто лежат в файловом кэше.
S>Как только мы попробуем запихивать те же данные в сокет из нашего юзермодного приложения мелкими порциями — грубо говоря, построчно — как вся магия тут же развеется.
А зачем так делать? Рендерим всю страницу (ну или заметный её кусок, скажем в районе мегабайта) и сплайсим его в сокет. Во время передачи мы можем даже продолжать рендеринг в другом потоке.
Sapienti sat!
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Динамический контент на то и динамический, что меняется. Если его кешировать, то надо знать когда сбрасывать кеш или как кеш варьировать, это все снижает Hit-Miss Ratio. G>Теперь банальный расчет — предположим удалось сделать кеш для динамического контента, который с вероятностью 50% попадает. Средний размер страницы — 60кб. Шаблонизатор работает 1 мсек. G>Приходит 1М запросов — это 500 секунд работы шаблонизатора и около 28 гб трафика.
G>Переносим шаблонизатор на клиент — шаблон весит 60кб, отдается один раз и лежит в кеше (ядра или reverse proxy). Данные для работы шаблонизатора — 5кб, при этом можно подобрать гранулярность запросов данных, чтобы повысить hit-miss ratio. Предположим удалось 60% сделать. Тот же 1М запросов — время на сервере — 0, трафик — 3гб, так еще и к внешнем данным обращаться реже надо из-за более удачного кеширования.
G>В реальном же случает кшировать генерируемые на сервере страницы нереально, слишком изменчивы и слишком сложно вычислять когда сбрасывать кеш. А для ajax запросов данных совсем наоборот. G>Так что с точки зрения кеша клиентская шаблонизация рулит. Фактичекси рулит она почти всегда, кроме слабых устройств обходчиков поиска.
Вот надо бы тебе всё же читать дискуссию с самого начала, а не кусками. Тогда не пришлось бы писать столько довольно разумного текста понапрасну. В данной темке обсуждалась ситуация сравнения отдачи клиентского js шаблона как статического файла, в сравнение с отдачей этого же клиентского js шаблона через его динамическую генерацию с помощью серверного шаблона. Во всяком случае именно к моей реплике к Ikemefula, что при таком раскладе шаблонизатор может обойти даже статическую отдачу, и прицепился Sinclair.
G>Статику как раз в режиме ядра кеширует. Динамику — в памяти приложения.
Там же написано, что даже банальная авторизация отключает кэширование...
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Да, именно. Но я так и не понял почему некоторые, считают подобную технологию в чём-то противопоставленной клиентским js скриптам, в то время как очевидно, что это дополняющие друг друга технологии. В частности вполне можно генерировать клиентские js шаблоны с помощью серверных шаблонов (кстати, с помощью того же jade частенько генерируют и полностью статические страницы, просто это происходит на компьютере разработчика, а не на сервере в реальном времени).
Простите, я потерял нить. Что такое "клиентские js шаблоны"?
_>Только правила разные. Если взглянуть на описание того же IIS, то там вполне указано, что не каждый запрос попадает в кэш...
Вы поймите, что для статики уже написаны правила и код, которые очень хорошо работают из коробки. Если вы пишете хэндлер, который отдаёт статический файл "вручную", то вам придётся сильно нагнуться для того, чтобы достичь производительности nginx или lighttpd.
_>Ну вообще то vibe.d был создан совсем не для того, чтобы соревноваться с http серверами в отдаче статики. Он предназначен для обгона совсем других конкурентов — см. первые же диаграммы тут http://dconf.org/2013/talks/panteleev.pdf. Более того, он естественно умеет отдавать статические страницы обычным образом (из файлов), а не только через шаблонизатор.
А что такое "обычным образом"? Он рассчитан на встраивание в инфраструктуру IIS или на самостоятельную работу? Есть ли в нём output cache? Использует ли он TransmitFile/splice для оффлоада отправки в железо?
_>))) Так что никакого позиционирования на конкуренцию со статическими серверами нет. Просто я отметил в одном месте Ikemefula, что подобный шаблонизатор может обойти по быстродействию даже отдачу шаблона из статического файла (при условии, что шаблонизатор отдаёт такую же страницу, а не какую-то динамику с данными из базы). А вы прицепились к этой фразе и начали строить теории про велосипеды. )))
Конечно прицепился. Потому что "подобный шаблонизатор" никак не сможет обойти по быстродействию отдачу шаблона из статического файла. Ну, то есть если мы возьмём одиночный запрос, то один из response time шаблонизатора может оказаться короче, чем один из response time классического HTTP-демона. Благодаря изначально неравным условиям — например, шаблонизатор прогрет, а статический хэндлер запускается из прогретого кэша.
А если мы будем симулировать реальную нагрузку и смотреть на response time и throughput, то шаблонизатор всегда будет не лучше, чем статический хэндлер. Природу не обманешь.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[132]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, Sinclair, Вы писали:
C>>>Вот только оказалось, что эта детская версия работает почти с такой же скоростью, что и nginx. Splice творит чудеса. S>>Конечно. Но эти чудеса, собственно, требуют наличия двух "файловых дескрипторов". C>Необязательно. Сплайсы можно делать прямо из куска памяти (выравненного по границе страницы).
Тогда будет маршаллинг из юзермоды в кернел; а тот конкретный splice(2), о котором идёт речь, пользуется перемещением данных в кернел-моде. C>А зачем так делать? Рендерим всю страницу (ну или заметный её кусок, скажем в районе мегабайта) и сплайсим его в сокет. Во время передачи мы можем даже продолжать рендеринг в другом потоке.
Если так делать, то мы быстро упрёмся в размеры буферов. Если, скажем, у нас буфер в районе мегабайта, то во всём адресном пространстве 32х-разрядного процесса мы не сможем одновременно обслуживать больше 2000 клиентов, что для веба как бы приговор. Ну, то есть на самом деле ещё меньше, т.к. адресное пространство нам нужно не только для буферов под сплайсинг.
Конечно, х64 немножко улучшает ситуацию, но в целом, оффлоадить нагрузку за пределы своего процесса — более грамотная стратегия.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Там же написано, что даже банальная авторизация отключает кэширование...
В режиме ядра, в режиме ядра. В юзермоде кэширование всё ещё возможно.
Шаблоны обычно не требуют авторизации, т.к. не содержат никаких sensitive данных.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[133]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
C>>Необязательно. Сплайсы можно делать прямо из куска памяти (выравненного по границе страницы). S>Тогда будет маршаллинг из юзермоды в кернел; а тот конкретный splice(2), о котором идёт речь, пользуется перемещением данных в кернел-моде.
Не будет. Splice(2) помечает куски памяти как защищённые, так что при обращении их изменении из пользовательского пространства произойдёт Copy-On-Write. В результате, сетевая карта может читать из засплайсенного буфера как из своего, не боясь разных гонок.
S>Если так делать, то мы быстро упрёмся в размеры буферов. Если, скажем, у нас буфер в районе мегабайта, то во всём адресном пространстве 32х-разрядного процесса мы не сможем одновременно обслуживать больше 2000 клиентов, что для веба как бы приговор. Ну, то есть на самом деле ещё меньше, т.к. адресное пространство нам нужно не только для буферов под сплайсинг.
2000 одновременных клиентов, что уже неплохо. Ну и таки x64 есть уже везде.
S>Конечно, х64 немножко улучшает ситуацию, но в целом, оффлоадить нагрузку за пределы своего процесса — более грамотная стратегия.
Это смотря для чего. Клиентские шаблоны мне, лично, не очень нравятся по многим причинам.
Sapienti sat!
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Cyberax, Вы писали: C>Не будет. Splice(2) помечает куски памяти как защищённые, так что при обращении их изменении из пользовательского пространства произойдёт Copy-On-Write. В результате, сетевая карта может читать из засплайсенного буфера как из своего, не боясь разных гонок.
Ничего не понял. Я плохо знаком с Linux технологиями. Вот, читаю тут:
1. Никакого упоминания про возможность копирования из буфера в сокет. Чёрным по белому написано:
splice() moves data between two file descriptors without copying between kernel address space and user address space.
2. Есть упоминания про семантику move, в сочетании с vmsplice(). Я до конца их не понял; про copy-on-write ничего не сказано, зато сказано, что если типа не указать SPLICE_F_GIFT в vmsplice(), то последующий splice() будет вынужден копировать страницы. C>2000 одновременных клиентов, что уже неплохо. Ну и таки x64 есть уже везде.
В жизни это означает 300 одновременных клиентов. Расходы памяти на каждого клиента стоит минимизировать. Тут как раз баланс: делаем большие буфера — снижаем concurrency. Делаем маленькие — тратимся на context switch и постоянный ремаппинг между user address space и kernel address space.
S>>Конечно, х64 немножко улучшает ситуацию, но в целом, оффлоадить нагрузку за пределы своего процесса — более грамотная стратегия. C>Это смотря для чего. Клиентские шаблоны мне, лично, не очень нравятся по многим причинам.
Это для улучшения масштабируемости.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ой, да я таких ссылок с любым результатом могу столько накидать... ))) Меня больше убеждают вот такие картинки: http://cdn-static.zdnet.com/i/r/story/70/00/017838/webserverjuly2013-620x359.png _>Кстати, в контексте нашей дискуссии небезынтересно взглянуть и на поведение "Other"...
И в чёи, интересно, такие картинки могут убедить? Что большинство вебсайтов строится людьми, не имеющими ни малейшего представления о производительности, так что даже самый уродский сервер, который только можно себе представить, доминирует на рынке с большим отрывом?
Простите, это вообще ничего не доказывает в техническом плане.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>2. Есть упоминания про семантику move, в сочетании с vmsplice(). Я до конца их не понял; про copy-on-write ничего не сказано, зато сказано, что если типа не указать SPLICE_F_GIFT в vmsplice(), то последующий splice() будет вынужден копировать страницы.
Да. Алгоритм такой:
1) Создаётся неименованый пайп.
2) Делается vmsplice() с SPLICE_F_GIFT. Ядро получает стабильную копию данных.
3) Делается splice() с другого конца пайпа в сокет. Физически в пайп ничего не пишется, конечно же.
C>>2000 одновременных клиентов, что уже неплохо. Ну и таки x64 есть уже везде. S>В жизни это означает 300 одновременных клиентов. Расходы памяти на каждого клиента стоит минимизировать. Тут как раз баланс: делаем большие буфера — снижаем concurrency. Делаем маленькие — тратимся на context switch и постоянный ремаппинг между user address space и kernel address space.
В Линуксе это достаточно тривиальная операция. Кстати, с помощью BPF (Berkely Packet Filter — такая виртуальная машинка в ядре, с простым JIT) можно даже часть её перенести в kernelspace.
C>>Это смотря для чего. Клиентские шаблоны мне, лично, не очень нравятся по многим причинам. S>Это для улучшения масштабируемости.
Только вот в случае больших страниц (мегабайт, как ты сам привёл) обработка на мобильных устройствах занимает достаточно много времени и требует батарейку. Причём весьма так заметно.
Во-вторых, большинство (все?) распространённые клиентские шаблонизаторы требуют полностью загруженного шаблона, чтобы начать рисовать страницу. При плохом мобильном соединении в результате получаем белый квадрат Малевича, пока страница загружается. В случае с серверными шаблонами Хром и другие браузеры умеют делать прогрессивный рендеринг.
Sapienti sat!
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Динамический контент на то и динамический, что меняется. Если его кешировать, то надо знать когда сбрасывать кеш или как кеш варьировать, это все снижает Hit-Miss Ratio. G>>Теперь банальный расчет — предположим удалось сделать кеш для динамического контента, который с вероятностью 50% попадает. Средний размер страницы — 60кб. Шаблонизатор работает 1 мсек. G>>Приходит 1М запросов — это 500 секунд работы шаблонизатора и около 28 гб трафика.
G>>Переносим шаблонизатор на клиент — шаблон весит 60кб, отдается один раз и лежит в кеше (ядра или reverse proxy). Данные для работы шаблонизатора — 5кб, при этом можно подобрать гранулярность запросов данных, чтобы повысить hit-miss ratio. Предположим удалось 60% сделать. Тот же 1М запросов — время на сервере — 0, трафик — 3гб, так еще и к внешнем данным обращаться реже надо из-за более удачного кеширования.
G>>В реальном же случает кшировать генерируемые на сервере страницы нереально, слишком изменчивы и слишком сложно вычислять когда сбрасывать кеш. А для ajax запросов данных совсем наоборот. G>>Так что с точки зрения кеша клиентская шаблонизация рулит. Фактичекси рулит она почти всегда, кроме слабых устройств обходчиков поиска.
_>Вот надо бы тебе всё же читать дискуссию с самого начала, а не кусками. Тогда не пришлось бы писать столько довольно разумного текста понапрасну. В данной темке обсуждалась ситуация сравнения отдачи клиентского js шаблона как статического файла, в сравнение с отдачей этого же клиентского js шаблона через его динамическую генерацию с помощью серверного шаблона. Во всяком случае именно к моей реплике к Ikemefula, что при таком раскладе шаблонизатор может обойти даже статическую отдачу, и прицепился Sinclair.
Я все прочитал. Ключевая фраза — Динамический контент на то и динамический, что меняется.
Если не меняется, то сгенерируй один раз и положи файлом, тогда IIS с его отдачей из ядра порвет любую реализацию.
G>>Статику как раз в режиме ядра кеширует. Динамику — в памяти приложения. _>Там же написано, что даже банальная авторизация отключает кэширование...
Статика по умолчанию не проходит через авторизацию.
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Cyberax, Вы писали: C>Да. Алгоритм такой: C>1) Создаётся неименованый пайп. C>2) Делается vmsplice() с SPLICE_F_GIFT. Ядро получает стабильную копию данных. C>3) Делается splice() с другого конца пайпа в сокет. Физически в пайп ничего не пишется, конечно же.
А, я-то думал что на одном конце сокет, а на другом — файл.
C>>>2000 одновременных клиентов, что уже неплохо. Ну и таки x64 есть уже везде. S>>В жизни это означает 300 одновременных клиентов. Расходы памяти на каждого клиента стоит минимизировать. Тут как раз баланс: делаем большие буфера — снижаем concurrency. Делаем маленькие — тратимся на context switch и постоянный ремаппинг между user address space и kernel address space. C>В Линуксе это достаточно тривиальная операция. Кстати, с помощью BPF (Berkely Packet Filter — такая виртуальная машинка в ядре, с простым JIT) можно даже часть её перенести в kernelspace.
Не очень понял, что именно можно перенести в kernelspace? формирование выходной разметки, накладывая шаблон на результат выборки из базы?
C>Только вот в случае больших страниц (мегабайт, как ты сам привёл) обработка на мобильных устройствах занимает достаточно много времени и требует батарейку. Причём весьма так заметно.
C>Во-вторых, большинство (все?) распространённые клиентские шаблонизаторы требуют полностью загруженного шаблона, чтобы начать рисовать страницу. При плохом мобильном соединении в результате получаем белый квадрат Малевича, пока страница загружается. В случае с серверными шаблонами Хром и другие браузеры умеют делать прогрессивный рендеринг.
Не очень понимаю, как так. Шаблон же сам по себе — это всего лишь кусок <tr></tr> с плейсхолдерами, условно говоря. Как он может загрузиться позже, чем фрагмент-страницы-с-данными? Он вообще должен с 90% уже в клиентском кэше лежать. Или имеется в виду то, что не работает обработка json-formatted data при частичной загрузке?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[137]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>А, я-то думал что на одном конце сокет, а на другом — файл.
Так и получается, на самом деле
C>>В Линуксе это достаточно тривиальная операция. Кстати, с помощью BPF (Berkely Packet Filter — такая виртуальная машинка в ядре, с простым JIT) можно даже часть её перенести в kernelspace. S>Не очень понял, что именно можно перенести в kernelspace? формирование выходной разметки, накладывая шаблон на результат выборки из базы?
Весь процесс splice'а данных, включая создание пайпов.
C>>Только вот в случае больших страниц (мегабайт, как ты сам привёл) обработка на мобильных устройствах занимает достаточно много времени и требует батарейку. Причём весьма так заметно.
S>Не очень понимаю, как так. Шаблон же сам по себе — это всего лишь кусок <tr></tr> с плейсхолдерами, условно говоря.
Смотри, при загрузке динамического контента мы имеем:
<body>
Hello, world!
<table>
<tr><td>This</td><td>is a test</td></tr>
//Затык на 10 секунд - мобильный инет тормозит
Браузер сразу покажет на дисплее "Hello, world!" и "This is a test", хотя ещё не всё загружено. В случае с клиентским шаблоном нужно загрузить ВЕСЬ шаблон и все данные (два отдельных запроса!), прежде чем на экране что-то появится.
S>Как он может загрузиться позже, чем фрагмент-страницы-с-данными? Он вообще должен с 90% уже в клиентском кэше лежать.
Клиентского кэша нет при первом (самом важном!) обращении к сайту. Вдобавок, в том же Хроме клиенсктий кэш — всего порядка 50Мб. Всего за пару дней оттуда данные исчезнут.
S>Или имеется в виду то, что не работает обработка json-formatted data при частичной загрузке?
Это тоже, кстати.
Sapienti sat!
Re[114]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Только т.к. в этих языках это является мелкими дополнениями вокруг главного ядра uml, то в Хаскеле мы соответственно только эту обёртку и получим, без всей мощи ядра.
Не понятно, что это за невостребованное ядро.
Диаграмма классов это:
1) а) Группировка для функций/методов с делением на публичные и приватные. Востребована она в хаскеле? Да. Функции на приватные/публичные делятся? Да.
б) Стереотипы для классификации таких групп. обычные классы/интерфейсы/статические классы/модули/классы типов/рекорды и т.д. Востребовано это в хаскеле? Да.
2) Отношения между этими группами функций вроде наследования, аггрегации, имплементации и т.д.
Востребовано это в хаскеле? Конечно. К примеру между классами типов отношение наследования, а между инстансами и классами типов — отношение имплементации.
Всего хватает, "ядро" используется в полном объеме. Что не так-то?
_>И это ещё речь только про одну (пусть и главную) структурную диаграмму, а у главных диаграмм поведение с Хаскелем вообще нет шансов (ну это мы уже обсудили, я просто напоминаю, а то вы же не уточняете выше, что говорите только про диаграмму классов).
И активити и сиквенс-диаграммы с хаскелем использовать конечно можно. Я просто не вижу особого смысла в использовании аквтивити диаграмм — псевдокод для этого куда лучше, что мы и обсуждали.
_>>>Ну так тогда вас не затруднит кинуть ссылку на конкретное сообщение ваше сообщение? ) K>>Ну вот об этом я и говорю. Ведь мы же эти преобразования буквально в предыдущем посте обсуждали. K>>http://rsdn.ru/forum/philosophy/5624883.1
Нет, я говорил о преобразовании конвейера из all / map / takeWhile и т.д. в цикл, и вообще класс преобразований из последовательных проходов в один проход. Без контроля эффектов эти преобразования в общем случае некорректны.
_>Это как-то доказывает теоретическую невозможность повторения всех возможностей Хаскеля, но без обязательности ограничений (и соответственно без синтаксического пенальти)?
Это не доказывает невозможность, но показывает, что никаких оснований говорить о повторении всех возможностей которые дает контроль эффектов а ля хаскель пока нет.
K>>Это только та часть не осознает, которая конвейеры не использует. _>Конвейеры очень разные бывают...
Это точно, те, кто использует только вырожденные конвейеры из 0 и 1-ой стадии — тоже не осознают.
K>>Да можно и при 10% равной считать. _>Тогда к чему разговор о "страшной" погрешности измерения в 2% и обоснование этим усреднения результатов, вместо выборки минимального?
Не знаю, к чему этот разговор. Если мы сравниваем числа сравнимые с погрешностью измерений, значит их нужно статистически обрабатывать, а не просто "брать минимальные" — вот и все.
Никаких выводов на том, что этот подход неправильный я, в отличие от вас, не строю.
Никаких выводов на разнице в 10% я тоже не строю, моя цель была опровергнуть утверждение про какие-то "отличия в разы", так что для меня и 30% разница не принципиальна. Особенно если учитывать, что речь идет о нерелевантных примерах, не имеющих никакого отношения к поддержке иммутабельности.
_>В D int равен 32 битам.
Ну вот, т.е. разница будет уже за счет того, что в одном случае (D) int32, а в другом (хаскель) int64
_>И дело не только в регистрах, а просто в том что разные алгоритмы используются (с разной степенью вылизанности).
Бывает, конечно, что компиляторы для 32 и 64 вообще разные проекты вроде CLR-ного JIT, но GHC это не касается. Там вообще какой-то особенной "вылизанности" в кодогенераторе нет.
_>Так 32 битный код имеет пенальти на 64 битной системе.
Предположу, что оно незначительно в нашем случае.
_> тем более если задача такова, что 32 битный код может оказаться абсолютным лидером в сравнение.
Если учесть, что x64 версия отвечающая условиям задачи выделяет примерно в два раза больше памяти, не сложно предположить, что работает дольше.
_>Зато поработав с ним сразу ощущается что такое настоящий высокий уровень... )
Пролог конечно вызывает, по началу, яркие впечатления у неподготовленного программиста, но представления о настоящем высоком уровне он составить никак не поможет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[116]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Я не очень понимаю смысл в гонке виртуальных гигабайтов.
В моем примере они не виртуальные. Это самые обычные аллокации, сделанные стандартным аллокатором. Вы же предлагаете считать каждое изменение на месте новым размещением всего массива. Тут "аллокации" будут, конечно, виртуальными.
_>Я не про нагрузку на память, а про принципиальный факт использования иммутабельных объектов. А то ведь вы помнится и с этим спорили...
"Принципиальный факт" заключается в том, что объект, ссылающийся на изменяемый массив, иммутабельным не является. Хотя конструирование миллиона таких объектов действительно от конструирования миллиона иммутабельных отличаться по производительности не будет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[114]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, D. Mon, Вы писали:
DM>И в исходном вызове передавать честные лямбды или иные функции. Это передача по имени, незаслуженно забытая многими языками.
Это, конечно, намного лучше, но передача функций через параметры шаблонов все равно кажется ненужной сложностью. (Я понимаю, что это нужно для инлайна, но нормальный инлайнер, который таких трюков не требует — все же лучше).
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[137]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Простите, я потерял нить. Что такое "клиентские js шаблоны"?
Ну например те же самые angular шаблоны. Собственно это просто html страницы без данных и скриптов. И соответственно они отлично генерируются серверными шаблонизаторами, заточенными под создание html. Более того, такие шаблонизаторы (jade и т.п.) частенько применяют и в случае отдачи клиентских шаблонов как файлов, просто тогда это происходит на компьютере разработчика и предназначено для удобства разработки.
S>Вы поймите, что для статики уже написаны правила и код, которые очень хорошо работают из коробки. Если вы пишете хэндлер, который отдаёт статический файл "вручную", то вам придётся сильно нагнуться для того, чтобы достичь производительности nginx или lighttpd.
Хы, так никто не ставит себе такие цели. ) Зачем писать с нуля то, что уже есть, отлично работает и полностью доступно. Тут пишутся другие решения для других целей. Но при этом одной из побочных функций у них идёт и такая функциональность, так сказать для комплекта. По поводу её эффективности надо смотреть (не измерял), но пример Cyberax с несколькими строками на Питоне весьма показателен... )
S>А что такое "обычным образом"? Он рассчитан на встраивание в инфраструктуру IIS или на самостоятельную работу? Есть ли в нём output cache? Использует ли он TransmitFile/splice для оффлоада отправки в железо?
Нет, рассчитан на самостоятельную работу, без дополнительных серверов. Хотя естественно в случае огромного количества статики никто не мешает поставить nginx в режиме прокси на выходе. Правда если сайт только из статики, то тогда непонятно зачем vibe.d тут вообще.
Кэша выходного нет. Хотя для динамики его тривиально реализовать, с учётом встроенного интерфейса к redis'у. Правда не уверен в его полезности, т.к. в большинстве случаев основными тормозами такого кода будут обращения к базе данных и лучше уж кэшировать там. Тем более, что в случае vibe.d стандартной встроенной базой является MongoDB.
Да, для отдачи статических файлов используется sendFile.
S>Конечно прицепился. Потому что "подобный шаблонизатор" никак не сможет обойти по быстродействию отдачу шаблона из статического файла. Ну, то есть если мы возьмём одиночный запрос, то один из response time шаблонизатора может оказаться короче, чем один из response time классического HTTP-демона. Благодаря изначально неравным условиям — например, шаблонизатор прогрет, а статический хэндлер запускается из прогретого кэша. S>А если мы будем симулировать реальную нагрузку и смотреть на response time и throughput, то шаблонизатор всегда будет не лучше, чем статический хэндлер. Природу не обманешь.
Ну так если мы предположим ситуацию (вполне реальную кстати), что шаблонизатор и прогретый кэш отдают статическую страницу за одно и то же время, то с учётом редких случаев непрогретого кэша/промахов кэша, в среднем можем получить чуть большее время, чем у шаблонизатора.
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>И в чёи, интересно, такие картинки могут убедить? Что большинство вебсайтов строится людьми, не имеющими ни малейшего представления о производительности, так что даже самый уродский сервер, который только можно себе представить, доминирует на рынке с большим отрывом? S>Простите, это вообще ничего не доказывает в техническом плане.
Почему на первом месте Apache и какова его клиентская база я вполне себе представляю. А вот сравнение тенденции других участников уже весьма интересно... )
Re[137]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Если не меняется, то сгенерируй один раз и положи файлом, тогда IIS с его отдачей из ядра порвет любую реализацию.
Вот именно по поводу этого тут и был небольшой спор. Потому как "отдача из ядра IIS" работает быстрее шаблонизатора (речь про выдачу статики с помощью него!) только при наличие ряда условий (типа наличия данных в кэше и т.п.).
Re[115]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Не понятно, что это за невостребованное ядро. K>Диаграмма классов это: K>1) а) Группировка для функций/методов с делением на публичные и приватные. Востребована она в хаскеле? Да. Функции на приватные/публичные делятся? Да. K>б) Стереотипы для классификации таких групп. обычные классы/интерфейсы/статические классы/модули/классы типов/рекорды и т.д. Востребовано это в хаскеле? Да. K>2) Отношения между этими группами функций вроде наследования, аггрегации, имплементации и т.д. K>Востребовано это в хаскеле? Конечно. К примеру между классами типов отношение наследования, а между инстансами и классами типов — отношение имплементации. K>Всего хватает, "ядро" используется в полном объеме. Что не так-то?
Нет, основой является совсем не это, а связь между функциями и данными (даже не типами, а экземплярами данных!), с которыми они работают. Всяческие преобразования этой взаимосвязи (типа наследования), а так же пересечение с соседними взаимосвязями (типа композиции/агрегации) является уже следствие. Ну а приватные/публичные методы или тем более стереотипы — это вообще уже мелочи. Да, они актуальны для работы автоматических генераторов код<->диаграмма, но архитектуру задают совсем не они.
K>Нет, я говорил о преобразовании конвейера из all / map / takeWhile и т.д. в цикл, и вообще класс преобразований из последовательных проходов в один проход. Без контроля эффектов эти преобразования в общем случае некорректны.
А зачем требуется какое-то специальное преобразование, если можно изначально писать писать эффективную однопроходную реализацию (как сделано в тех же диапазонах D). Причём никакой чистоты для этого не требуется.
Или же подразумевается, что компоновщик/компилятор сможет взять произвольную чужую функцию типа FilterXXX(array, pure func) с циклом по array внутри и как-то интегрировать её внутрь цикла допустим внутри map'a? ) Если так, то это конечно довольно интересно, но я пока о таком не слышал.
Кстати, забавно что в gcc есть как раз обратная автоматическая возможность (опция ftree-loop-distribution).
K>Это не доказывает невозможность, но показывает, что никаких оснований говорить о повторении всех возможностей которые дает контроль эффектов а ля хаскель пока нет.
"Пока нет" — это справедливо. ) Я кстати даже не уверен, что это "пока" когда-нибудь исправится, т.к. что-то не очень много желающих заниматься этим направлением. Но главное то, что теоретическая возможность вполне есть, причём без всяких ужасных ограничений на язык (типа хаскельских). О чём я собственно и говорил.
_>>Конвейеры очень разные бывают... K>Это точно, те, кто использует только вырожденные конвейеры из 0 и 1-ой стадии — тоже не осознают.
? )
K>Не знаю, к чему этот разговор. Если мы сравниваем числа сравнимые с погрешностью измерений, значит их нужно статистически обрабатывать, а не просто "брать минимальные" — вот и все.
Ну так вы не правильно статистически обрабатываете — не учитываете, что отклонение измерения от истинного значения идёт только в одну сторону. )
K>Пролог конечно вызывает, по началу, яркие впечатления у неподготовленного программиста, но представления о настоящем высоком уровне он составить никак не поможет.
Не, я с ним очень давно знаком и он мне всегда нравился. ) Но ни разу не было возможности применить его по делу — я же исключительно практик, а не теоретик, играющийся с маргинальными языками. А тут вот неожиданно нашлось применение (правда для этого пришлось встраивать в C++ приложение и добавлять свои предикаты), причём получилось всё крайне удачно и удобно.
Re[117]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В моем примере они не виртуальные. Это самые обычные аллокации, сделанные стандартным аллокатором. Вы же предлагаете считать каждое изменение на месте новым размещением всего массива. Тут "аллокации" будут, конечно, виртуальными.
Вообще то в том моём коде по сути используется своеобразный аналог функции realloc из C. Так вот если заменить его на просто alloc, то по сути ничего не изменится. Кроме просевшего быстродействия, т.к. все эти виртуальные гигабайты резко станут реальными. Т.е. в данном случае мы имеем дело именно с оптимизацией. Просто ручной, а не автоматической. Ну так про отсутствие в D готовых библиотек подобной оптимизации мы уже говорили, но как видно, их написание не представляет вообще никакого труда.
K>"Принципиальный факт" заключается в том, что объект, ссылающийся на изменяемый массив, иммутабельным не является. Хотя конструирование миллиона таких объектов действительно от конструирования миллиона иммутабельных отличаться по производительности не будет.
Я уже не раз повторял: область памяти, на которую ссылается такой объект является абсолютно неизменной всё время жизни объекта. Почему вы ставите "в ответственность" такому объекту изменение памяти следующей непосредственно за его блоком, мне не понятно.
Re[138]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну например те же самые angular шаблоны. Собственно это просто html страницы без данных и скриптов.
Тогда почему вы называете их "js", если они html?
_>И соответственно они отлично генерируются серверными шаблонизаторами, заточенными под создание html.
Продолжаю непонимать — в чём тут роль серверного шаблонизатора?
_>Хы, так никто не ставит себе такие цели. ) Зачем писать с нуля то, что уже есть, отлично работает и полностью доступно. Тут пишутся другие решения для других целей. Но при этом одной из побочных функций у них идёт и такая функциональность, так сказать для комплекта. По поводу её эффективности надо смотреть (не измерял), но пример Cyberax с несколькими строками на Питоне весьма показателен... )
Пример ничего не говорит про то, как замечательно пример с несколькими строками хэндлит conditional get и range requests.
_>Нет, рассчитан на самостоятельную работу, без дополнительных серверов. Хотя естественно в случае огромного количества статики никто не мешает поставить nginx в режиме прокси на выходе. Правда если сайт только из статики, то тогда непонятно зачем vibe.d тут вообще.
Ну, тогда не стоит рассчитывать, что он хоть кого-то порвёт на отдаче статики.
_>Кэша выходного нет. Хотя для динамики его тривиально реализовать, с учётом встроенного интерфейса к redis'у. Правда не уверен в его полезности, т.к. в большинстве случаев основными тормозами такого кода будут обращения к базе данных и лучше уж кэшировать там.
Кэширование — сложная штука. В общем случае кэширование должно быть расположено как можно ближе к клиенту. Лучше всего — клиентский кэш. Хуже всего — файловый кэш сервера базы данных.
_>Да, для отдачи статических файлов используется sendFile.
_>Ну так если мы предположим ситуацию (вполне реальную кстати), что шаблонизатор и прогретый кэш отдают статическую страницу за одно и то же время, то с учётом редких случаев непрогретого кэша/промахов кэша, в среднем можем получить чуть большее время, чем у шаблонизатора.
У шаблонизатора будет примерно столько же случаев непрогретого кэша и промахов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[138]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Если не меняется, то сгенерируй один раз и положи файлом, тогда IIS с его отдачей из ядра порвет любую реализацию.
_>Вот именно по поводу этого тут и был небольшой спор. Потому как "отдача из ядра IIS" работает быстрее шаблонизатора (речь про выдачу статики с помощью него!) только при наличие ряда условий (типа наличия данных в кэше и т.п.).
Ну если файл статичен, то его не будет в кеше ровно один раз.
Re[139]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Тогда почему вы называете их "js", если они html?
Потому что они потом используются из клиентских js фреймворков в качестве шаблонов.
S>Продолжаю непонимать — в чём тут роль серверного шаблонизатора?
Эээ, он их генерирует? )
S>Пример ничего не говорит про то, как замечательно пример с несколькими строками хэндлит conditional get и range requests.
Ну так эти несколько строк и не задумывались как конкурент nginx'у на рынке. )))
S>Ну, тогда не стоит рассчитывать, что он хоть кого-то порвёт на отдаче статики.
А тут кто-то предлагал vibe.d для отдачи файлов с диска? )
S>У шаблонизатора будет примерно столько же случаев непрогретого кэша и промахов.
С чего это? После загрузки приложения в память у него будет стабильное время выдачи результата.
Re[139]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Ну если файл статичен, то его не будет в кеше ровно один раз.
Если мы говорим про тот же IIS, то это не так. Я же кидал уже тут ссылку. Там и стратегия засовывания в кэш более сложная и не всё можно засунуть в кэш, работающий в ядре (а в ином случае шаблонизатор явно не медленнее будет) и т.п.
Re[140]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Ну если файл статичен, то его не будет в кеше ровно один раз.
_>Если мы говорим про тот же IIS, то это не так. Я же кидал уже тут ссылку. Там и стратегия засовывания в кэш более сложная и не всё можно засунуть в кэш, работающий в ядре (а в ином случае шаблонизатор явно не медленнее будет) и т.п.
А ты её сам читал? Если файл на диске, то надо очень постараться чтобы не попал в кеш. Собственно если ты специально не будешь портить настройки IIS, то он статику будет отдавать очень быстро.
Re[141]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>А ты её сам читал? Если файл на диске, то надо очень постараться чтобы не попал в кеш. Собственно если ты специально не будешь портить настройки IIS, то он статику будет отдавать очень быстро.
Я и не говорю, что там всё плохо. Но и с твоим "если файл статичен, то его не будет в кеше ровно один раз" тоже совсем не совпадает.
Re[142]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>А ты её сам читал? Если файл на диске, то надо очень постараться чтобы не попал в кеш. Собственно если ты специально не будешь портить настройки IIS, то он статику будет отдавать очень быстро.
_>Я и не говорю, что там всё плохо. Но и с твоим "если файл статичен, то его не будет в кеше ровно один раз" тоже совсем не совпадает.
Твое мнение не совпадает или что? Думаешь я не настраивал IIS для максимального быстродействия и не оптимизировал веб-приложения?
То что ты пишешь — фантастика чистой воды.
Для скорости веб-приложений важно:
1) Кеширование
2) Работа с хранилищем данных
...
10) скорость работы кода
Хоть заоптимизируй до невозможности свои нативные модули, но пара настроек в IIS и подкручивание запросов к базе, порвут в какашки любой код.
Re[140]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Эээ, он их генерирует? )
Из чего он их "генерирует"?
_>А тут кто-то предлагал vibe.d для отдачи файлов с диска? )
Ещё четыре поста назад вы наивно полагали, что vibe.d способен каким-то магическим образом обойти коробочные http-сервера в отдаче статики (которая как правило сводится к "отдаче файлов с диска").
_>С чего это? После загрузки приложения в память у него будет стабильное время выдачи результата.
Ну так и после загрузки файла в кэш у сервера будет стабильное время выдачи результата. Ровно вплоть до вытеснения файла из кэша.
Что работает ровно так же и для приложений. Понятие "загрузки приложения в память", на которое вы опираетесь, последний раз было актуально примерно во времена MS DOS. Современные оси загружают код приложений по требованию, точно так же, как и данные.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[143]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, gandjustas, Вы писали:
G>Твое мнение не совпадает или что? Думаешь я не настраивал IIS для максимального быстродействия и не оптимизировал веб-приложения? G>То что ты пишешь — фантастика чистой воды.
Нет, описание работы кэша IIS не совпадает с твоими высказываниями. )
G>Для скорости веб-приложений важно: G>1) Кеширование G>2) Работа с хранилищем данных G>... G>10) скорость работы кода
G>Хоть заоптимизируй до невозможности свои нативные модули, но пара настроек в IIS и подкручивание запросов к базе, порвут в какашки любой код.
Потестируем?
Re[141]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Из чего он их "генерирует"?
Из серверного шаблона (типа jade).
_>>А тут кто-то предлагал vibe.d для отдачи файлов с диска? ) S>Ещё четыре поста назад вы наивно полагали, что vibe.d способен каким-то магическим образом обойти коробочные http-сервера в отдаче статики (которая как правило сводится к "отдаче файлов с диска").
Ничего подобного. Речь шла про отдачу шаблонизатором (который, как мы уже обсуждали, не сильно отличается по быстродействию от кэша), а не про отдачу файлов с диска.
S>Ну так и после загрузки файла в кэш у сервера будет стабильное время выдачи результата. Ровно вплоть до вытеснения файла из кэша.
Ну так тот же IIS скажем работает с кэшем совсем не так тривиально, как вы тут описали. А вот загрузка приложения в память именно так. )))
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, gandjustas, Вы писали:
G>>Твое мнение не совпадает или что? Думаешь я не настраивал IIS для максимального быстродействия и не оптимизировал веб-приложения? G>>То что ты пишешь — фантастика чистой воды.
_>Нет, описание работы кэша IIS не совпадает с твоими высказываниями. )
G>>Для скорости веб-приложений важно: G>>1) Кеширование G>>2) Работа с хранилищем данных G>>... G>>10) скорость работы кода
G>>Хоть заоптимизируй до невозможности свои нативные модули, но пара настроек в IIS и подкручивание запросов к базе, порвут в какашки любой код.
_>Потестируем?
Тестируй.
Re[142]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Из серверного шаблона (типа jade).
Масло масленое. Какие параметры подставляются в шаблон?
_>Ничего подобного. Речь шла про отдачу шаблонизатором (который, как мы уже обсуждали, не сильно отличается по быстродействию от кэша), а не про отдачу файлов с диска.
Ок, давайте сначала. Что именно у вас собирается отдавать шаблонизатор? Готовый маркап? Тот, который вместо 5 килобайт шаблона и 20 килобайт данных содержит 100 килобайт разметки? Или всё же он у вас отдаёт отдельно шаблон, отдельно данные?
_>Ну так тот же IIS скажем работает с кэшем совсем не так тривиально, как вы тут описали. А вот загрузка приложения в память именно так. )))
Ещё раз: Усложнения IIS по работе с кэшем позволяют ему порвать ваш шаблонизатор, даже если последний будет прогрет. Потому что он, в отличие от шаблонизатора, умеет хэндлить conditional get и partial requests. А с точки зрения кэша файловой системы данные ведут себя совершенно одинаково, хоть они лежат внутри .exe, хоть в отдельном файлике. Ну, разве что кодировка строковых констант может отличаться — в файлухе можно использовать UTF-8, дружелюбный к HTML, а в data segment обычно константы пишутся в кодировке, выбранной компилятором. Я не в курсе, что выбрано в D, подозреваю, что UCS-2 — в духе времени. Плюс возможности частичного обновления — при хранении файликов отдельно мы можем инвалидировать кэш локально; в случае монолитного exe замена Copyright(c) 2013 на Copyright(c) 2014 вызовет сброс всего кэша в ноль. Но это — малосущественные детали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[143]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Масло масленое. Какие параметры подставляются в шаблон?
А зачем параметры? ) Вы вообще в курсе, что такое скажем jade и каковы его возможности? )
S>Ок, давайте сначала. Что именно у вас собирается отдавать шаблонизатор? Готовый маркап? Тот, который вместо 5 килобайт шаблона и 20 килобайт данных содержит 100 килобайт разметки? Или всё же он у вас отдаёт отдельно шаблон, отдельно данные?
В сравнение с отдачей статического шаблона из файла естественно сравнивался вариант с отдачей шаблона отдельно, потому как глупо сравнивать динамику (обращение в бд и т.п.) со статикой. Но в принципе vibe.d поддерживает оба описанных сценария. А так же ещё и промежуточные варианты, например когда мы отдаём в одной html странице шаблон + данные (в формате json скажем), которые потом визуализирует клиентский js фреймворк.
S>Ещё раз: Усложнения IIS по работе с кэшем позволяют ему порвать ваш шаблонизатор, даже если последний будет прогрет. Потому что он, в отличие от шаблонизатора, умеет хэндлить conditional get и partial requests.
Хыхы, идея выдача шаблонов html страниц с докачкой весьма феерична... )
S>Я не в курсе, что выбрано в D, подозреваю, что UCS-2 — в духе времени.
Строки в D — это всего лишь алиас к "immutable T[]", где T может быть char (utf8), wchar (utf16), dchar(utf32), по желанию. Впрочем для нашей дискуссии это действительно не принципиально.
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>А зачем параметры? ) Вы вообще в курсе, что такое скажем jade и каковы его возможности? )
Нет, не в курсе. Жду, пока вы мне это расскажете. Пока что звучит как "генерация шаблонов по шаблонам", и хочется понять, чем вызван этот 2й уровень косвенности.
_>В сравнение с отдачей статического шаблона из файла естественно сравнивался вариант с отдачей шаблона отдельно, потому как глупо сравнивать динамику (обращение в бд и т.п.) со статикой. Но в принципе vibe.d поддерживает оба описанных сценария. А так же ещё и промежуточные варианты, например когда мы отдаём в одной html странице шаблон + данные (в формате json скажем), которые потом визуализирует клиентский js фреймворк.
Ок. И в каком из этих вариантов vibe.d собрался порвать и кого?
_>Хыхы, идея выдача шаблонов html страниц с докачкой весьма феерична... )
Ну, то есть про conditional get вам сказать нечего. Понятно.
_>Строки в D — это всего лишь алиас к "immutable T[]", где T может быть char (utf8), wchar (utf16), dchar(utf32), по желанию. Впрочем для нашей дискуссии это действительно не принципиально.
А как это выглядит в реальности? Можно мне показать пример статически скомпилированного шаблона, который порождает html-маркап на vibe.d?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Нет, не в курсе. Жду, пока вы мне это расскажете. Пока что звучит как "генерация шаблонов по шаблонам", и хочется понять, чем вызван этот 2й уровень косвенности.
Кроме просто удобства (автоматической корректности html, намного более ясного синтаксиса и т.п.) jade и ему подобные включают ещё и множество дополнительных возможностей по сравнению с html. Причём речь даже не о банальном императивном исполнение произвольного кода (хотя понятно какие возможности следуют из этого), а скажем о таких вещах как import. Например мы можем сделать некий шаблон common, в котором определим стандартные для всех страниц вещи (шапку, меню и т.п.), а потом использовать его во всех остальных шаблонах (конкретных страниц). Думаю программисту сразу должны быть очевидны преимущества такого инструмента, по сравнению с ручным набором отдельных html. Остальное можно глянуть например здесь http://jade-lang.com.
В случае jade (и ещё некоторых других аналогов) это всё естественно применимо как для статической генерации страниц (на компьютере разработчика), так и для динамической. Ну а в vibe.d только динамическая (правда при этом со статической компиляцией).
S>Ок. И в каком из этих вариантов vibe.d собрался порвать и кого?
Ну вы прицепились к фразе о вполне конкретном варианте. )))
S>Ну, то есть про conditional get вам сказать нечего. Понятно.
Хы, ну 304 для файлов vibe.d тоже умеет отдавать. )))
S>А как это выглядит в реальности? Можно мне показать пример статически скомпилированного шаблона, который порождает html-маркап на vibe.d?
я уже показывал пример, правда на jade. На vibe.d будет всё тоже самое, но только язык D вместо JavaScript. Если же интересуют нюансы конкретно с D, то можно глянуть здесь http://vibed.org/templates/diet.
Re[138]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Уже в который раз повторяю: это зависит от выбранной стратегии на клиенте, а не от vibe.d. Ты можешь отдавать на клиента статические js шаблоны плюс данные через ajax. Можешь отдавать js шаблоны + данные внутри одной html страницы. А можешь отдавать уже готовые html страницы без всяких скриптов, как в старом веб'е. Выбор на твой вкус, а vibe.d будет одинаково эффективно поддерживать любой из этих сценариев.
Ты никак не можешь дать простой ответ на один простой вопрос — что именно отдаётся в твоём случае. Вместо этого ты силишься дать всеобъемлющий ответ: "можно по-всякому..."
Если ты по шаблону генеришь шаблоны, то возникает естественный вопрос, откуда берутся все необходимые данные для для обработки конкретного реквеста.
I>>Если на серверве, то отдавать надо в сотни раз больше чисто из за того, что данные унуте html. Кроме того, это вызывает проблемы например с кешированием, делает невозможным использование большинтсва других оптимизаций. Например, CDN тебе так же не поможет.
_>Так сравнивать то надо конкурирующие между собой вещи, а это дополняющие друг друга... )
У тебя ничего дополняющего нет, ты отдаёшь динамику пополам со статикой. Стало быть в CDN твоё решение не влезет.
Если ты генерируешь ангуляровский шаблон по jade шаблону, то я боюсь ты делаешь двойную работу и собираешь все недостатки как серверной обработки шаблонов, так и клиентской.
Во первых, CDN и прочие отптимизации тебе не помогут, т.к. твои шаблоны суть динамика. Во вторых, задержка времени отклика тупо увеличивается из за того, что контент должен будет процесситься еще и на клиенте.
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ну да, в среднем это гораздо больше будет. Я вот книги в epub формате вижу, около 100мб в зипе. Надо объяснять, что зип жмёт текст примерно 10 к 1 ? I>>Книг может быть очень много. Вопрос — обо что встанет сделать веб-интерфейс для небольшой библиотеки, скажем в 1-10 тыс книжек ?
_>Я что-то не понял за какую собственно точку зрения ты аргументируешь. ) Ведь это как раз обычному статическому серверу придётся держать книги прямо в готовом состояние, а шаблонизатор то может без проблем и из архивов отдавать...
Ты вероятно не понял — epub уже архив, его не надо клать еще в один архив. Второе — для веб-интерфейса его придется распаковать на сервере, хотя бы для того, что бы отдать нужную юзеру страницу. После распаковки спокойно можно отдавать статику, а тебе что бы "из архивов отдавать" придется переключаться между user/kernel по сотню раз на сессию.
I>>Не рассказывай ерунды. http://www.webperformance.com/load-testing/blog/2011/11/what-is-the-fastest-webserver/
_>Ой, да я таких ссылок с любым результатом могу столько накидать... ))) Меня больше убеждают вот такие картинки: http://cdn-static.zdnet.com/i/r/story/70/00/017838/webserverjuly2013-620x359.png _>Кстати, в контексте нашей дискуссии небезынтересно взглянуть и на поведение "Other"...
И что мы видим на твоей картинке ? Бесплатное решение уровня "на коленке" более популярно, чем высокотехнологичное качественное и дорогое . Выйди на улицу и посмотри, сколько там серьёзных автомобилей, что бы современная конструкция, технологии, качественная сборка и тд и тд. Единицы процентов.
Re[146]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>Нет, не в курсе. Жду, пока вы мне это расскажете. Пока что звучит как "генерация шаблонов по шаблонам", и хочется понять, чем вызван этот 2й уровень косвенности.
_>Кроме просто удобства (автоматической корректности html, намного более ясного синтаксиса и т.п.) jade и ему подобные включают ещё и множество дополнительных возможностей по сравнению с html. Причём речь даже не о банальном императивном исполнение произвольного кода (хотя понятно какие возможности следуют из этого), а скажем о таких вещах как import. Например мы можем сделать некий шаблон common, в котором определим стандартные для всех страниц вещи (шапку, меню и т.п.), а потом использовать его во всех остальных шаблонах (конкретных страниц). Думаю программисту сразу должны быть очевидны преимущества такого инструмента, по сравнению с ручным набором отдельных html. Остальное можно глянуть например здесь http://jade-lang.com.
Ты внятно скажи,
1 какую это проблему решает и почему вот такую хрень нельзя сделать на ангуляре.
2 откуда берутся параметры для обработки конкретного реквеста
А то получается как то странно — процессить надо на сервере, т.е. никаких CDN и прочих вещей нет и быть не может, а из за ангуляра получаем все недостатки клиентской модели.
"Войны — не объявлять, мира — не подписывать, армию — распустить" @
Re[140]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>Тогда почему вы называете их "js", если они html?
_>Потому что они потом используются из клиентских js фреймворков в качестве шаблонов.
И тем не менее это html.
S>>Продолжаю непонимать — в чём тут роль серверного шаблонизатора?
_>Эээ, он их генерирует? )
Если это безусловная генерация, то получаем все прелести северной динамики — проблемы с кешами, и всякими мега-оптимизациями типа CDN. А если чтото другое, то надо знать откуда какие параметры приходят
_>Ну так эти несколько строк и не задумывались как конкурент nginx'у на рынке. )))
Если ты сказал это хорошо подумав, то должен понимать, что нгинкс уступает IIS в части отдачи статики, а твое решение стало быть, уступае даже нгинксу.
S>>Ну, тогда не стоит рассчитывать, что он хоть кого-то порвёт на отдаче статики. _>А тут кто-то предлагал vibe.d для отдачи файлов с диска? )
Ты и предлагаешь, толко передёргиваешь. Речи ведь не было про "файлы с диска". Речь была про статику. Скажем, IIS можешь вообще даже и не видеть реквестов на статику, они все обработаются через тот же CDN.
S>>У шаблонизатора будет примерно столько же случаев непрогретого кэша и промахов.
_>С чего это? После загрузки приложения в память у него будет стабильное время выдачи результата.
А длину и качество пути до сервера надо учитывать или как ?
Re[140]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
S>>У шаблонизатора будет примерно столько же случаев непрогретого кэша и промахов.
_>С чего это? После загрузки приложения в память у него будет стабильное время выдачи результата.
Кстати говоря, "загрузки приложения в память" в 99% случаев никогда не будет. Даже если ты принудительно запретишь своп, виртуальная память на этом не закончится — система мапит страницы прямо на исполнительные бинарники. Придется сделать многократный запас оперативной памяти на сервере.
Что бы получить эту самую "загрузку приложения в память", надо кроме отключения свопа запретить все остальные приложения, модули, демоны и тд и тд и тд. Аккуратно использовать динамическую памяти, ничего не хранить локально, ни в каком виде. В противном случае ты будешь получать косяки с кешем.
В итоге тебе понадобится один адский сервер, на котором будет крутиться один единственный сайт. Чуть что поменял, добавил — твоё приложение будет вытесняться в своп.
Итого, твоё приложения при всех недостатках серверной генерации шаблонов будет обходиться дороже, чем десяток деплойментов IIS.
Re[116]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, основой является совсем не это, а связь между функциями и данными (даже не типами, а экземплярами данных!), с которыми они работают.
Что за "связь между функциями и данными", да еще такая, которой нет в хаскеле и каким образом это является основой UML-диаграмм?
_>А зачем требуется какое-то специальное преобразование, если можно изначально писать писать эффективную однопроходную реализацию (как сделано в тех же диапазонах D). Причём никакой чистоты для этого не требуется.
Да, я уже понял, что вам оптимизации не нужны и даже написал об этом:
4) В конце концов выяснилось что оптимизации не нужны, потому что комбинации комбинаторов вы никогда не используете. <..>
С учетом этого опыта, я могу только констатировать что ничего ни доказать, ни продемонстрировать я вам не смогу.
Но не у всех такие скромные потребности.
_>Или же подразумевается, что компоновщик/компилятор сможет взять произвольную чужую функцию типа FilterXXX(array, pure func) с циклом по array внутри и как-то интегрировать её внутрь цикла допустим внутри map'a? ) Если так, то это конечно довольно интересно, но я пока о таком не слышал.
Программист на высокоуровневом языке не пишет какие-то "FilterXXX(array, pure func) с циклом по array внутри" а комбинирует комбинаторы. Именно на такой подход такие системы оптимизации и рассчитаны в первую очередь. Оптимизации, естественно, работают с "чужими функциями" тоже, если они соответствуют некоторым требованиям. Система оптимизации для списков в стандартной библиотеке foldr/build-fusion требует для того чтоб функция была хорошим консьюмером и продьюсером написания функции с использованием функций foldr и build. В случае stream-fusion из пакета vector можно писать обычные функции работающие с итераторами.
Такой вот filter
filter f (Stream step s n) = Stream step' s (toMax n) where
step' s = case step s of
Yield x s' | f x -> Yield x s'
| otherwise -> Skip s'
Skip s' -> Skip s'
Done -> Done
будет "интегрирован внутрь цикла" вот такого map
map f (Stream step s n) = Stream step' s n where
step' s = case step s of
Yield x s' -> Yield (f x) s'
Skip s' -> Skip s'
Done -> Done
в результате оптимизаций общего назначения. тут требование заключается в том, чтоб "итератор"
data Step s a = Yield a s
| Skip s
| Done
был нерекурсивным АлгТД.
_>"Пока нет" — это справедливо. ) Я кстати даже не уверен, что это "пока" когда-нибудь исправится, т.к. что-то не очень много желающих заниматься этим направлением. Но главное то, что теоретическая возможность вполне есть, причём без всяких ужасных ограничений на язык (типа хаскельских). О чём я собственно и говорил.
Ну или один конвейер на всю программу как тут.
_>Ну так вы не правильно статистически обрабатываете — не учитываете, что отклонение измерения от истинного значения идёт только в одну сторону. )
Если речь идет о сотых секунды то нет, не в одну. Что я, вроде бы, понятно объяснил. Если бы речь шла о секундах — да, можно считать, что в одну.
_>я же исключительно практик, а не теоретик, играющийся с маргинальными языками.
Каким образом тогда оказалось, что вы знаете D?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[118]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то в том моём коде по сути используется своеобразный аналог функции realloc из C.
Каким образом это противоречит тому, что у вас аллокации "виртуальные"?
_>Так вот если заменить его на просто alloc, то по сути ничего не изменится.
Конечно изменится.
_>Просто ручной, а не автоматической.
Вот именно. "Ручная оптимизация" упрощенно говоря везде есть. А вы заявляете некую "поддержку".
_>Ну так про отсутствие в D готовых библиотек подобной оптимизации мы уже говорили, но как видно, их написание не представляет вообще никакого труда.
Это точно — потому их никто и не делает. Для программиста написание библиотек, которые никакого труда не требуют — оскорбительно, никто за такое не возьмется.
_>Я уже не раз повторял: область памяти, на которую ссылается такой объект является абсолютно неизменной всё время жизни объекта.
Конечно нет.
auto a = IArray!(10, int).Make()~1~2~3;
auto a1 = a~4;
auto a2 = a~5;
a1[].writeln;
a2[].writeln;
выдаст
[1, 2, 3, 5]
[1, 2, 3, 5]
_>Почему вы ставите "в ответственность" такому объекту изменение памяти следующей непосредственно за его блоком, мне не понятно.
Постарайтесь понять.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[117]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Что за "связь между функциями и данными", да еще такая, которой нет в хаскеле и каким образом это является основой UML-диаграмм?
Так это же объединение функций и данных в рамках одного класса (в uml это соответственно выражается, как рисование их внутри одного прямоугольника). И это не основа всего uml, а основа ООП и соответственно основа диаграммы классов uml.
K>Да, я уже понял, что вам оптимизации не нужны и даже написал об этом: K>Но не у всех такие скромные потребности.
Ну если написание уже оптимизированного кода не требует вообще никаких дополнительных усилий (например как в случае диапазонов D), то действительно зачем нам возможность писать неоптимизированный и потом ждать чудес от оптимизатора? )
K>Программист на высокоуровневом языке не пишет какие-то "FilterXXX(array, pure func) с циклом по array внутри" а комбинирует комбинаторы. Именно на такой подход такие системы оптимизации и рассчитаны в первую очередь. Оптимизации, естественно, работают с "чужими функциями" тоже, если они соответствуют некоторым требованиям. Система оптимизации для списков в стандартной библиотеке foldr/build-fusion требует для того чтоб функция была хорошим консьюмером и продьюсером написания функции с использованием функций foldr и build. В случае stream-fusion из пакета vector можно писать обычные функции работающие с итераторами. K>Такой вот filter K>
K>filter f (Stream step s n) = Stream step' s (toMax n) where
K> step' s = case step s of
K> Yield x s' | f x -> Yield x s'
K> | otherwise -> Skip s'
K> Skip s' -> Skip s'
K> Done -> Done
K>
K>будет "интегрирован внутрь цикла" вот такого map K>
K>map f (Stream step s n) = Stream step' s n where
K> step' s = case step s of
K> Yield x s' -> Yield (f x) s'
K> Skip s' -> Skip s'
K> Done -> Done
K>
K>в результате оптимизаций общего назначения. тут требование заключается в том, чтоб "итератор" K>
K>data Step s a = Yield a s
K> | Skip s
K> | Done
K>
K>был нерекурсивным АлгТД.
Ааа, ну т.е. всё как я и думал, работаем только для заранее предусмотренных случаев. И в чём тогда принципиальное отличие от такой же оптимизации диапазонов D? Там тоже всё отлично работает, в том числе и для пользовательских функций (написанных в соответствие с техникой диапазонов) и при этом без всяких требований чистоты.
K>Каким образом аннотации эффектов являются "ужасным ограничением", а аннотации чистоты — нет?
Вы так и не поняли? ) Ключевой вопрос не в разновидностях синтаксиса (в конце концов у всех разные вкусы и на планете полно поклонников и java стиля и perl стиля), а в обязательности ограничений. Ключевой подход C++ заключается в том, что мы используем только те возможности языка (включая и различные варианты ограничений и самоконтроля), которые выбираем сами. Причём остальное совершенно не мешает нам жить, если мы его не трогаем. Этого же принципа во многом придерживаются и другие приятные мне языки, типа Питона или D, а вот Хаскель его существенно нарушает.
_>>А как насчёт таких http://www.rsdn.ru/forum/philosophy/5676154
? ) K>Ну или один конвейер на всю программу как тут.
Так больше и не лезет в подобное приложение. )))
K>Если речь идет о сотых секунды то нет, не в одну. Что я, вроде бы, понятно объяснил. Если бы речь шла о секундах — да, можно считать, что в одну.
Эээ, где было объяснение такого интересного факта, как отклонение измерения времени работы алгоритма в меньшую сторону от истинного? )
_>>я же исключительно практик, а не теоретик, играющийся с маргинальными языками. K>Каким образом тогда оказалось, что вы знаете D?
А причём тут знание языка? Я их много разных знаю и значительную часть явно можно назвать маргинальными. Однако я не использую их в каких-то серьёзных проектах. Как впрочем и D пока что. Хотя надеюсь, что когда-нибудь он всё же встанет на одну ступень с C/C++.
Re[119]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Так вот если заменить его на просто alloc, то по сути ничего не изменится. K>Конечно изменится.
Снаружи ничего не изменится, кроме быстродействия естественно. )
K>Вот именно. "Ручная оптимизация" упрощенно говоря везде есть. А вы заявляете некую "поддержку".
Эээ, мы вообще то говорили не про оптимизацию, а про иммутабельность. Её поддержка есть далеко не везде. И на мой взгляд ключевым является именно этот факт, т.к. его не изменишь без переделки самого языка и компилятора. А уж если сама иммутабельность в языке есть (именно это я и называю поддержкой), то написать специальные оптимизации под такие данные уже не проблема.
_>>Ну так про отсутствие в D готовых библиотек подобной оптимизации мы уже говорили, но как видно, их написание не представляет вообще никакого труда. K>Это точно — потому их никто и не делает. Для программиста написание библиотек, которые никакого труда не требуют — оскорбительно, никто за такое не возьмется.
Видимо не особо интересно это практикам... А D написан как раз матёрым практиками по C++ для себя.
K>Конечно нет.
K>
K> auto a = IArray!(10, int).Make()~1~2~3;
K> auto a1 = a~4;
K> auto a2 = a~5;
K> a1[].writeln;
K> a2[].writeln;
K>
K>выдаст K>
K>[1, 2, 3, 5]
K>[1, 2, 3, 5]
K>
Хы, так речь же шла про конкретно тот код, а не про произвольное использование класса оттуда в других проектах. Естественно, что если бы я решил выложить этот класс публично в виде библиотеки, то там учитывался бы этот нюанс и в случае добавления к старой версии происходило бы или копирование или срабатывал бы запрет (в зависимости от назначение класса). Но для решения нашей конкретной форумной задачки это не требовалось, т.к. там добавление было строго под контролем.
И как я понимаю, вы не может показать мне точку мутабельности в том моём коде, не смотря на все громкие заявления перед этим.
Re[139]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты никак не можешь дать простой ответ на один простой вопрос — что именно отдаётся в твоём случае. Вместо этого ты силишься дать всеобъемлющий ответ: "можно по-всякому..." I>Если ты по шаблону генеришь шаблоны, то возникает естественный вопрос, откуда берутся все необходимые данные для для обработки конкретного реквеста.
В каком это "моём случае"? ) Мы говорим про какой-то конкретный мой проект или же просто про vibe.d? ) Мне казалось что про последнее. И в таком случае ответ "можно по-всякому" является абсолютно точным.
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты вероятно не понял — epub уже архив, его не надо клать еще в один архив. Второе — для веб-интерфейса его придется распаковать на сервере, хотя бы для того, что бы отдать нужную юзеру страницу. После распаковки спокойно можно отдавать статику, а тебе что бы "из архивов отдавать" придется переключаться между user/kernel по сотню раз на сессию.
Всё равно не понял какие варианты ты сравниваешь. Опиши подробно обе сравниваемые архитектуры.
I>И что мы видим на твоей картинке ? Бесплатное решение уровня "на коленке" более популярно, чем высокотехнологичное качественное и дорогое . Выйди на улицу и посмотри, сколько там серьёзных автомобилей, что бы современная конструкция, технологии, качественная сборка и тд и тд. Единицы процентов.
IIS — это не дорогое и качественное, а скорее такой средний класс. ) А дорогое — это кастомый продукт, разработанный профи, типа как у гугла. Так вот наш средний класс что-то падает, а nginx (интересно какая у него аналогия из мира авто, самодельный спорткар?) наоборот растёт...
Re[147]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты внятно скажи, I>1 какую это проблему решает и почему вот такую хрень нельзя сделать на ангуляре.
В принципе подобное вполне реализуемо на основе клиентских js скриптов. Но я навскидку не могу вспомнить таких готовых решений. Возможно их даже и нет, хотя теоретически не вижу каких-то принципиальных препятствий.
Что касается angular'a, то с помощью него такое в принципе не реализуемо, т.к. у него совсем другая архитектура. Так что в случае пожелания совмещения подобных техник, придётся строить своеобразный конвейер по загрузке и обработке. В начале некий препроцессор грузит набор (там же не 1 в 1 преобразуется) исходников, а потом полученные html шаблоны поступают на вход angular'а.
I>2 откуда берутся параметры для обработки конкретного реквеста
Что такое "параметры для обработки конкретного реквеста"?
Re[141]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
_>>Ну так эти несколько строк и не задумывались как конкурент nginx'у на рынке. ))) I>Если ты сказал это хорошо подумав, то должен понимать, что нгинкс уступает IIS в части отдачи статики, а твое решение стало быть, уступае даже нгинксу.
Причём тут моё решение какое-то? ) Ты вообще читаешь на что отвечаешь? ))) Там речь шла про несколько строк на Питоне от Cyberax.
_>>А тут кто-то предлагал vibe.d для отдачи файлов с диска? ) I>Ты и предлагаешь, толко передёргиваешь. Речи ведь не было про "файлы с диска". Речь была про статику. Скажем, IIS можешь вообще даже и не видеть реквестов на статику, они все обработаются через тот же CDN.
Ну так о том и речь, что vibe.d умеет отдавать статические html через шаблонизатор даже быстрее, чем будет их отдавать с диска обычный сервер.
Да, кстати, и с чего ты взял, что эти данные нельзя кэшировать далее? ) Вообще то управление кэшированием находится под полным упралением программиста в vibe.d. Как укажешь, так и будет.
I>А длину и качество пути до сервера надо учитывать или как ?
Кстати, если уж тебе так нравятся решения с клиентскими шаблонами... А ты можешь рассказать что думают поисковые машины о сайтах, на которых все данные на страницах грузятся исключительно через ajax? )
Re[141]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Кстати говоря, "загрузки приложения в память" в 99% случаев никогда не будет. Даже если ты принудительно запретишь своп, виртуальная память на этом не закончится — система мапит страницы прямо на исполнительные бинарники. Придется сделать многократный запас оперативной памяти на сервере.
Бред какой-то ты написал. ) Да, изначально приложение не загружено полностью, но после разового исполнения уже будет всё нормально. Полный аналог "прогрева кэша" у обычных серверов. Только вот у них там другой алгоритм несколько — не каждый запрос и не обязательно с первого раза попадает в кэш.
I>Что бы получить эту самую "загрузку приложения в память", надо кроме отключения свопа запретить все остальные приложения, модули, демоны и тд и тд и тд. Аккуратно использовать динамическую памяти, ничего не хранить локально, ни в каком виде. В противном случае ты будешь получать косяки с кешем.
Вообще какие-то потоки бреда. )))
I>В итоге тебе понадобится один адский сервер, на котором будет крутиться один единственный сайт. Чуть что поменял, добавил — твоё приложение будет вытесняться в своп.
Ну собственно да, один сервер под одного такого демона. Только вот хватает при этом самого дохлого vps, хотя при обычных технологиях такой сервер не держит больше десятка клиентов. )))
Re[142]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Бред какой-то ты написал. ) Да, изначально приложение не загружено полностью, но после разового исполнения уже будет всё нормально. Полный аналог "прогрева кэша" у обычных серверов. Только вот у них там другой алгоритм несколько — не каждый запрос и не обязательно с первого раза попадает в кэш.
Не будет "всё нормально". Хоть в виндовсе, хоть в линуксе, крайне сложно заставить систему отказаться от свопа. О чем, собственно, и сообщают тулы.
I>>Что бы получить эту самую "загрузку приложения в память", надо кроме отключения свопа запретить все остальные приложения, модули, демоны и тд и тд и тд. Аккуратно использовать динамическую памяти, ничего не хранить локально, ни в каком виде. В противном случае ты будешь получать косяки с кешем.
_>Вообще какие-то потоки бреда. )))
У тебя вероятно RAM исчисляется терабайтами. Это объясняет, почему тебе не понятно, что такое своп.
I>>В итоге тебе понадобится один адский сервер, на котором будет крутиться один единственный сайт. Чуть что поменял, добавил — твоё приложение будет вытесняться в своп.
_>Ну собственно да, один сервер под одного такого демона. Только вот хватает при этом самого дохлого vps, хотя при обычных технологиях такой сервер не держит больше десятка клиентов. )))
Приехали — виртуальный хостинг означает, что физическую память разделяют
1 целая куча других экземпляров VPS — иначе нет смысла подымать VPS
2 хостовая операционная система
Для твоего сайта должно быть выделено достаточно большое количество страниц физической памяти. Вероятность такого исхода стремится к нулю — именно из за vps.
Проблемы со свопом только усугубляются. Без нагрузки все шоколадно. А под нагрузкой все еще хуже, чем под обычным физическим сервером.
Что характерно, под нагрузкой в первую очередь и очень сильно страдает именно latency, про который мы все время и говорим.
Более того — совершенно не важно, кто будет источником нагрузки, твое приложение или приложение на другом vps на том же железе.
Re[142]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>>>А тут кто-то предлагал vibe.d для отдачи файлов с диска? ) I>>Ты и предлагаешь, толко передёргиваешь. Речи ведь не было про "файлы с диска". Речь была про статику. Скажем, IIS можешь вообще даже и не видеть реквестов на статику, они все обработаются через тот же CDN.
_>Ну так о том и речь, что vibe.d умеет отдавать статические html через шаблонизатор даже быстрее, чем будет их отдавать с диска обычный сервер.
Объясняю еще раз — речь не про отдачу файлов. Речь про отдачу статики.
В моей схеме сервер может вообще _не_ отдавать статику. За счет оптимизаций время обработки запроса стремится к нулю справа.
В твоем случае такого нет и быть не может, потому, что твоя статика на самом деле динамика. Из этого следуеют что тот же CDN в твоём случае невозможен.
_>Да, кстати, и с чего ты взял, что эти данные нельзя кэшировать далее? ) Вообще то управление кэшированием находится под полным упралением программиста в vibe.d. Как укажешь, так и будет.
Я хочу что бы статика кешировалась вне моего сервера. То есть — вообще. Желательно поближе к клиенту и если можно то и вообще прямо на нём. Это очевидно — ангуляр конкретной версии никогда не экспайрится, в отличие от твоих темплейтов. А это значит, что его в 100% случае можно отдавать вообще как угодно, через тот же CDN который гарантировано быстрее любого процессинга на vide.d
I>>А длину и качество пути до сервера надо учитывать или как ?
_>Кстати, если уж тебе так нравятся решения с клиентскими шаблонами...
Я скипнул — ответь прямо на заданый вопрос. Повторяю — надо ли учитывать длину и качество пути от клиента на сервер и обратно ?
Re[148]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты внятно скажи, I>>1 какую это проблему решает и почему вот такую хрень нельзя сделать на ангуляре.
_>В принципе подобное вполне реализуемо на основе клиентских js скриптов. Но я навскидку не могу вспомнить таких готовых решений. Возможно их даже и нет, хотя теоретически не вижу каких-то принципиальных препятствий.
Вообще от ангуляр весь целиком именно про это.
_>Что касается angular'a, то с помощью него такое в принципе не реализуемо, т.к. у него совсем другая архитектура. Так что в случае пожелания совмещения подобных техник, придётся строить своеобразный конвейер по загрузке и обработке. В начале некий препроцессор грузит набор (там же не 1 в 1 преобразуется) исходников, а потом полученные html шаблоны поступают на вход angular'а.
Алё — задача показать общие для всех страниц элементы — футеры, меню и прочие вещи. Это делается легко и просто. Директивы ангуляра творят чудеса.
I>>2 откуда берутся параметры для обработки конкретного реквеста _>Что такое "параметры для обработки конкретного реквеста"?
Обычно это юзерские данные всех возможных сортов.
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты вероятно не понял — epub уже архив, его не надо клать еще в один архив. Второе — для веб-интерфейса его придется распаковать на сервере, хотя бы для того, что бы отдать нужную юзеру страницу. После распаковки спокойно можно отдавать статику, а тебе что бы "из архивов отдавать" придется переключаться между user/kernel по сотню раз на сессию.
_>Всё равно не понял какие варианты ты сравниваешь. Опиши подробно обе сравниваемые архитектуры.
Я не сравнию, я спрашиваю у тебя, как это можно сделать на твоих мега-технологиях. Ты ничего внятно сказать не можешь, ощущение, что архив у тебя сам по себе прочитается и распакуется за время ноль, вместе с отдачей клиенту.
_>IIS — это не дорогое и качественное, а скорее такой средний класс. ) А дорогое — это кастомый продукт, разработанный профи, типа как у гугла. Так вот наш средний класс что-то падает, а nginx (интересно какая у него аналогия из мира авто, самодельный спорткар?) наоборот растёт...
IIS это и есть дорогое и качественное. На ём реализуются высоконагруженые решения.
Re[140]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>В каком это "моём случае"? ) Мы говорим про какой-то конкретный мой проект или же просто про vibe.d? ) Мне казалось что про последнее. И в таком случае ответ "можно по-всякому" является абсолютно точным.
Я задавал простой вопрос — как делается в твоём случае, с которого все началось. Там было какое то чудо навроде мега-серверных-темплейтов, с аджаксом и прочими чудесами.
Это уже позже ты решил увиливать и притягивать все возможные и невозможные баззворды.
Re[118]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так это же объединение функций и данных в рамках одного класса (в uml это соответственно выражается, как рисование их внутри одного прямоугольника). И это не основа всего uml, а основа ООП и соответственно основа диаграммы классов uml.
Группировка "внутри одного прямоугольника" определяется архитектурными соображениями. Соответствует ли ей связь а-ля симула-ООП — деталь реализации языка, к архитектуре и UML никакого значения не имеющая.
_>Ну если написание уже оптимизированного кода не требует вообще никаких дополнительных усилий
Это фантастика.
_>(например как в случае диапазонов D)
Как мы узнали из опыта, в случае диапазонов D оптимизации не сработали и вам пришлось конвейер переписать в потрясающую строчку
p.find!(q{b%a==0||a^^2>b})(v).front()^^2>v
умопомрачительной читаемости.
_>то действительно зачем нам возможность писать неоптимизированный и потом ждать чудес от оптимизатора? )
Я же говорю, человеку, который считает, что преимущества высокоуровневых языков не нужны в принципе, я доказать ничего не смогу.
_>Ааа, ну т.е. всё как я и думал, работаем только для заранее предусмотренных случаев.
Да, все оптимизации работают только для "заранее предусмотренных случаев". Просто таких случаев может быть достаточно много или недостаточно.
_>И в чём тогда принципиальное отличие от такой же оптимизации диапазонов D?
В том, что в хаскеле оптимизация работает, а в Ди — нет. Это довольно важное отличие.
_>Там тоже всё отлично работает, в том числе и для пользовательских функций (написанных в соответствие с техникой диапазонов)
В обсуждаемом примере не работает.
_>и при этом без всяких требований чистоты.
Это означает, что в тех случаях, когда она работает (если такие есть) — преобразования некорректны в общем случае, и правильность кода остается на совести программиста. такой подход плохо масштабируется.
_>Вы так и не поняли? ) Ключевой вопрос не в разновидностях синтаксиса (в конце концов у всех разные вкусы и на планете полно поклонников и java стиля и perl стиля), а в обязательности ограничений.
Вы так и не поняли? ) Ключевой вопрос не в разновидностях синтаксиса, а в обязательности ограничений. Если ограничения не обязательны — то и возможности, которые основываются на таких ограничениях недоступны.
_>Ключевой подход C++ заключается в том, что мы используем только те возможности языка (включая и различные варианты ограничений и самоконтроля), которые выбираем сами.
Поэтому никакие нормальные возможности для выбора в C++ и не доступны, только недоделанные. Да, это закономерное следствие ключевого подхода "не используем не платим". Поскольку никаких нетривиальных возможностей не требующих платить в случае неиспользования не существует — никаких интересных возможностей и в C++ нет. В этом отличия между высокоуровневыми и низкоуровневыми языками и заключается.
_>Причём остальное совершенно не мешает нам жить, если мы его не трогаем.
Но если вдруг потрогаем, серьезно нам жить не поможет. Чудес не бывает.
_>Этого же принципа во многом придерживаются и другие приятные мне языки, типа Питона или D, а вот Хаскель его существенно нарушает.
Как раз скриптовые языки — чемпионы по предъявлению счетов за неиспользуемые возможности.
_>Так больше и не лезет в подобное приложение. )))
Любой цикл, который в вашем приложении, я уверен, не один может быть представлен как комбинация комбинаторов с улучшением читаемости. Вот только возможно такое при работающей в значительном числе случаев оптимизации.
K>>Если речь идет о сотых секунды то нет, не в одну. Что я, вроде бы, понятно объяснил. Если бы речь шла о секундах — да, можно считать, что в одну.
_>Эээ, где было объяснение такого интересного факта, как отклонение измерения времени работы алгоритма в меньшую сторону от истинного? )
Если ваши часы обновляются раз в 0,02сек. то вроде бы очевидно, что измерение интервала времени по таким часам может быть меньше действительного примерно на 0,02сек. Вы когда-нибудь часами пользовались? Или линейкой?
_>>>я же исключительно практик, а не теоретик, играющийся с маргинальными языками. K>>Каким образом тогда оказалось, что вы знаете D? _>А причём тут знание языка?
Тогда не понятно. Если вы не "играющийся с маргинальными языками", то вроде бы это означает, что вы с маргинальными языками не играете. Где тут ошибка?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[120]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Конечно изменится. _>Снаружи ничего не изменится, кроме быстродействия естественно. )
Изменится результат работы программы в моем примере.
_>Эээ, мы вообще то говорили не про оптимизацию, а про иммутабельность. Её поддержка есть далеко не везде. И на мой взгляд ключевым является именно этот факт, т.к. его не изменишь без переделки самого языка и компилятора. А уж если сама иммутабельность в языке есть (именно это я и называю поддержкой), то написать специальные оптимизации под такие данные уже не проблема.
Я же говорю, я понял, что иммутабельностью вы называете возможность кастить между двумя типами, один из которых вроде как иммутабельный (на самом деле нет). Такое достигается без переделки языка написанием/генерированием иммутабельных оберток для мутабельных классов.
Впрочем, если вы не видите принципиальной разницы между ручной и автоматической оптимизацией, удивительно видеть, как вы проводите разницу между ручной и автоматической проверкой (которую вы в демонстрируемых примерах сами же легко обходите).
_>Видимо не особо интересно это практикам... А D написан как раз матёрым практиками по C++ для себя.
Многим "матерым практикам по X" вообще ничего кроме обоснования ненужности отсутствующего в X отсутствием в X не интересно. Самопровозглашенные матерые практики они такие.
_>Хы, так речь же шла про конкретно тот код, а не про произвольное использование класса оттуда
Речь шла про иммутабельность структуры данных. Естественно, для любой мутабельной структуры данных можно написать код, в котором ее мутабельность не наблюдается. Это очень просто, например такой вот код "" не содержит наблюдаемых изменений любой возможной мутабельной структуры данных на почти любом языке.
При таком подходе разницы между мутабельными и иммутабельными структурами действительно нет, поздравляю.
_>Естественно, что если бы я решил выложить этот класс публично в виде библиотеки,
Вы его публично выложили на форум в качестве якобы "иммутабельной" структуры данных.
При этом не понятно, зачем там вообще все эти приседания с immutable.
_>то там учитывался бы этот нюанс и в случае добавления к старой версии происходило бы или копирование или срабатывал бы запрет (в зависимости от назначение класса)
Да, да. Структура данных которая меняется на месте и которую нужно копировать полностью для получения версии называется "мутабельной", "эфемерной". К иммутабельности и персистентности это никакого отношения не имеет.
_>Но для решения нашей конкретной форумной задачки это не требовалось, т.к. там добавление было строго под контролем.
Не знаю, что вы называете "нашей" задачкой, но для решения моей конкретной задачи много чего требуется и в основном ничего из этих требований в ваших "решениях" не выполняется.
_>И как я понимаю, вы не может показать мне точку мутабельности в том моём коде, не смотря на все громкие заявления перед этим.
Я вам ее показал, но как обычно, вы в упор не видите то, что вам показывают. Впрочем, остается еще вариант, что вы под словами "точка мутабельности" понимаете что-то совершенно невообразимое.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[143]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не будет "всё нормально". Хоть в виндовсе, хоть в линуксе, крайне сложно заставить систему отказаться от свопа. О чем, собственно, и сообщают тулы.
А зачем отключать своп на сервере? )
I>У тебя вероятно RAM исчисляется терабайтами. Это объясняет, почему тебе не понятно, что такое своп.
И зачем мне терабайты для загрузки программы размером в несколько мегабайт? )
I>Приехали — виртуальный хостинг означает, что физическую память разделяют I>1 целая куча других экземпляров VPS — иначе нет смысла подымать VPS I>2 хостовая операционная система
I>Для твоего сайта должно быть выделено достаточно большое количество страниц физической памяти. Вероятность такого исхода стремится к нулю — именно из за vps.
I>Проблемы со свопом только усугубляются. Без нагрузки все шоколадно. А под нагрузкой все еще хуже, чем под обычным физическим сервером. I>Что характерно, под нагрузкой в первую очередь и очень сильно страдает именно latency, про который мы все время и говорим.
I>Более того — совершенно не важно, кто будет источником нагрузки, твое приложение или приложение на другом vps на том же железе.
Очаровательно) Ты мне тут излагаешь свои теории, а я тебе рассказываю практику. Что всё отлично работает. Причём на таком же железе классическая конфигурация (LAMP) просто дохнет от малейшей нагрузки. Нормальная конфигурация (nginx + python и т.п.) в принципе работает, но при увеличение числа клиентов быстро начинает подтормаживать. А вот обсуждаемая штука спокойно летает даже на этой дохлой железке.
Re[143]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Объясняю еще раз — речь не про отдачу файлов. Речь про отдачу статики.
I>В моей схеме сервер может вообще _не_ отдавать статику. За счет оптимизаций время обработки запроса стремится к нулю справа.
I>В твоем случае такого нет и быть не может, потому, что твоя статика на самом деле динамика. Из этого следуеют что тот же CDN в твоём случае невозможен.
Почему не возможен то? ) Кэширование зависит от возвращаемых заголовков, а мы ими полностью управляем. )
I>Я хочу что бы статика кешировалась вне моего сервера. То есть — вообще. Желательно поближе к клиенту и если можно то и вообще прямо на нём. Это очевидно — ангуляр конкретной версии никогда не экспайрится, в отличие от твоих темплейтов. А это значит, что его в 100% случае можно отдавать вообще как угодно, через тот же CDN который гарантировано быстрее любого процессинга на vide.d
Ну на клиенте, так на клиенте — всё в твоих руках.
I>Я скипнул — ответь прямо на заданый вопрос. Повторяю — надо ли учитывать длину и качество пути от клиента на сервер и обратно ?
В нашей дискуссии не надо, т.к. работа с данными после выдачи с сервера не зависит от применяемого на сервере решения. А так в принципе это конечно же один из важнейших моментов.
Да, ну так и что у нас с обработкой поисковыми машинами чисто ajax'ых страниц? )
Re[149]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Алё — задача показать общие для всех страниц элементы — футеры, меню и прочие вещи. Это делается легко и просто. Директивы ангуляра творят чудеса.
Ну покажи пример. )
Re[137]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Я не сравнию, я спрашиваю у тебя, как это можно сделать на твоих мега-технологиях. Ты ничего внятно сказать не можешь, ощущение, что архив у тебя сам по себе прочитается и распакуется за время ноль, вместе с отдачей клиенту.
ОК, тогда опиши подробно какую задачку надо решить и я скажу о вариантах на vibe.d.
I>IIS это и есть дорогое и качественное. На ём реализуются высоконагруженые решения.
Вот как раз в области высоконагруженных он существенно устипил nginx'у. Ещё год назад об это статья была подробная.
Re[119]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Группировка "внутри одного прямоугольника" определяется архитектурными соображениями. Соответствует ли ей связь а-ля симула-ООП — деталь реализации языка, к архитектуре и UML никакого значения не имеющая.
Т.е. всё снова сводится к тому, что вы предлагаете рисовать виртуальное ООП для Хаскеля. Мы же это уже обсуждали — мне уже как-то надоело ходить по кругу...
K>Как мы узнали из опыта, в случае диапазонов D оптимизации не сработали и вам пришлось конвейер переписать в потрясающую строчку K>
K>p.find!(q{b%a==0||a^^2>b})(v).front()^^2>v
K>
K>умопомрачительной читаемости.
Так это же какая-то недоработка конкретной функции, а не принципиальная проблема архитектуры. Зачем использовать подобные демагогические аргументы во вроде как не базарной дискуссии?
K>В том, что в хаскеле оптимизация работает, а в Ди — нет. Это довольно важное отличие.
С map'ми всё отлично работает, как вы уже видели. А то, что вам посчастливилось наткнуться на какую-то недоработка стандартной библиотеки D при первом же знакомстве с языком, — это конечно нестандартное "везение". )))
_>>и при этом без всяких требований чистоты. K>Это означает, что в тех случаях, когда она работает (если такие есть) — преобразования некорректны в общем случае, и правильность кода остается на совести программиста. такой подход плохо масштабируется.
Фокус в том, что там нет каких-то преобразований, а есть стандартный подход, прописанный в документации. Кстати, тот же IEnumerable в C# хотя и заметно послабее, но тоже ведь из этой области...
_>>Вы так и не поняли? ) Ключевой вопрос не в разновидностях синтаксиса (в конце концов у всех разные вкусы и на планете полно поклонников и java стиля и perl стиля), а в обязательности ограничений. K>Вы так и не поняли? ) Ключевой вопрос не в разновидностях синтаксиса, а в обязательности ограничений. Если ограничения не обязательны — то и возможности, которые основываются на таких ограничениях недоступны.
Ну вот здесь у нас с вами и находится принципиальное различие во взглядах. )
K>Поэтому никакие нормальные возможности для выбора в C++ и не доступны, только недоделанные. Да, это закономерное следствие ключевого подхода "не используем не платим". Поскольку никаких нетривиальных возможностей не требующих платить в случае неиспользования не существует — никаких интересных возможностей и в C++ нет. В этом отличия между высокоуровневыми и низкоуровневыми языками и заключается.
Да да. ) Только вот переход вверх возможен (написанием своего кода, подключением готового из библиотеки), а переход вниз обычно нет... )
_>>Причём остальное совершенно не мешает нам жить, если мы его не трогаем. K>Но если вдруг потрогаем, серьезно нам жить не поможет. Чудес не бывает.
По разному бывает. Частенько требуется не просто использовать какую-то возможность языка, а подключить мощную библиотеку, которая в итоге существенно меняет язык. )
K>Любой цикл, который в вашем приложении, я уверен, не один может быть представлен как комбинация комбинаторов с улучшением читаемости. Вот только возможно такое при работающей в значительном числе случаев оптимизации.
Да, циклов много, но большая часть из них написана на спец. языке, компилируемом в simd инструкции.
K>Если ваши часы обновляются раз в 0,02сек. то вроде бы очевидно, что измерение интервала времени по таким часам может быть меньше действительного примерно на 0,02сек. Вы когда-нибудь часами пользовались? Или линейкой?
Ааа вы всё про это... Ну это же меньше процента погрешность. А ведь у вас перед усреднением разброс был существенно больше, не так ли? )
Да, и кстати на счёт 16 мс — это ещё не факт. Многий софт (включая например Хром) меняет это значение до 1 мс. Из-за чего как раз недавно были разборки, т.к. на мобильных устройствах это вызывало повышенный расход батареи.
K>Тогда не понятно. Если вы не "играющийся с маргинальными языками", то вроде бы это означает, что вы с маргинальными языками не играете. Где тут ошибка?
Не знаю что вам непонятно. ) Знать язык и использовать его — это абсолютно разные вещи. Знаю я много языков, использую в реальных проектах очень мало.
Re[121]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Я же говорю, я понял, что иммутабельностью вы называете возможность кастить между двумя типами, один из которых вроде как иммутабельный (на самом деле нет). Такое достигается без переделки языка написанием/генерированием иммутабельных оберток для мутабельных классов. K>Впрочем, если вы не видите принципиальной разницы между ручной и автоматической оптимизацией, удивительно видеть, как вы проводите разницу между ручной и автоматической проверкой (которую вы в демонстрируемых примерах сами же легко обходите).
Просто я существенно разделяю, закладываемое в языке, и добавляемое в библиотеках. Для меня хорош такой язык, который позволяет сделать практически всё что угодно с помощью дополнительных библиотек или своего кода. При этом стандартная поставка не так принципиальна.
В этом смысле D занимает странное положение. По расширяемости он существенно превосходит и C++, но при этом в силу пока небольшого сообщества, библиотек на все случаи жизни пока нет. В то время как в C++ есть совершенно невероятные библиотеки на все случая жизни, которые выжимают из языка уже даже больше, чем он может дать.
K>Многим "матерым практикам по X" вообще ничего кроме обоснования ненужности отсутствующего в X отсутствием в X не интересно. Самопровозглашенные матерые практики они такие.
Я думаю что очень многие программисты мечтали бы иметь такую репутацию, как авторы D. )
K>Речь шла про иммутабельность структуры данных. Естественно, для любой мутабельной структуры данных можно написать код, в котором ее мутабельность не наблюдается. Это очень просто, например такой вот код "" не содержит наблюдаемых изменений любой возможной мутабельной структуры данных на почти любом языке. K>При таком подходе разницы между мутабельными и иммутабельными структурами действительно нет, поздравляю.
О, наконец то вы это осознали. )
K>Вы его публично выложили на форум в качестве якобы "иммутабельной" структуры данных. K>При этом не понятно, зачем там вообще все эти приседания с immutable.
Кстати говоря в D immutable имеет важный смысл при работе с многопоточностью в D.
K>Я вам ее показал, но как обычно, вы в упор не видите то, что вам показывают. Впрочем, остается еще вариант, что вы под словами "точка мутабельности" понимаете что-то совершенно невообразимое.
Если признать вашу логику, то тогда любые данные в любых языках выделенные не с помощью прямого вызова VirtualAlloc не могут быть иммутабельными. )
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И зачем мне терабайты для загрузки программы размером в несколько мегабайт? )
Опять про белого бычка. Если у вас вся статика отдаётся программой размером в несколько мегабайт, то и аналогичный набор статических файлов будет весить несколько мегабайт, и будет отдаваться в худшем случае из кэша ФС. А в хорошем случае он будет отдаваться сразу из kernel-кэша. Поэтому ваша "программа" никого никогда не порвёт.
_>Очаровательно) Ты мне тут излагаешь свои теории, а я тебе рассказываю практику. Что всё отлично работает. Причём на таком же железе классическая конфигурация (LAMP) просто дохнет от малейшей нагрузки.
Классическая конфигурация — это гарантированный тормоз, т.к. в ней участвуют одновременно самый неэффективный HTTP-демон и самый неэффективный скриптовый движок.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Опять про белого бычка. Если у вас вся статика отдаётся программой размером в несколько мегабайт, то и аналогичный набор статических файлов будет весить несколько мегабайт, и будет отдаваться в худшем случае из кэша ФС. А в хорошем случае он будет отдаваться сразу из kernel-кэша. Поэтому ваша "программа" никого никогда не порвёт.
Да на этой машине Windows Server с IIS вообще наверное не запустятся. )))
S>Классическая конфигурация — это гарантированный тормоз, т.к. в ней участвуют одновременно самый неэффективный HTTP-демон и самый неэффективный скриптовый движок.
А никто и не спорит, но тестировали не только его. )
Re[146]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Я не сравнию, я спрашиваю у тебя, как это можно сделать на твоих мега-технологиях. Ты ничего внятно сказать не можешь, ощущение, что архив у тебя сам по себе прочитается и распакуется за время ноль, вместе с отдачей клиенту.
_>ОК, тогда опиши подробно какую задачку надо решить и я скажу о вариантах на vibe.d.
Да вроде все понятно — есть N книг в формате навроде epub на сервере. Нужен веб-интерфейс для чтения. Заодно покажи куда ты приспособишь генерацию темплейтов по темплейтам.
_>Вот как раз в области высоконагруженных он существенно устипил nginx'у. Ещё год назад об это статья была подробная.
Пудозреваю дело было не в нагрузке а в стоимости решения. Есть ссылка ?
Re[150]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Алё — задача показать общие для всех страниц элементы — футеры, меню и прочие вещи. Это делается легко и просто. Директивы ангуляра творят чудеса.
_>Ну покажи пример. )
<megafooter />
В коде директивы megafooter пишешь джаваскриптовый код, который делает все что тебе нужно — т.е. выставляет нужную тебе разметку.
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В твоем случае такого нет и быть не может, потому, что твоя статика на самом деле динамика. Из этого следуеют что тот же CDN в твоём случае невозможен.
_>Почему не возможен то? ) Кэширование зависит от возвращаемых заголовков, а мы ими полностью управляем. )
Ты вероятно, не понял — CDN означает, что реквесты на статику вообще никогда, ни разу не придукт к твоему серверу. Так понятно ?
I>>Я хочу что бы статика кешировалась вне моего сервера. То есть — вообще. Желательно поближе к клиенту и если можно то и вообще прямо на нём. Это очевидно — ангуляр конкретной версии никогда не экспайрится, в отличие от твоих темплейтов. А это значит, что его в 100% случае можно отдавать вообще как угодно, через тот же CDN который гарантировано быстрее любого процессинга на vide.d
_>Ну на клиенте, так на клиенте — всё в твоих руках.
У тебя какая то военная технология — отдавать статику с CDN при этом генерить её будет твой сервер по каждому запросу. В реальном мире или одно или другое.
I>>Я скипнул — ответь прямо на заданый вопрос. Повторяю — надо ли учитывать длину и качество пути от клиента на сервер и обратно ?
_>В нашей дискуссии не надо, т.к. работа с данными после выдачи с сервера не зависит от применяемого на сервере решения.
Вообще говоря надо. Если сеть плохая или несимметричная, то даже первый реквест может затупить. А в случае с CDN путь будет короче и как правило надежнее. Чего собственно и наблюдаем.
_>Да, ну так и что у нас с обработкой поисковыми машинами чисто ajax'ых страниц? )
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Не будет "всё нормально". Хоть в виндовсе, хоть в линуксе, крайне сложно заставить систему отказаться от свопа. О чем, собственно, и сообщают тулы.
_>А зачем отключать своп на сервере? )
Затем, что работа со свопом стоит очень дорого — 1-15мс на кластер данных. Есть только один способ избавиться от этой задержки — держать вообще всё в памяти. Для среднего веб-приложения это 4-8гб памяти, включая все необходимые функции OS.
Нет разницы между чтением из файла и подкачкой из свопа. То есть — вообще.
I>>У тебя вероятно RAM исчисляется терабайтами. Это объясняет, почему тебе не понятно, что такое своп.
_>И зачем мне терабайты для загрузки программы размером в несколько мегабайт? )
Во первых, твоя программа в рантайме занимает много больше. Во вторых, у ней есть куча депенденсов. В третьих, управление ей отдаёт операционая система которая сама делает кучу вещей. Все вместе это 4-8гб для среднего веб-приложения.
Что бы исключить обращения к диску, всю эту кухню надо держать в RAM, а не в свопе.
I>>Для твоего сайта должно быть выделено достаточно большое количество страниц физической памяти. Вероятность такого исхода стремится к нулю — именно из за vps.
I>>Более того — совершенно не важно, кто будет источником нагрузки, твое приложение или приложение на другом vps на том же железе.
_>Очаровательно) Ты мне тут излагаешь свои теории, а я тебе рассказываю практику. Что всё отлично работает.
Работает, но не так как ты думаешь. У всех виртуальных серверов большие проблемы с временем отклика.
>Причём на таком же железе классическая конфигурация (LAMP) просто дохнет от малейшей нагрузки. Нормальная конфигурация (nginx + python и т.п.) в принципе работает, но при увеличение числа клиентов быстро начинает подтормаживать. А вот обсуждаемая штука спокойно летает даже на этой дохлой железке.
Это чушь. Ты путаешь железо физическое и виртуальное. vps не ставится на дохлое железо. А вот виртуальное железо на таком сервере может быть очень даже дохлым и дешовым.
Скорость работы получается адекватная не потому, что клауд, а потому, что физический хост обеспечивает адскую производительность.
vps нужен всего лишь для того, что бы железо не простаивало и можно было приложения изолировать друг от друга. Делается это за счет распыления ресурсов.
Если поставить lamp на такой же сервер, как хостовый физический, то перформансу будет в разы больше, чем на vps любой конфигурации на этом же физическом хосте.
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Более того — совершенно не важно, кто будет источником нагрузки, твое приложение или приложение на другом vps на том же железе.
_>Очаровательно) Ты мне тут излагаешь свои теории, а я тебе рассказываю практику. Что всё отлично работает. Причём на таком же железе классическая конфигурация (LAMP) просто дохнет от малейшей нагрузки. Нормальная конфигурация (nginx + python и т.п.) в принципе работает, но при увеличение числа клиентов быстро начинает подтормаживать. А вот обсуждаемая штука спокойно летает даже на этой дохлой железке.
Мне сразу вспомнился спор с выпускником гуманитарного техникума. Он утверждал, что Pentium 100 работает под виртуалкой быстрее, чем его PII, раза в три. При этом он забыл уточнить, что виртуалка, где был Pentium 100 работала на PIV.
Похоже, тебя всерьез заинтересовали идеи таких гуманитарщиков.
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>Очаровательно) Ты мне тут излагаешь свои теории, а я тебе рассказываю практику. Что всё отлично работает. Причём на таком же железе классическая конфигурация (LAMP) просто дохнет от малейшей нагрузки. S>Классическая конфигурация — это гарантированный тормоз, т.к. в ней участвуют одновременно самый неэффективный HTTP-демон и самый неэффективный скриптовый движок.
Не, он про другое — он про магию клауда. Типа — если сайт тормозит на домашнем железе, то купив такое же железо, но VPS, сайт резко начнет летать. Товарищ почему то не в курсе, что хостовое железо на порядок быстрее любого из VPS что на нём крутятся.
Re[146]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не, он про другое — он про магию клауда. Типа — если сайт тормозит на домашнем железе, то купив такое же железо, но VPS, сайт резко начнет летать. Товарищ почему то не в курсе, что хостовое железо на порядок быстрее любого из VPS что на нём крутятся.
Это понятно, как и наивная вера в то, что RAM ему отдаётся с коммитом 1:1 к физическому. Муа-хаа-хаа.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[148]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>http://www.hetzner.de/en/hosting/produkte_vserver/vq7 такого типа. )
Диск маловат, и для инсталляции потребуется больше RAM. За такие деньги можно взять Win2012R2 VPS c 50GB диска и 2GB рамы.
А вообще — взлетит. Как раз вписывается в минимальные требования к веб-серверу на винде.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[139]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Да вроде все понятно — есть N книг в формате навроде epub на сервере. Нужен веб-интерфейс для чтения. Заодно покажи куда ты приспособишь генерацию темплейтов по темплейтам.
Эммм, я так понял что сайт полностью статический? А зачем тут вообще vibe.d (или какой-либо ещё серверный фреймворк) тогда? )))
I>Пудозреваю дело было не в нагрузке а в стоимости решения. Есть ссылка ?
Я кидал её сюда когда-то, но сейчас вряд ли найду. Там смысл был в том, что была отдельно представлена статистика для высоконагруженных серверов и суммарная. Так вот по первому было распределение Nginx->IIS->Apache, причём на момент статьи это было уже как бы давно и привычная норма. А новое заключалось в том, что Nginx вышел на 2-ое место и по суммарной статистике (первый там естественно Apache).
Re[151]: Есть ли вещи, которые вы прницпиально не понимаете...
I>В коде директивы megafooter пишешь джаваскриптовый код, который делает все что тебе нужно — т.е. выставляет нужную тебе разметку.
Не, в таком виде не пойдёт, т.к. footer'e должен задаваться в виде html шаблона, а не в виде js кода. Но нечто похожее всё же можно сделать с помощью angular'a, воспользовавшись его директивой ngInclude (и опять же не придётся делать каких-то спец. директив и js кодов под конкретный сайт). Только вот include — это всего лишь одна из множества фич jade'а, причём наверное самая простейшая. Для многих других реализации в angular не найти.
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ты вероятно, не понял — CDN означает, что реквесты на статику вообще никогда, ни разу не придукт к твоему серверу. Так понятно ?
Что-то ты бредишь. ))) Вот покажи мне в чём будет отличие для CDN в отдаче сервером статического файла или же отдаче шаблонизатором страницы с соответствующим образом установленными заголовками (время, кэш и т.п.)
I>У тебя какая то военная технология — отдавать статику с CDN при этом генерить её будет твой сервер по каждому запросу. В реальном мире или одно или другое.
Если мы используем CDN, то просто сервер отработает скорее всего только один раз (в идеале). )))
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Во первых, твоя программа в рантайме занимает много больше. Во вторых, у ней есть куча депенденсов. В третьих, управление ей отдаёт операционая система которая сама делает кучу вещей. Все вместе это 4-8гб для среднего веб-приложения.
Что за фееричная чушь? ) Наш демон отжирает порядка 10Мб на старте и потом по несколько Кб на каждого одновременного клиента.
Ну и плюс ещё БД в памяти сидит, но тут уже потребление зависит от объёма данных и это уже другой вопрос.
I>Это чушь. Ты путаешь железо физическое и виртуальное. vps не ставится на дохлое железо. А вот виртуальное железо на таком сервере может быть очень даже дохлым и дешовым. I>Скорость работы получается адекватная не потому, что клауд, а потому, что физический хост обеспечивает адскую производительность.
I>vps нужен всего лишь для того, что бы железо не простаивало и можно было приложения изолировать друг от друга. Делается это за счет распыления ресурсов.
I>Если поставить lamp на такой же сервер, как хостовый физический, то перформансу будет в разы больше, чем на vps любой конфигурации на этом же физическом хосте.
Ну и к чему ты тут излагаешь эту банальщину? ) И откуда ты вообще взял разное железо? ) Я вроде как очень чётко написал, что сравнивался разный софт на одном и том же железе.
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Мне сразу вспомнился спор с выпускником гуманитарного техникума. Он утверждал, что Pentium 100 работает под виртуалкой быстрее, чем его PII, раза в три. При этом он забыл уточнить, что виртуалка, где был Pentium 100 работала на PIV.
I>Похоже, тебя всерьез заинтересовали идеи таких гуманитарщиков.
Я думаю ты сможешь очень успешно продолжить этот спор с голосами в твоей голове и дальше. Только не надо при этом использовать мой ник.
Re[149]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>http://www.hetzner.de/en/hosting/produkte_vserver/vq7 такого типа. ) S>Диск маловат, и для инсталляции потребуется больше RAM. За такие деньги можно взять Win2012R2 VPS c 50GB диска и 2GB рамы.
Ну по моей ссылке только лицензия на винду стоит 25 евро/месяц. Так что будет интересно взглянуть на vps с виндой за 8 евро. )
S>А вообще — взлетит. Как раз вписывается в минимальные требования к веб-серверу на винде.
У hetzner винду ставят начиная с этого http://www.hetzner.de/en/hosting/produkte_vserver/vq12 плана. ) Только вот нафига она вообще нужна то? ) Т.е. даже если бы и была возможность поставить винду за те же деньги, то всё равно остаётся вопрос: а зачем? Это же не десктоп, а сервер — тут я больше знаю про недостатки винды, чем про достоинства.
P.S. Естественно сервер по ссылке наверху — это не боевой, а тестовый. И как раз на таком слабом очень удобно тестировать эффективность разных решений, т.к. боевой гораздо сложнее загрузить. Хотя при нынешнем раскладе теперь ещё не факт какой у нас будет боевой — может и какого-то vps хватит в итоге. )))
P.P.S. Данный тестовый проект — это высоконагруженный сервис со страницами из чистой динамики, причём приватной (доступной после логина пользователя).
Re[146]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Во первых, твоя программа в рантайме занимает много больше. Во вторых, у ней есть куча депенденсов. В третьих, управление ей отдаёт операционая система которая сама делает кучу вещей. Все вместе это 4-8гб для среднего веб-приложения.
_>Что за фееричная чушь? ) Наш демон отжирает порядка 10Мб на старте и потом по несколько Кб на каждого одновременного клиента.
Ну то есть ты утверждаешь, что твоему демону не нужны никакие функции операционной системы и особенно её ядра ? Ну и дела.
_>Ну и плюс ещё БД в памяти сидит, но тут уже потребление зависит от объёма данных и это уже другой вопрос.
А только что ты сказал что у тебя жалких 10мб. Один IPC между БД и твоим демоном стоит вагона ресурсов. Только ты об этом не знаешь, потому что это берёт на себя операционная система и в твоем процессе этих издержек нет.
I>>Если поставить lamp на такой же сервер, как хостовый физический, то перформансу будет в разы больше, чем на vps любой конфигурации на этом же физическом хосте.
_>Ну и к чему ты тут излагаешь эту банальщину? ) И откуда ты вообще взял разное железо? ) Я вроде как очень чётко написал, что сравнивался разный софт на одном и том же железе.
От верблюда. vps железо это считай просто название, кроме некоторых параметров, навроде объема трафика, дискового пространства и тд.
Если тебе придет в голову запустить на том же физическом сервере виртуалку с Pentium 100, он, внезапно, шикарно потянет lamp. Не потому, что P100, а потому что хостовое железо адское.
Re[146]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты вероятно, не понял — CDN означает, что реквесты на статику вообще никогда, ни разу не придукт к твоему серверу. Так понятно ?
_>Что-то ты бредишь. ))) Вот покажи мне в чём будет отличие для CDN в отдаче сервером статического файла или же отдаче шаблонизатором страницы с соответствующим образом установленными заголовками (время, кэш и т.п.)
CDN это внешняя сеть по отношению к веб-приложению. Маршрутизатор направляет запрос к самому оптимальному ноду этой сети. Ноды сконфигурированы именно под статику, т.е. кеширование и прочие чудеса на высоте. Статика приходит на клиент за смешное время. Сравнивая с твоим случаем это означает следующее. Предположим клиент делает два запроса — к CDN и к твоему серверу в одно и то же время. Пока запрос к твоему серверу еще в пути, CDN уже отдаёт статику по другому запросу.
_>Если мы используем CDN, то просто сервер отработает скорее всего только один раз (в идеале). )))
Неверно. Если мы используем CDN, то сервер в это время просто отдыхает, ему незачем отдавать статику, ни разу. Если точнее — ровно 0 (ноль) раз. Все это сделает CDN, который ближе и шустрее к юзеру, а часто он и вовсе в сети крупного провайдера.
Re[152]: Есть ли вещи, которые вы прницпиально не понимаете...
I>>В коде директивы megafooter пишешь джаваскриптовый код, который делает все что тебе нужно — т.е. выставляет нужную тебе разметку.
_>Не, в таком виде не пойдёт, т.к. footer'e должен задаваться в виде html шаблона, а не в виде js кода.
Ты наверное плохо понимаешь, что такое директивы ангуляра. Унутре js, на выходе — html.
>Но нечто похожее всё же можно сделать с помощью angular'a, воспользовавшись его директивой.
Все что нужно — написать одну директиву, если нет готовых. Директив для ангуляра написано больше, чем ты можешь представить.
Re[140]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Да вроде все понятно — есть N книг в формате навроде epub на сервере. Нужен веб-интерфейс для чтения. Заодно покажи куда ты приспособишь генерацию темплейтов по темплейтам.
_>Эммм, я так понял что сайт полностью статический? А зачем тут вообще vibe.d (или какой-либо ещё серверный фреймворк) тогда? )))
Неправильно понял, но статики много. Ты ведь говорил что vibe.d умеет шикарно отдавать статику.
Скажем, для книг надо генерить watermark, разным юзерам рендерить разное, разным устройствам отдавать снова разное.
_>Я кидал её сюда когда-то, но сейчас вряд ли найду. Там смысл был в том, что была отдельно представлена статистика для высоконагруженных серверов и суммарная. Так вот по первому было распределение Nginx->IIS->Apache, причём на момент статьи это было уже как бы давно и привычная норма. А новое заключалось в том, что Nginx вышел на 2-ое место и по суммарной статистике (первый там естественно Apache).
Пудозреваю, методика была примерно такая — "смотрите, лады-жыгули самое массовое ведро, следовательно, это самый лучший автос. Быстрый автос — хороший автос, следовательно, лады-жыгули самые быстрые"
Re[147]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Ну то есть ты утверждаешь, что твоему демону не нужны никакие функции операционной системы и особенно её ядра ? Ну и дела.
Т.е. это у тебя ядро линуха занимает 8 гигов оперативки? )
I>А только что ты сказал что у тебя жалких 10мб. Один IPC между БД и твоим демоном стоит вагона ресурсов. Только ты об этом не знаешь, потому что это берёт на себя операционная система и в твоем процессе этих издержек нет.
Почитай что-нибудь о сокетах юникса что ли... )
I> От верблюда. vps железо это считай просто название, кроме некоторых параметров, навроде объема трафика, дискового пространства и тд. I> Если тебе придет в голову запустить на том же физическом сервере виртуалку с Pentium 100, он, внезапно, шикарно потянет lamp. Не потому, что P100, а потому что хостовое железо адское.
Какая разница какое железо, если оно одинаковое? ) Я тебе говорю, что на одном и том же железе LAMP сдыхает уже от небольшой нагрузки, nginx+python начинают подтормаживать на средней, а vibe.d продолжает летать. Ну а IIS (и а точнее винду) вообще на такие планы не ставят. Так какое отношения эти твои рассуждения о теории виртуализации имели к данным тестам? )
Re[147]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>CDN это внешняя сеть по отношению к веб-приложению. Маршрутизатор направляет запрос к самому оптимальному ноду этой сети. Ноды сконфигурированы именно под статику, т.е. кеширование и прочие чудеса на высоте. Статика приходит на клиент за смешное время. Сравнивая с твоим случаем это означает следующее. Предположим клиент делает два запроса — к CDN и к твоему серверу в одно и то же время. Пока запрос к твоему серверу еще в пути, CDN уже отдаёт статику по другому запросу.
Ты похоже не понял, что я тебе спрашиваю. ))) Покажи мне что мешает применить CDN вместе с vibe.d.
I>Неверно. Если мы используем CDN, то сервер в это время просто отдыхает, ему незачем отдавать статику, ни разу. Если точнее — ровно 0 (ноль) раз. Все это сделает CDN, который ближе и шустрее к юзеру, а часто он и вовсе в сети крупного провайдера.
Хы, очаровательно. ) А теперь расскажи, как контент попадает в CDN. )
Re[141]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Неправильно понял, но статики много. Ты ведь говорил что vibe.d умеет шикарно отдавать статику. I>Скажем, для книг надо генерить watermark, разным юзерам рендерить разное, разным устройствам отдавать снова разное.
А, ну отлично. Тут я думаю лучше всего сделать стандартное решение на серверном шаблоне (он кстати один будет на все книги). Он будет доставать нужную книгу из архива и вставлять в соответствующе место на странице, выдавая уже готовый html. Ну и надо правильно настроить там параметры http кэширования (что бы снаружи оно казалось статикой) и сжатия. По идее будет не плохое решение и за одно поисковым машинам понравится. )
_>>Я кидал её сюда когда-то, но сейчас вряд ли найду. Там смысл был в том, что была отдельно представлена статистика для высоконагруженных серверов и суммарная. Так вот по первому было распределение Nginx->IIS->Apache, причём на момент статьи это было уже как бы давно и привычная норма. А новое заключалось в том, что Nginx вышел на 2-ое место и по суммарной статистике (первый там естественно Apache).
I>Пудозреваю, методика была примерно такая — "смотрите, лады-жыгули самое массовое ведро, следовательно, это самый лучший автос. Быстрый автос — хороший автос, следовательно, лады-жыгули самые быстрые"
По твоей логике на первом месте Apache был бы, а у них это, как видишь, не так. )
Re[142]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Скажем, для книг надо генерить watermark, разным юзерам рендерить разное, разным устройствам отдавать снова разное.
_>А, ну отлично. Тут я думаю лучше всего сделать стандартное решение на серверном шаблоне (он кстати один будет на все книги). Он будет доставать нужную книгу из архива и вставлять в соответствующе место на странице, выдавая уже готовый html.
Не ясно, чем тебе помогает серверный шаблон, который один на все книги. Поясни
1 что надо сделать для обработки ровно одного сценария юзера
2 какие потребуются запросы
3 что будет отдавать сервер на каждый запрос, желательно с указанием размеров респонса
Сценарий такой — юзер жмякает кнопку "продолжить" и ему надо показать ту страницу, где он остановился в прошлый раз
Как закончишь, я покажу, чего надо сделать если взять клиентский шаблон JS навроде ангуляра.
I>>Пудозреваю, методика была примерно такая — "смотрите, лады-жыгули самое массовое ведро, следовательно, это самый лучший автос. Быстрый автос — хороший автос, следовательно, лады-жыгули самые быстрые"
_>По твоей логике на первом месте Apache был бы, а у них это, как видишь, не так. )
У эппла ничего такого нет, так что все в порядке.
Re[148]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>CDN это внешняя сеть по отношению к веб-приложению. Маршрутизатор направляет запрос к самому оптимальному ноду этой сети. Ноды сконфигурированы именно под статику, т.е. кеширование и прочие чудеса на высоте. Статика приходит на клиент за смешное время. Сравнивая с твоим случаем это означает следующее. Предположим клиент делает два запроса — к CDN и к твоему серверу в одно и то же время. Пока запрос к твоему серверу еще в пути, CDN уже отдаёт статику по другому запросу.
_>Ты похоже не понял, что я тебе спрашиваю. ))) Покажи мне что мешает применить CDN вместе с vibe.d.
Мешает твоё желание отдавать статику своим же сервером при помощи динамики. Ты хорошо понимаешь, что с CDN означаеть 0 (ноль) запросов к твоему серверу ?
Объясни, где польза от vibe.d если запросы вообще не придут на твой сервер ?
I>>Неверно. Если мы используем CDN, то сервер в это время просто отдыхает, ему незачем отдавать статику, ни разу. Если точнее — ровно 0 (ноль) раз. Все это сделает CDN, который ближе и шустрее к юзеру, а часто он и вовсе в сети крупного провайдера.
_>Хы, очаровательно. ) А теперь расскажи, как контент попадает в CDN. )
Например так — юзеры удаленно закидывают в CDN css, картинки, скрипты и тд, после чего эта статика распространяется по всем нодам сети.
Re[143]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не ясно, чем тебе помогает серверный шаблон, который один на все книги. Поясни I>1 что надо сделать для обработки ровно одного сценария юзера I>2 какие потребуются запросы I>3 что будет отдавать сервер на каждый запрос, желательно с указанием размеров респонса
I>Сценарий такой — юзер жмякает кнопку "продолжить" и ему надо показать ту страницу, где он остановился в прошлый раз
Для подробной проработки всё ещё недостаточно деталей. Как минимум нам надо знать:
1. Являются ли книги публичными (тогда мы естественно заходим, чтобы их индексировали поисковые машины) или же они должны быть видны только определённым зарегистрированным пользователям.
2. Мы хотим экономить клиентский трафик (актуально для мобильных устройств с моделью регистрации и покупки) или же наоборот нам важно почаще обновлять всю страницу (с кучей навешенной рекламы) при чтение пользователя.
I>Как закончишь, я покажу, чего надо сделать если взять клиентский шаблон JS навроде ангуляра.
Было бы интересно глянуть)
Re[149]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Объясни, где польза от vibe.d если запросы вообще не придут на твой сервер ?
Я тебе уже несколько раз говорил, что если у нас в системе вообще только статика, то смысла брать фреймворк для динамики довольно странно. ) Хотя он и будет работать не медленнее, но смысла всё равно нет. Тем более, что администрирование обычного сервера и программирование своего — это вообще задачи из разных миров. )))
I>Например так — юзеры удаленно закидывают в CDN css, картинки, скрипты и тд, после чего эта статика распространяется по всем нодам сети.
Хыхы, ну в начале получше познакомься с темой, а потом уже рассказывай. )
Кстати, ты в курсе, что через CDN раздают в том числе и видео в прямом эфире? )
Re[150]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Например так — юзеры удаленно закидывают в CDN css, картинки, скрипты и тд, после чего эта статика распространяется по всем нодам сети.
_>Хыхы, ну в начале получше познакомься с темой, а потом уже рассказывай. )
_>Кстати, ты в курсе, что через CDN раздают в том числе и видео в прямом эфире? )
В твоем случае никакого видео нет. Все что нужно для скриптов и темплейтов — один раз запихнуть их в CDN. Для этого совершенно нет необходимости отдавать их через серевер. Это, например, можно делать прямо во время релизного билда приложения.
Re[144]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Сценарий такой — юзер жмякает кнопку "продолжить" и ему надо показать ту страницу, где он остановился в прошлый раз
_>Для подробной проработки всё ещё недостаточно деталей. Как минимум нам надо знать: _>1. Являются ли книги публичными (тогда мы естественно заходим, чтобы их индексировали поисковые машины) или же они должны быть видны только определённым зарегистрированным пользователям.
Только зарегистрированым.
_>2. Мы хотим экономить клиентский трафик (актуально для мобильных устройств с моделью регистрации и покупки) или же наоборот нам важно почаще обновлять всю страницу (с кучей навешенной рекламы) при чтение пользователя.
Да вроде как уже сказал — экономить клиентский трафик. Рекламу показывать, как положено. "почаще обновлять страницу" — это не совсем понятно, что за кейс. Кучу рекламы показывать уже стало проблемой ?
I>>Как закончишь, я покажу, чего надо сделать если взять клиентский шаблон JS навроде ангуляра.
_>Было бы интересно глянуть)
Ты для начала покажи решение на своих серверных темплейтах.
Re[118]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>А причём тут знание языка? Я их много разных знаю и значительную часть явно можно назвать маргинальными. Однако я не использую их в каких-то серьёзных проектах. Как впрочем и D пока что. Хотя надеюсь, что когда-нибудь он всё же встанет на одну ступень с C/C++.
Если ты внимаетльно посмотришь, то окажется, что хаскель рвёт в хлам твой хвалёный vibe.d
Более того, erlang, до безобразия "манеджед" рвет вообще всех, кроме nginx, который, в свою очередь, даже не на С++ написан.
D выступил очень удачно — еле-еле обогнал Node.js
Пудозреваю, на таком бенчмарке можно заканчивать весь этот тред
Re[151]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В твоем случае никакого видео нет. Все что нужно для скриптов и темплейтов — один раз запихнуть их в CDN. Для этого совершенно нет необходимости отдавать их через серевер. Это, например, можно делать прямо во время релизного билда приложения.
О, я смотрю до тебя дошло...
Да, действительно совершенно не обязательно отдавать через сервер. Но главное что ты понимаешь, что CDN можно точно так же эффективно работать и вместе с vibe.d (и любым другим подобным фреймворком).
Re[152]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Да, действительно совершенно не обязательно отдавать через сервер. Но главное что ты понимаешь, что CDN можно точно так же эффективно работать и вместе с vibe.d (и любым другим подобным фреймворком).
Да, для этого нужно отказаться от идеи отдавать статику динамически, как ты предлагал
Re[120]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Группировка "внутри одного прямоугольника" определяется архитектурными соображениями. Соответствует ли ей связь а-ля симула-ООП — деталь реализации языка, к архитектуре и UML никакого значения не имеющая. _>Т.е. всё снова сводится к тому, что вы предлагаете рисовать виртуальное ООП для Хаскеля. Мы же это уже обсуждали — мне уже как-то надоело ходить по кругу...
Так вы не ходите по кругу, а объясните:
1) Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой.
2) Какие проблемы с использованием UML возникают от того, что она другая.
_>Так это же какая-то недоработка конкретной функции, а не принципиальная проблема архитектуры. Зачем использовать подобные демагогические аргументы во вроде как не базарной дискуссии?
Проблема в том, что для всех юзкейсов удобную функцию не сделаешь, потому и стараются сделать так, чтоб комбинация функций работала так же хорошо, как специально написанная. И если эту главную задачу библиотека не решает — то это уже принципиальная проблема ее архитектуры.
_>С map'ми всё отлично работает, как вы уже видели. А то, что вам посчастливилось наткнуться на какую-то недоработка стандартной библиотеки D при первом же знакомстве с языком, — это конечно нестандартное "везение". )))
Я же говорил, недоработка библиотеки сама по себе возможна и даже вероятна. Но такая проблема должна как-то обходится. Использованием другой библиотеки или каким-то изменением конвейера, или даже дописыванием своей функции, пригодной для оптимизации. Но если от него приходится отказываться в принципе, другого воркараунда нет — это уже говорит о проблеме.
_>Фокус в том, что там нет каких-то преобразований, а есть стандартный подход, прописанный в документации. Кстати, тот же IEnumerable в C# хотя и заметно послабее, но тоже ведь из этой области...
Если "нет каких-то преобразований", то возможности оптимизации сильно ограничены. А IEnumerable работает медленно, потому что никаких преобразований-оптимизаций там нет.
Такой вот код (Seq.cache кеширует последовательность в изменяемом массиве)
let rec primes = Seq.cache << Seq.append [2;3] << Seq.filter isPrime <| { 5 .. 2 .. 1000000000 }
and isPrime x = Seq.forall ((<>)0) << Seq.map (fun y -> x % y) << Seq.takeWhile (fun y -> y*y <= x) <| primes
let test1 = Seq.length << Seq.takeWhile (fun y -> y <= pown 2 24) <| primes
полторы минуты работает.
Проблемы же, если использовать "функции", которые чистыми не являются все равно будут.
_>Ну вот здесь у нас с вами и находится принципиальное различие во взглядах. )
Мои взгляды легко изменятся, если мне кто-нибудь продемонстрирует действительно интересные возможности, за которые не нужно платить (даже в случае их неиспользования).
_>Да да. ) Только вот переход вверх возможен (написанием своего кода, подключением готового из библиотеки), а переход вниз обычно нет... )
Переход вверх для низкоуровневого языка вроде C++ возможет только интеропом с высокоуровневым языком вроде хаскеля. Точно так же и наоборот — переход на низкий уровень для высокоуровневого языка возможен интеропом с низкоуровневым или генерацией кода на низкоуровневом языке из встроенного ДСЛ.
_>По разному бывает. Частенько требуется не просто использовать какую-то возможность языка, а подключить мощную библиотеку, которая в итоге существенно меняет язык. )
Что такое "существенно поменять язык" в данном случае? Систему типов библиотекой можно поменять? А систему модулей? И как это все будет взаимодействовать с уже написанным кодом на не "измененном существенно" языке. Поддержку нормального сборщика в библиотекке не добавить. Нормальную поддержку ленивости тоже.
_>Да, циклов много, но большая часть из них написана на спец. языке, компилируемом в simd инструкции.
Ну так и комбинации комбинаторов можно в simd инструкции компилировать.
_>Ааа вы всё про это... Ну это же меньше процента погрешность.
Если в этой ветке давали измерения с точностью до сотых, я и обрабатывал их соответствующим образом. Может толку от этого особого и нет, но уж точно нельзя сказать, что это "неправильно".
_>А ведь у вас перед усреднением разброс был существенно больше, не так ли? )
Нет, он не был существенно больше, потому что выбросы я не учитывал.
_>Не знаю что вам непонятно. ) Знать язык и использовать его — это абсолютно разные вещи. Знаю я много языков, использую в реальных проектах очень мало.
Допустим, что разные, хотя я бы не стал переоценивать степень "знания" языка, которым не пользовался. Тут непонятно, почему вы упоминаете "играющихся с маргинальными языками" явно в негативном ключе, хотя сами же таким играющимся и являетесь.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[122]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Просто я существенно разделяю, закладываемое в языке, и добавляемое в библиотеках. Для меня хорош такой язык, который позволяет сделать практически всё что угодно с помощью дополнительных библиотек или своего кода. При этом стандартная поставка не так принципиальна.
Обычно оказывается, что язык, "который позволяет сделать практически всё что угодно с помощью дополнительных библиотек", не позволяет сделать ничего из того, что я полагаю нужным, если этого в языке с самого начала нет. Возможность добавлять что-то в язык с помощью библиотек — возможность очень важная и даже один из основных показателей качества языка. Однако если база у языка неудачная, сделать с этим уже ничего нельзя.
_>В этом смысле D занимает странное положение. По расширяемости он существенно превосходит и C++, но при этом в силу пока небольшого сообщества, библиотек на все случаи жизни пока нет. В то время как в C++ есть совершенно невероятные библиотеки на все случая жизни, которые выжимают из языка уже даже больше, чем он может дать.
При этом в C++ нет нормальной реализации практически ни для одной фичи, изобретенной после 68-го года, да и изобретенные до 68-го не все есть.
_>Я думаю что очень многие программисты мечтали бы иметь такую репутацию, как авторы D. )
Да, я и сам всегда мечтал стать известным писателем (пускай и известным в узких кругах, как Андрей Александреску).
K>>При таком подходе разницы между мутабельными и иммутабельными структурами действительно нет, поздравляю. _>О, наконец то вы это осознали. )
Да нет, основной принцип апологетики такого рода я уловил довольно давно.
1) Считаем, что Y отсутствующее в языке X это то же самое, что и Y' в языке присутствующее.
1 б) Если в языке вообще ничего достойного упоминания нет, считаем, что отсутствие — это то же, что и наличие в общем случае.
2) На всякий случай одновременно обосновываем, что Y не нужно. Обосновываем, разумеется, отсутствием Y в X.
3) Теперь в нашем чудо языке X есть все, что бы мы не пожелали, и одновременно все (кроме, быть может, прилежания и усидчивости) — не нужно.
...
5) ПРОФИТ!
_>Кстати говоря в D immutable имеет важный смысл при работе с многопоточностью в D.
Да, как и pure.
_>Если признать вашу логику, то тогда любые данные в любых языках выделенные не с помощью прямого вызова VirtualAlloc не могут быть иммутабельными. )
Нет, из моей логики это не следует.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[145]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Только зарегистрированым.
Если это модель с продажами, то тогда надо ставить защиту и соответственно это будет уже не тривиальная система, в которой должен быть и специфический js код на клиенте и серверная поддержка этого. Последнее вполне реализуемо на vibe.d, но в одиночку он естественно не правится.
I>Да вроде как уже сказал — экономить клиентский трафик. Рекламу показывать, как положено. "почаще обновлять страницу" — это не совсем понятно, что за кейс. Кучу рекламы показывать уже стало проблемой ?
Так рекламу чаще всего показывают просто через переход на след. страницу. Во всяком случае на тех сайтах с книгами, что я видел (давно уже не пользуюсь).
Re[119]: Есть ли вещи, которые вы прницпиально не понимаете...
О, интересная ссылочка. Хотя и несколько устаревшая и от фаната эрланга (соответственно очень прогнозируемое первое место), но в остальном весьма любопытно, т.к. собраны действительно интересные и быстродействующие языки. Хотя без Java (как самого популярного) и C/C++ (как предел по быстродействию) этот тест выглядит всё же скучновато. Единственный сильно выделяющийся там из общей массы, это JS. И при этом он выступил очень достойно, даже обойдя нескольких конкурентов из старшей лиги.
I>Если ты внимаетльно посмотришь, то окажется, что хаскель рвёт в хлам твой хвалёный vibe.d I>Более того, erlang, до безобразия "манеджед" рвет вообще всех, кроме nginx, который, в свою очередь, даже не на С++ написан. I>D выступил очень удачно — еле-еле обогнал Node.js
Хы, ты похоже даже не прочитал текст по своей же ссылке. )))
Да, а вообще если интересоваться подобными тестами, то надо смотреть не подобные статьи в жж, а на что-то типа такого http://www.techempower.com/benchmarks/. Правда vibe.d там ещё нет. )
Re[153]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Так вы не ходите по кругу, а объясните: K>1) Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой.
А какую другую может предложить Хаскель? ) Причём чтобы на основе неё можно было строить иерархии (это не обязательно про наследование — агрегирование тоже подходит), задавая тем самым архитектуру приложения на всех уровнях.
K>2) Какие проблемы с использованием UML возникают от того, что она другая.
Только в том, что в данный момент UML заточен под неё (в части своих диаграмм). Теоретически проблема решаемая, но похоже спецов по Хаскелю это не особо интересует. ))) Да, и кстати мы это тоже уже обсуждали... Подобные пережёвывания по нескольку раз утомляют уже.
K>Проблема в том, что для всех юзкейсов удобную функцию не сделаешь, потому и стараются сделать так, чтоб комбинация функций работала так же хорошо, как специально написанная. И если эту главную задачу библиотека не решает — то это уже принципиальная проблема ее архитектуры.
Так диапазоны D как раз и предполагают комбинации — даже здесь это было видно. И оно собственно работало, только почему-то плохо сработала оптимизация.
K>Я же говорил, недоработка библиотеки сама по себе возможна и даже вероятна. Но такая проблема должна как-то обходится. Использованием другой библиотеки или каким-то изменением конвейера, или даже дописыванием своей функции, пригодной для оптимизации. Но если от него приходится отказываться в принципе, другого воркараунда нет — это уже говорит о проблеме.
В том конкретном случае можно было без проблем написать свою версию (а на самом деле наверное глянуть на исходники оригинальной и что-то там подправить) функций any или until (не знаю какая из них тормозила). Только вот в любом случае проще и быстрее было поменять сам алгоритм. ))) Тем более, что речь шла о форумном споре.
K>Если "нет каких-то преобразований", то возможности оптимизации сильно ограничены. А IEnumerable работает медленно, потому что никаких преобразований-оптимизаций там нет. K>Такой вот код (Seq.cache кеширует последовательность в изменяемом массиве) K>
K>let rec primes = Seq.cache << Seq.append [2;3] << Seq.filter isPrime <| { 5 .. 2 .. 1000000000 }
K>and isPrime x = Seq.forall ((<>)0) << Seq.map (fun y -> x % y) << Seq.takeWhile (fun y -> y*y <= x) <| primes
K>let test1 = Seq.length << Seq.takeWhile (fun y -> y <= pown 2 24) <| primes
K>
K>полторы минуты работает.
А если на C#? )
K>Проблемы же, если использовать "функции", которые чистыми не являются все равно будут.
Проблемы могут быть только у неумеющих читать документацию. )
K>Мои взгляды легко изменятся, если мне кто-нибудь продемонстрирует действительно интересные возможности, за которые не нужно платить (даже в случае их неиспользования).
Это слишком неопределённо звучит) Начнём с того, что вы можете посчитать интересными возможностями. А то вот скажем мне кажется интересным распараллеливание цикла с помощью simd и на ядра процессора (в идеале и то и другое вместе). А вас такое быть может вообще не впечатляет... )
K>Переход вверх для низкоуровневого языка вроде C++ возможет только интеропом с высокоуровневым языком вроде хаскеля. Точно так же и наоборот — переход на низкий уровень для высокоуровневого языка возможен интеропом с низкоуровневым или генерацией кода на низкоуровневом языке из встроенного ДСЛ.
Как раз если мы имеем генерацию кода, то это не встроенный DSL, а обычный. А встроенный — это чаще результат подключения какой-нибудь библиотеки, о чём я собственно и говорил.
K>Что такое "существенно поменять язык" в данном случае? Систему типов библиотекой можно поменять? А систему модулей? И как это все будет взаимодействовать с уже написанным кодом на не "измененном существенно" языке.
Ну вот подключаем мы скажем Boost.Spirit и начинаем спокойно задавать грамматику для парсера в удобном декларативном виде. Или подключаем Boost.MSM и начинаем задавать конечные автоматы в удобном декларативном виде. При этом код реально становится похож на какой-то другой язык (например так http://www.boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/ch03s04.html#d0e1462), но при этом остаётся всё тем же C++ со всеми его возможностями...
K>Поддержку нормального сборщика в библиотекке не добавить. Нормальную поддержку ленивости тоже.
Хы, ну как раз сборщик мусора и ленивость в C++ получаются подключением библиотек. ))) Но вы сейчас безусловно скажите, что это неправильные сборщики мусора и ленивость. ))) Хотя насчёт сборщика мусора я даже спорить не буду, т.к. вообще не считаю что он нужен в языке (написание его реализаций для C++ мне кажется просто академическими развлечениями).
_>>Да, циклов много, но большая часть из них написана на спец. языке, компилируемом в simd инструкции. K>Ну так и комбинации комбинаторов можно в simd инструкции компилировать.
Не очень понял. Вот есть у меня функция Filter(uchar* data, int width, int height); Она вызывается из кода на C++, а реализацию имеет на другом специальном языке со своим компилятором. И куда мне тут прилепить конвейер? )
K>Допустим, что разные, хотя я бы не стал переоценивать степень "знания" языка, которым не пользовался. Тут непонятно, почему вы упоминаете "играющихся с маргинальными языками" явно в негативном ключе, хотя сами же таким играющимся и являетесь.
Там же ясно было написано в моей предыдущей фразе. Речь о реальных проектах. Т.е. если скажем у вас основная деятельность реализуется с помощью какого-то из мэйнстримовых инструментов (а не Хаскеля), то значит у вас приблизительно такое же отношение к Хаскелю, как у меня к D (и ещё нескольким языкам).
Re[123]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>При этом в C++ нет нормальной реализации практически ни для одной фичи, изобретенной после 68-го года, да и изобретенные до 68-го не все есть.
Это в смысле в голом языке или с учётом библиотек?
K>Да нет, основной принцип апологетики такого рода я уловил довольно давно. K>...
Нет, вы совсем не то поняли. Речь идёт об одном нюансе, связанном именно с иммутабельностью. Дело в том, что если мы возьмём мутабельный контейнер даже в языке без всяких спец. модификаторов и т.п. на эту тему и будем использовать на нём только не меняющее его подмножество операций, то у нас на самом деле получится полноценная работа с иммутабельными данными. Конечно в таком виде там не будет никаких оптимизаций, но их можно без проблем навесить потом, если они вообще понадобятся. Т.е. грубо говоря для нормальной работы с иммутабельными данными нам вообще ничего особенного не требуется от самого языка. Единственная проблема может быть в том, что компилятор не будет отслеживать применение "запрещенных" операций. А вот если в языке есть ещё и поддержка подобной проверки (как есть в D и частично в C++), то тогда вообще всё замечательно.
Re[154]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Да, для этого нужно отказаться от идеи отдавать статику динамически, как ты предлагал
_>С чего бы это? ) Динамика оно или нет — это наше дело. Снаружи оно будет казаться тем, чем мы захотим.
Не будет. CDN это работа со статикий без участия твоего сервера. А если отдават статику динамикой, это непосредственное участие сервера.
Ты можешь внятно ответить на вопрос — каким чудом один и тот же файл можно отдавать через свой сервер, но так, что бы запрос не доходил до сервера ?
Re[120]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Кстати говоря, http://maxim.livejournal.com/392971.html
_>О, интересная ссылочка. Хотя и несколько устаревшая и от фаната эрланга (соответственно очень прогнозируемое первое место), но в остальном весьма любопытно, т.к.
И давно nginx на erlang переписали ?
I>>Если ты внимаетльно посмотришь, то окажется, что хаскель рвёт в хлам твой хвалёный vibe.d I>>Более того, erlang, до безобразия "манеджед" рвет вообще всех, кроме nginx, который, в свою очередь, даже не на С++ написан. I>>D выступил очень удачно — еле-еле обогнал Node.js
_>Хы, ты похоже даже не прочитал текст по своей же ссылке. )))
Наоборот, я практически процитировал.
_>Да, а вообще если интересоваться подобными тестами, то надо смотреть не подобные статьи в жж, а на что-то типа такого http://www.techempower.com/benchmarks/. Правда vibe.d там ещё нет. )
Ты очевидно не понял. Я привел тесты исключительно сетевой части, то есть самого вебсервера, а ты показываешь совсем другие тесты. Надо объяснять, что если сам сервер не выдержит N коннектов, то нагрузив его чем угодно, не получится выдать эти же 10 тыщ коннектов ?
Это понятно ?
Теперь про твои тесты, в частности Data Updates, Multiple Queries — C и C++ отсутствуют среди лидеров. Опаньки ! и почему то отсутствует перформанс парсинга JSON, есть только серилизация.
Вобщем ты привел какие то невнятные тесты, из которых снова не ясно, чем же нативные языки так круты.
Re[146]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Только зарегистрированым.
_>Если это модель с продажами, то тогда надо ставить защиту и соответственно это будет уже не тривиальная система, в которой должен быть и специфический js код на клиенте и серверная поддержка этого. Последнее вполне реализуемо на vibe.d, но в одиночку он естественно не правится.
I>>Да вроде как уже сказал — экономить клиентский трафик. Рекламу показывать, как положено. "почаще обновлять страницу" — это не совсем понятно, что за кейс. Кучу рекламы показывать уже стало проблемой ?
_>Так рекламу чаще всего показывают просто через переход на след. страницу. Во всяком случае на тех сайтах с книгами, что я видел (давно уже не пользуюсь).
Я понял, у тебя ничего нет, только общие слова.
Re[122]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Так вы не ходите по кругу, а объясните: K>>1) Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой.
_>А какую другую может предложить Хаскель? )
А почему вы отвечаете вопросом на вопрос?
Вообще, вынесите пока хаскель за скобки, для ответа на вопрос его притягивать не нужно, да и вы все равно про него недостаточно знаете, чтоб его можно было использовать тут как (контр)пример.
Повторяю вопрос: Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой?
К примеру, связь экстеншн-метода с расширяемым им классом/интерфейсом в C# не является симула-стайл, однако с архитектурной точки зрения может быть удобнее показывать их на диаграмме как члены расширяемого класса, а не как члены некоего статического утилитного класса, или как одновременно и те и другие.
K>>2) Какие проблемы с использованием UML возникают от того, что она другая.
_>Только в том, что в данный момент UML заточен под неё
В чем эта заточенность выражается?
Можно, наверное, сказать, что UML заточен под связь функции с одним типом — т.е. со всякими мультиметодами могут быть проблемы. Да и то на вряд ли — никаких проблем с размещением одной функции в n прямоугольниках нет.
K>>Проблема в том, что для всех юзкейсов удобную функцию не сделаешь, потому и стараются сделать так, чтоб комбинация функций работала так же хорошо, как специально написанная. И если эту главную задачу библиотека не решает — то это уже принципиальная проблема ее архитектуры.
_>Так диапазоны D как раз и предполагают комбинации — даже здесь это было видно. И оно собственно работало, только почему-то плохо сработала оптимизация.
Ну вот, оптимизация сработала плохо — см. выделенное — и след. главную задачу библиотека не решает.
_>В том конкретном случае можно было без проблем написать свою версию (а на самом деле наверное глянуть на исходники оригинальной и что-то там подправить) функций any или until (не знаю какая из них тормозила). Только вот в любом случае проще и быстрее было поменять сам алгоритм. ))) Тем более, что речь шла о форумном споре.
Даже в форумном споре продемонстрировать что-то работающее, после всяких громких заявлений было бы не лишним, особенно когда это "можно было без проблем" (на самом деле, видимо, нельзя без проблем).
_>А если на C#? )
Немного побыстрее, скорее всего, но не принципиально. Вообще Linq to Objects работает немного быстрее f#-библиотек. Такой вот вариант
let rec primes = Seq.cache << Seq.append [2;3] << Seq.filter isPrime <| { 5 .. 2 .. 1000000000 }
and isPrime x = primes.TakeWhile(fun y -> y*y <= x).Select(fun y -> x % y).All(fun x -> x <> 0)
минуту проработает.
Кое-какие средства фьюжена у Linq to Objects, кстати, есть — но не особенно серьезные: набор написанных вручную "сфьюженных" итераторов типа WhereSelectListIterator, которые выбираются в рантайме.
_>Проблемы могут быть только у неумеющих читать документацию. )
Распространенная отговорка. Примерно то же самое и любители бестиповых языков говорят. Ну, "не умеющие читать документацию" в данном случае означает примерно то же, что и "все".
K>>Мои взгляды легко изменятся, если мне кто-нибудь продемонстрирует действительно интересные возможности, за которые не нужно платить (даже в случае их неиспользования). _>Это слишком неопределённо звучит)
Согласен, но довольно утомительно в каждой фразе обозначать контекст разговора. Речь идет о "поднятии уровня" языка
_>Начнём с того, что вы можете посчитать интересными возможностями. А то вот скажем мне кажется интересным распараллеливание цикла с помощью simd и на ядра процессора (в идеале и то и другое вместе). А вас такое быть может вообще не впечатляет... )
"распараллеливание с помощью simd и на ядра процессора" мне кажется интересным. Выжимание из цикла смысла, вкладываемого в него программистом, которое для этого требуется мне тоже интересно, как сложная задача. Но мне интереснее циклы вообще не писать и не читать, средства, которые меня от этого освобождают.
_>Как раз если мы имеем генерацию кода, то это не встроенный DSL, а обычный. А встроенный — это чаще результат подключения какой-нибудь библиотеки, о чём я собственно и говорил.
Встроенный ДСЛ может использоваться для генерации кода. Как в случае сишарпного linq какого-нибудь или хаскельного accelerate.
_>Ну вот подключаем мы скажем Boost.Spirit и начинаем спокойно задавать грамматику для парсера в удобном декларативном виде. Или подключаем Boost.MSM и начинаем задавать конечные автоматы в удобном декларативном виде. При этом код реально становится похож на какой-то другой язык (например так http://www.boost.org/doc/libs/1_55_0/libs/msm/doc/HTML/ch03s04.html#d0e1462), но при этом остаётся всё тем же C++ со всеми его возможностями...
Это называется не "существенно менять язык". Это называется "использовать библиотеку". Базовая фича для языка программирования.
_>Хы, ну как раз сборщик мусора и ленивость в C++ получаются подключением библиотек. )))
Вот только с нормальным сборщиком или нормальной реализацией ленивости это нельзя даже сравнивать, так что толку от таких "подключений" нет.
_>Но вы сейчас безусловно скажите, что это неправильные сборщики мусора и ленивость. )))
Ну вот, вы и сами все знаете.
_>Хотя насчёт сборщика мусора я даже спорить не буду, т.к. вообще не считаю что он нужен в языке (написание его реализаций для C++ мне кажется просто академическими развлечениями).
Это то как раз понятно, потому что ваша позиция заключается в том, что ничего сверх того, что есть в C++ (за исключением перламутровых пуговиц добавленных в D) в принципе не нужно. И собственно наличие в c++ и является критерием нужности.
_>Хотя насчёт сборщика мусора я даже спорить не буду
Насчет ленивости, стало быть, спорить будете?
_>Не очень понял. Вот есть у меня функция Filter(uchar* data, int width, int height); Она вызывается из кода на C++, а реализацию имеет на другом специальном языке со своим компилятором. И куда мне тут прилепить конвейер? )
Туда что код Map(что-то там).Filter(что-то там).Fold(что-то там) превращается в код на "другом специальном языке со своим компилятором".
_>Там же ясно было написано в моей предыдущей фразе. Речь о реальных проектах. Т.е. если скажем у вас основная деятельность реализуется с помощью какого-то из мэйнстримовых инструментов (а не Хаскеля), то значит у вас приблизительно такое же отношение к Хаскелю, как у меня к D (и ещё нескольким языкам).
Да, у меня именно такое же отношение к хаскелю, как у вас к ди, так что непонятно, откуда вы выводите противопоставление.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[124]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>При этом в C++ нет нормальной реализации практически ни для одной фичи, изобретенной после 68-го года, да и изобретенные до 68-го не все есть. _>Это в смысле в голом языке или с учётом библиотек?
С учетом библиотек.
_>Нет, вы совсем не то поняли. Речь идёт об одном нюансе, связанном именно с иммутабельностью. Дело в том, что если мы возьмём мутабельный контейнер даже в языке без всяких спец. модификаторов и т.п. на эту тему и будем использовать на нём только не меняющее его подмножество операций, то у нас на самом деле получится полноценная работа с иммутабельными данными.
1) Это не имеет отношения к обсуждаемому примеру, в котором используются не "не меняющее его подмножество операций", которого вообще у вашего "иммутабельного типа" нет, а мутирующие операции используются таким образом (линейно и уникально), что мутабельность структуры данных семантически не наблюдается.
2) Нет, если вы используете "не меняющее его подмножество операций", то это не является "полноценной работой с иммутабельными данными". Иммутабельность вообще не про это. Иммутабельность — это, например, когда вы можете рассчитывать, что всем остальным держателем ссылки на объект, с которым вы работаете не доступны мутирующие операции над ним и они не могут его "испортить", а значит вам не нужно оборонительно копировать (не поверхностно) обсуждаемый объект.
Еще иммутабельность — это дешевое создание версии, этот конкретный аспект обычно называют "персистентность".
_>Конечно в таком виде там не будет никаких оптимизаций, но их можно без проблем навесить потом, если они вообще понадобятся. Т.е. грубо говоря для нормальной работы с иммутабельными данными нам вообще ничего особенного не требуется от самого языка.
Да, для описываемой вами "иммутабельности" ничего от языка не требуется.
_>Единственная проблема может быть в том, что компилятор не будет отслеживать применение "запрещенных" операций. А вот если в языке есть ещё и поддержка подобной проверки (как есть в D и частично в C++), то тогда вообще всё замечательно.
Вы же сами такой контроль и преодолели, сделав структуру данных, свободную от какого-то там "контроля". Вообще отслеживание применения запрещенных операций есть в любом типизированном языке. То, что вы называете "проверкой" в Ди — это на самом деле инструмент для "выдавания" структуры, имеющей запрещенные операции за структуру не имеющую их. Т.е. это инструмент для обхода проверки, лупхол.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[155]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не будет. CDN это работа со статикий без участия твоего сервера. А если отдават статику динамикой, это непосредственное участие сервера.
I>Ты можешь внятно ответить на вопрос — каким чудом один и тот же файл можно отдавать через свой сервер, но так, что бы запрос не доходил до сервера ?
Я тебе уже несколько раз говорил, но до тебя похоже даже прямой текст перестал доходить. Сервер отработает один раз (отдавая в CDN).
Хотя если у нас вообще только статика на сервере, то естественно никакие фреймворки типа vibe.d вообще не нужны, т.к. привносят только ненужную сложность. Но дело именно в сложности и неудобности (в сравнение со статическим сервером), а не в меньшем быстродействие, которое мы тут обсуждали.
Re[121]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>И давно nginx на erlang переписали ?
Nginx там только для оценочного сравнения, т.к. вообще не относится к группе исследуемых фреймворков (они же все для динамики). Т.е. фреймворка на C/C++ в данном тесте вообще не было. А первое место занял именно ерланговский фреймворк, что абсолютно не удивительно с учётом пристрастий автора теста.
I>Ты очевидно не понял. Я привел тесты исключительно сетевой части, то есть самого вебсервера, а ты показываешь совсем другие тесты. Надо объяснять, что если сам сервер не выдержит N коннектов, то нагрузив его чем угодно, не получится выдать эти же 10 тыщ коннектов ?
В большинстве таких фреймворков сервер интегрирован во фреймворк, а не живёт где-то отдельно. )
Re[123]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>А почему вы отвечаете вопросом на вопрос? K>Вообще, вынесите пока хаскель за скобки, для ответа на вопрос его притягивать не нужно, да и вы все равно про него недостаточно знаете, чтоб его можно было использовать тут как (контр)пример. K>Повторяю вопрос: Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой?
Нет, дело как раз в Хаскеле. Потому как, раз он не поддерживает связь "симула-стайл", то должен предложить что-то взамен для тех же целей.
K>В чем эта заточенность выражается? K>Можно, наверное, сказать, что UML заточен под связь функции с одним типом — т.е. со всякими мультиметодами могут быть проблемы. Да и то на вряд ли — никаких проблем с размещением одной функции в n прямоугольниках нет.
Вы в начале опишите с помощью чего на Хаскеле можно спроектировать нормальную иерархическую архитектуру, а мы уже потом посмотрим как это отобразить в UML.
Вот например возьмём самую лубочную реализацию обычного ООП GUI приложения:
class MyView: public View{
void OnDraw() override;//рисуем что-то в окне
};
class MyWindow: public Window{
Menubar menu;
Toolbar tools;
MyView view;
Statusbar status;
void OnViewClear();//реакция на меню/тулбар/хоткейpublic:
MyWindow();//установка элементов по местам и настройка реакций на события
};
class MyApp: public App{
MyWindow window;
public:
MyApp();//Инициализация каких-нибудь библиотек
~MyApp();//Деинициализация библиотек
};
int main()
{
MyApp app;
app.Run();//основной цикл приложения
}
Рисовать UML диаграмму классов для этого кода я здесь не буду, потому как думаю все без проблем представляют её себе. Так вот, взглянув на эту диаграмму я мгновенно понимаю всю структуру приложения (да, сейчас то это и по коду можно, но на практике код будет во многих больших файлах, а не как здесь).
Можно увидеть каноническую реализацию подобного кода на Хаскеле? Т.е. не использование из Хаскеля биндинга к какой-то известной ООП GUI библиотеки (т.к. там всё равно будет сохраняться подобная же структура, хотя и по кривому), а именно если взять GUI библиотеку написанную на Хаскеле с нуля в правильном функциональном стиле.
Ну и соответственно будет интересно взглянуть на UML диаграмму для такого канонического кода — оценим насколько она позволяет понять всю архитектуру приложения.
_>>Так диапазоны D как раз и предполагают комбинации — даже здесь это было видно. И оно собственно работало, только почему-то плохо сработала оптимизация. K>Ну вот, оптимизация сработала плохо — см. выделенное — и след. главную задачу библиотека не решает.
Вот зачем выдавать какой-то конкретный баг/недоработку в реализации за архитектурную проблему? Это уже демагогия слишком низкого уровня...
K>"распараллеливание с помощью simd и на ядра процессора" мне кажется интересным. Выжимание из цикла смысла, вкладываемого в него программистом, которое для этого требуется мне тоже интересно, как сложная задача. Но мне интереснее циклы вообще не писать и не читать, средства, которые меня от этого освобождают.
Хех, ну я бы тоже такое предпочёл. Только вот в реальном мире нет ничего подобного. Например даже C++ со своим автовекторизатором не дотягивает по эффективности до специализированных (и соответственно более низкоуровневых) решений. А уж про другие реализации я вообще молчу.
K>Это называется не "существенно менять язык". Это называется "использовать библиотеку". Базовая фича для языка программирования.
Да, но в некоторых языках (типа C++ или D) есть возможности очень сильно изменять язык прямо в коде (метапрограммирование, перегрузка операторов и т.п.). И соответственно в таких языках использование некоторых библиотек очень сильно меняет язык, вплоть до задания полноценных встроенных DSL.
_>>Хотя насчёт сборщика мусора я даже спорить не буду, т.к. вообще не считаю что он нужен в языке (написание его реализаций для C++ мне кажется просто академическими развлечениями). K>Это то как раз понятно, потому что ваша позиция заключается в том, что ничего сверх того, что есть в C++ (за исключением перламутровых пуговиц добавленных в D) в принципе не нужно. И собственно наличие в c++ и является критерием нужности.
Как раз нет. У меня вообще огромный список претензий к C++. В первую очередь это конечно отсутствие статической интроспекции — это просто дико бросается в глаза. Потом переусложнённый и одновременно недостаточно функциональный (в первую очередь нельзя строки передавать как параметры) синтаксис шаблонов (при использование их для метапрограммирования, а не для обобщённого). Далее отсутствие удобной системы модулей и т.д. и т.п. В общем я могу долго продолжать о недостатках C++. Только вот при всём при этом к сожалению ничего лучше по сумме параметров (включающих и наличие библиотек/инструметов и стабильность/оптимизированность) всё равно на рынке не наблюдается.
Но вот относительно конкретно сборщика мусора у меня именно идеологическая позиция, что при наличие полноценного RAII он является только вредным элементом.
K>Насчет ленивости, стало быть, спорить будете?
Насчёт ленивости у меня следующая позиция:
— в принципе ленивость вещь полезная, но не глобально, а в специфических случаях
— в C++, в самом языке, естественно ничего подобного нет
— в C++ есть много библиотек на эту тему (в первую очередь в Boost'е), которые покрывают множество сценариев с ленивостью, но думаю что не все, т.к. там используется так сказать экстенсивный подход, а не фундаментальный
— все встреченные мною случаи, когда была бы полезна ленивость, покрывались библиотеками из Boost'а.
_>>Не очень понял. Вот есть у меня функция Filter(uchar* data, int width, int height); Она вызывается из кода на C++, а реализацию имеет на другом специальном языке со своим компилятором. И куда мне тут прилепить конвейер? ) K>Туда что код Map(что-то там).Filter(что-то там).Fold(что-то там) превращается в код на "другом специальном языке со своим компилятором".
Всё равно не понял. Ну т.е. если вы говорите о том, что бы заменить код вида "Filter(data);Map(data);Fold(data);" на "data.Filter().Map().Fold();", то это действительно без проблем делается. Только вот какой-либо пользы от подобного нет. А если вы про что-то другое, то тогда поясните подробнее.
K>Да, у меня именно такое же отношение к хаскелю, как у вас к ди, так что непонятно, откуда вы выводите противопоставление.
Если точно такое же, то тогда никаких противопоставлений. ) Просто вы ни разу не озвучивали тут свои основные инструменты для работы, так что создаётся впечатление, что вы позиционируете Хаскель на эту роль.
Re[124]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Можно увидеть каноническую реализацию подобного кода на Хаскеле? Т.е. не использование из Хаскеля биндинга к какой-то известной ООП GUI библиотеки (т.к. там всё равно будет сохраняться подобная же структура, хотя и по кривому), а именно если взять GUI библиотеку написанную на Хаскеле с нуля в правильном функциональном стиле. http://www.haskell.org/haskellwiki/Existential_type
Re[125]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>>>При этом в C++ нет нормальной реализации практически ни для одной фичи, изобретенной после 68-го года, да и изобретенные до 68-го не все есть. _>>Это в смысле в голом языке или с учётом библиотек? K>С учетом библиотек.
Если с учётом библиотек, то вы очевидно не правы))) Есть множество различных техник, которые добавляются библиотеками. Это же можно целый день перечислять всякие мелочи приятные. Но для примера (просто чтобы не звучало голословно) возьмём например ту же модель акторов.
_>>Нет, вы совсем не то поняли. Речь идёт об одном нюансе, связанном именно с иммутабельностью. Дело в том, что если мы возьмём мутабельный контейнер даже в языке без всяких спец. модификаторов и т.п. на эту тему и будем использовать на нём только не меняющее его подмножество операций, то у нас на самом деле получится полноценная работа с иммутабельными данными. K>1) Это не имеет отношения к обсуждаемому примеру, в котором используются не "не меняющее его подмножество операций", которого вообще у вашего "иммутабельного типа" нет, а мутирующие операции используются таким образом (линейно и уникально), что мутабельность структуры данных семантически не наблюдается.
Это имело отношение к первому примеру на D, когда использовался самый обычный массив, но при этом с модификатором immutable. Как раз с помощью него и ограничивается набор возможных операций (т.е. ~ разрешён, а =~ нет). Так что на мой взгляд тот пример работал с полноценными иммутабельным данными. Только он при этом естественно был очень медленным, т.к. никаких оптимизаций в связи с иммутабельностью не производилось.
K>2) Нет, если вы используете "не меняющее его подмножество операций", то это не является "полноценной работой с иммутабельными данными". Иммутабельность вообще не про это. Иммутабельность — это, например, когда вы можете рассчитывать, что всем остальным держателем ссылки на объект, с которым вы работаете не доступны мутирующие операции над ним и они не могут его "испортить", а значит вам не нужно оборонительно копировать (не поверхностно) обсуждаемый объект.
Да да, immutable в D как раз подобное гарантирует. Если конечно не прибегать к чёрной магии кастов. )))
K>Еще иммутабельность — это дешевое создание версии, этот конкретный аспект обычно называют "персистентность".
Угу, та самая оптимизация. И вот её модификатор immutable в D естественно не предоставляет. Но как я уже показал, мы без проблем можем добавить её сами.
K>Вы же сами такой контроль и преодолели, сделав структуру данных, свободную от какого-то там "контроля". Вообще отслеживание применения запрещенных операций есть в любом типизированном языке. То, что вы называете "проверкой" в Ди — это на самом деле инструмент для "выдавания" структуры, имеющей запрещенные операции за структуру не имеющую их. Т.е. это инструмент для обхода проверки, лупхол.
Просто есть два разных подхода к этому. Можно для каждого нюанса создавать отдельный тип данных (и соответственно заниматься копипастом части кода между ними), а можно создать один универсальный и управлять ситуацией с помощью внешних модификаторов. В C++ у нас есть всего один такой модификатор (const), а в D у нас есть ещё immutable и не только.
Re[124]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, дело как раз в Хаскеле. Потому как, раз он не поддерживает связь "симула-стайл", то должен предложить что-то взамен для тех же целей.
Ну вот об этом я и говорю. Ваши представления о хаскеле довольно смутные, так что использовать его для предоставления (контр)примеров в разговоре с вами затруднительно. Связь "симула-стайл" т.е. хранение вместе с данными ссылки на словарь "методов" хаскель поддерживает. С поправкой на различие между "наследованием" и "имплементацией". Поскольку разница между этими отношениями в UML поддерживается, никаких проблем и нет. Но это не важно, потому что не просматривается какой-то несовместимости UML и других способов группировки данных и функций, не симула-стайл, которые используются тоже и не только в хаскеле, но даже и каком-нибудь сишарпе, "протитипных"-ООЯ, языках с развитой системой модулей и т.д.
Потому повторяю вопросы:
1) Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой?
2) В чем выражается эта заточенность под симула-стайл?
_>Вы в начале опишите с помощью чего на Хаскеле можно спроектировать нормальную иерархическую архитектуру
С помощью классов типов. Как второй вариант — с помощью "ручного управления" словарями "методов", т.е. "прототипного" подхода. Выглядеть на диаграмме это будет точно так же.
_>Вот например возьмём самую лубочную реализацию обычного ООП GUI приложения:
data MyView = MyView {
drawView :: UI () -- рисуем что-то в окне
}
instance View MyView where onDraw = drawView
-- и т.д.
_>Можно увидеть каноническую реализацию подобного кода на Хаскеле? Т.е. не использование из Хаскеля биндинга к какой-то известной ООП GUI библиотеки (т.к. там всё равно будет сохраняться подобная же структура, хотя и по кривому), а именно если взять GUI библиотеку написанную на Хаскеле с нуля в правильном функциональном стиле.
Ну так
1) С чего вдруг появляться какой-то GUI-библиотеке написанной на хаскеле "с нуля"? Естественно, все библиотеки и будут "биндингами известных библиотек".
2) Что вообще необычного вы ожидаете от изображения виджетов в хаскеле? Все интересное в GUI там в работе с событиями, ну может еще в лайауте виджетов.
_>Вот зачем выдавать какой-то конкретный баг/недоработку в реализации за архитектурную проблему? Это уже демагогия слишком низкого уровня...
Ну перепишите тот конвейер из трех стадий на D, который основную работу делает, и чтоб он оптимизировался. Тогда и посмотрим. А так вы предлагаете верить что все работает, но при этом 1) не демонстрируете рабочий пример. 2) утверждаете, что не пишете код с конвейерами.
_>Хех, ну я бы тоже такое предпочёл. Только вот в реальном мире нет ничего подобного.
Наработки вполне есть. Я же вам в этом споре неоднократно демонстрировал конвейеры, оптимизирующиеся в один цикл, но все это в очередной раз уже из вашей памяти выпало.
_>Например даже C++ со своим автовекторизатором не дотягивает по эффективности до специализированных (и соответственно более низкоуровневых) решений.
Вот только векторизировать цикл вообще-то более сложная задача, чем векторизировать комбинацию комбинаторов. Потому, что во втором случае у компилятора больше информации.
_>Да, но в некоторых языках (типа C++ или D) есть возможности очень сильно изменять язык прямо в коде (метапрограммирование, перегрузка операторов и т.п.). И соответственно в таких языках использование некоторых библиотек очень сильно меняет язык, вплоть до задания полноценных встроенных DSL.
Нет, метапрограммирование в масштабах C++ и уж тем более "перегрузка операторов" на "сильные изменения языка" никак не тянет.
K>>Это то как раз понятно, потому что ваша позиция заключается в том, что ничего сверх того, что есть в C++ (за исключением перламутровых пуговиц добавленных в D) в принципе не нужно. И собственно наличие в c++ и является критерием нужности.
_>Как раз нет. У меня вообще огромный список претензий к C++. В первую очередь это конечно отсутствие статической интроспекции — это просто дико бросается в глаза. Потом переусложнённый и одновременно недостаточно функциональный (в первую очередь нельзя строки передавать как параметры) синтаксис шаблонов (при использование их для метапрограммирования, а не для обобщённого). Далее отсутствие удобной системы модулей и т.д. и т.п.
Я же написал про перламутровые пуговицы.
_>В общем я могу долго продолжать о недостатках C++. Только вот при всём при этом к сожалению ничего лучше по сумме параметров (включающих и наличие библиотек/инструметов и стабильность/оптимизированность) всё равно на рынке не наблюдается.
Да, имплементации у С++ лучшие на рынке, и вообще богатая инфраструктура в смысле библиотек/инструментов но язык ничего интересного из себя не представляет, крайне убогий и невыразительный.
_>Но вот относительно конкретно сборщика мусора у меня именно идеологическая позиция, что при наличие полноценного RAII он является только вредным элементом.
Это, конечно, вредный элемент в низкоуровневом языке. Но в высокоуровневом зато необходимый.
_>- в принципе ленивость вещь полезная, но не глобально, а в специфических случаях
Тут вообще вопрос не в "глобально", в смысле по-умолчанию или нет. А в поддержке со стороны рантайма, в том числе для SMP и т.д. По-умолчанию ленивость или аннотируется явно, но она должна быстро работать — иначе в ней особого смысла нет. Так вот быстро работающую поддержку ленивости в библиотеке не сделать. по крайней мере, я такой не видел.
_>- все встреченные мною случаи, когда была бы полезна ленивость, покрывались библиотеками из Boost'а.
Учитывая, что с вашей точки зрения (попробую угадать) она полезна примерно никогда — перекрыть пустое множество юзкейсов даже в плюсах не сложно.
_>Всё равно не понял. Ну т.е. если вы говорите о том, что бы заменить код вида "Filter(data);Map(data);Fold(data);" на "data.Filter().Map().Fold();", то это действительно без проблем делается. Только вот какой-либо пользы от подобного нет. А если вы про что-то другое, то тогда поясните подробнее.
Нет, интереснее что-то менее тривиальное. А чтоб мне объяснить подробнее вы сами должны объяснить подробнее, что делаете для этой самой "генерации simd инструкций из спецязыка", и что это за спецязык.
_>Если точно такое же, то тогда никаких противопоставлений. ) Просто вы ни разу не озвучивали тут свои основные инструменты для работы, так что создаётся впечатление, что вы позиционируете Хаскель на эту роль.
Не понятно только, какое это отношение имеет к любой из обсуждаемых нами тем.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[126]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Если с учётом библиотек, то вы очевидно не правы))) Есть множество различных техник, которые добавляются библиотеками. Это же можно целый день перечислять всякие мелочи приятные. Но для примера (просто чтобы не звучало голословно) возьмём например ту же модель акторов.
Ну, удивите меня примером. какую-то костыльную модель акторов можно, конечно, в библиотеке сделать. Но это будет такая же недоделанная фича без поддержки языка, как и то, что я перечислял.
_>Это имело отношение к первому примеру на D, когда использовался самый обычный массив, но при этом с модификатором immutable. Как раз с помощью него и ограничивается набор возможных операций (т.е. ~ разрешён, а =~ нет). Так что на мой взгляд тот пример работал с полноценными иммутабельным данными. Только он при этом естественно был очень медленным, т.к. никаких оптимизаций в связи с иммутабельностью не производилось.
И про это вы говорили "получится полноценная работа с иммутабельными данными"? Если это полноценная работа — что же тогда неполноценная?
K>>Еще иммутабельность — это дешевое создание версии, этот конкретный аспект обычно называют "персистентность".
_>Угу, та самая оптимизация.
Это не столько оптимизация, сколько другие структуры данных, лучше подходящие для дешевого создания версий.
_>Но как я уже показал, мы без проблем можем добавить её сами.
Вы этого не показали. Где вы какую-то оптимизацию добавили?
_>Просто есть два разных подхода к этому. Можно для каждого нюанса создавать отдельный тип данных (и соответственно заниматься копипастом части кода между ними), а можно создать один универсальный и управлять ситуацией с помощью внешних модификаторов. В C++ у нас есть всего один такой модификатор (const), а в D у нас есть ещё immutable и не только.
Ну так я и сказал. В языках без какого-нибудь метапрограммирования отличие в ручном написании обертки. там где обертку можно автоматически генерировать — вообще никакой разницы не будет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[125]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну вот об этом я и говорю. Ваши представления о хаскеле довольно смутные, так что использовать его для предоставления (контр)примеров в разговоре с вами затруднительно. Связь "симула-стайл" т.е. хранение вместе с данными ссылки на словарь "методов" хаскель поддерживает. С поправкой на различие между "наследованием" и "имплементацией". Поскольку разница между этими отношениями в UML поддерживается, никаких проблем и нет. Но это не важно, потому что не просматривается какой-то несовместимости UML и других способов группировки данных и функций, не симула-стайл, которые используются тоже и не только в хаскеле, но даже и каком-нибудь сишарпе, "протитипных"-ООЯ, языках с развитой системой модулей и т.д.
Нет, недостаточное знание Хаскеля может помешать аргументировать что-то его кодом мне, но никак не вам. Не стоит путать возможность читать код и возможность писать классный код на каком-то языке.
K>Потому повторяю вопросы: K>1) Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой? K>2) В чем выражается эта заточенность под симула-стайл?
Я уже не раз отвечал на это в общем виде, но как обычно у нас с вами это ни к чему продуктивному не привело и разговор пошёл по кругу. Поэтому я и предлагаю перейти к конкретике — на ней демагогия и т.п. не работают. ))) Вот я привёл максимально короткий и банальный пример. Если надо, могу даже диаграммку под него нарисовать, хотя думаю каждый может с ходу представить её в голове. И ожидаю от вас в ответ того же. После этого можем продолжать какую-то конструктивную дискуссию уже на основе этих конкретных данных.
_>>Вы в начале опишите с помощью чего на Хаскеле можно спроектировать нормальную иерархическую архитектуру K>С помощью классов типов. Как второй вариант — с помощью "ручного управления" словарями "методов", т.е. "прототипного" подхода. Выглядеть на диаграмме это будет точно так же.
Это всё общие слова, а интересует конкретика.
_>>Вот например возьмём самую лубочную реализацию обычного ООП GUI приложения:
K>
K>data MyView = MyView {
K> drawView :: UI () -- рисуем что-то в окне
K>}
K>instance View MyView where onDraw = drawView
K>-- и т.д.
K>
И? Где собственно код примера на Хаскеле и его UML диаграмма? Я пока вижу только пример сомнительной реализации аналога виртуальных функций. А где всё остальное? ) У меня же было то всего 3 класса из нескольких строчек — это разве долго показать, если нет никаких проблем?
K>Ну так K>1) С чего вдруг появляться какой-то GUI-библиотеке написанной на хаскеле "с нуля"? Естественно, все библиотеки и будут "биндингами известных библиотек".
Ну если для обычных императивных языков действительно мало смысла повторять уже существующий (хотя и на другом языке) код, то для Хаскеля и ему подобных возможно в этом был бы смысл, т.к. в связи с иной архитектурой это возможно не был бы чистый повтор. Или же вы считаете, что и тут понадобилось бы подделываться под ООП? )
K>2) Что вообще необычного вы ожидаете от изображения виджетов в хаскеле? Все интересное в GUI там в работе с событиями, ну может еще в лайауте виджетов.
Ну для начала композиция... А потом обработка событий была и в моём примере. Выполненная как раз по обычной ООП технике (внутри конструктора Window идёт код вида menuitem1.connect(Window::OnFileNew); и т.п.). Т.е. у вас была возможность кратенько показать, как вы говорите интересное, но что-то вы пропустили эту возможность.
K>Ну перепишите тот конвейер из трех стадий на D, который основную работу делает, и чтоб он оптимизировался. Тогда и посмотрим. А так вы предлагаете верить что все работает, но при этом 1) не демонстрируете рабочий пример. 2) утверждаете, что не пишете код с конвейерами.
Рабочий пример тут уже был. С теми же самыми map'и — там этот принцип работы влиял уже даже не на быстродействия, а на результат кода, так что мы очень чётко это тут отследили. Более того, с until.all тоже пример работал, но наблюдалось падение быстродействия по сравнению с линейным кодом. В чём причина этого падения я не в курсе и разбираться лень, т.к. такой код у меня только на форуме и встречался.
_>>Хех, ну я бы тоже такое предпочёл. Только вот в реальном мире нет ничего подобного. K>Наработки вполне есть. Я же вам в этом споре неоднократно демонстрировал конвейеры, оптимизирующиеся в один цикл, но все это в очередной раз уже из вашей памяти выпало.
Вообще то здесь речь шла об автовекторизации. )
K>Вот только векторизировать цикл вообще-то более сложная задача, чем векторизировать комбинацию комбинаторов. Потому, что во втором случае у компилятора больше информации.
Если мы говорим про SIMD, то вряд ли. Там же ещё специфическая векторизация...
K>Нет, метапрограммирование в масштабах C++ и уж тем более "перегрузка операторов" на "сильные изменения языка" никак не тянет.
Это не изменения языка, а инструменты для изменения. В основном путём построения встроенных DSL.
K>Да, имплементации у С++ лучшие на рынке, и вообще богатая инфраструктура в смысле библиотек/инструментов но язык ничего интересного из себя не представляет, крайне убогий и невыразительный.
Я бы такое сказал про C... А вот у C++ имеется целый ряд оригинальных решений. Как насчёт той же move semantic? ) Я уже не говорю про метапрограммирование на шаблонах. )
K>Тут вообще вопрос не в "глобально", в смысле по-умолчанию или нет. А в поддержке со стороны рантайма, в том числе для SMP и т.д. По-умолчанию ленивость или аннотируется явно, но она должна быстро работать — иначе в ней особого смысла нет. Так вот быстро работающую поддержку ленивости в библиотеке не сделать. по крайней мере, я такой не видел.
Хы, вот как раз в обычных реализация C++ ленивость идеально быстрая))) У неё другое ограничение — она скажем так работает только на подмножестве языка.
K>Учитывая, что с вашей точки зрения (попробую угадать) она полезна примерно никогда — перекрыть пустое множество юзкейсов даже в плюсах не сложно.
На самом деле после выхода C++11 практически перестал использовать. Потому как стало проще банально поставить лямбду (такая вот ленивость руками). Конечно это казалось бы лишний шаг, но зато поддерживает любой код и не надо лезть в документацию библиотеки элементов ленивости по каждому чиху. Более того, в итоге код становится понятен всем (лямбды уже все изучили, а вот всякие сложные библиотеки из Boost знают далеко не все).
K>Нет, интереснее что-то менее тривиальное. А чтоб мне объяснить подробнее вы сами должны объяснить подробнее, что делаете для этой самой "генерации simd инструкций из спецязыка", и что это за спецязык.
Эммм, запускаю компилятор этого языка и всё. И потом просто добавляю полученные объектные файлы к построению приложения на C++. А язык собственно такой: https://ispc.github.io/ispc.html#the-ispc-language.
K>Не понятно только, какое это отношение имеет к любой из обсуждаемых нами тем.
Это поясняет общую позицию человека. ) Ну скажем фанатик (готов всё делать на любимом языке из принципа), теоретик (превозносит некий язык из общих соображений, но никогда не делал ничего серьёзного), профи (знает и использует оптимальные инструменты на текущий момент и интересуется остальными для общего развития), неудачливый (вынужден использовать на работе ужасные инструменты и отрывается дома со всяческими игрушками), новичок и т.п.
Re[127]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Ну, удивите меня примером. какую-то костыльную модель акторов можно, конечно, в библиотеке сделать. Но это будет такая же недоделанная фича без поддержки языка, как и то, что я перечислял.
Т.е. вы считаете, что для реализации модели акторов необходима обязательно поддержка в синтаксисе языка? ) Очень забавная точка зрения. А я тут даже в Прологе видел реализацию потоков в таком стиле... )))
K>И про это вы говорили "получится полноценная работа с иммутабельными данными"? Если это полноценная работа — что же тогда неполноценная?
Полноценная в том смысле, что данные были реально иммутабельные. Хотя при этом мы не использовали никаких отдельных специальных типов. Если добавить ещё и оптимизацию, то вообще всё отлично было бы. )
K>Это не столько оптимизация, сколько другие структуры данных, лучше подходящие для дешевого создания версий.
Я про это и говорю.
K>Вы этого не показали. Где вы какую-то оптимизацию добавили?
Так последний мой пример был как раз с оптимизацией — там была реализована персистентная структура с версиями массива.
K>Ну так я и сказал. В языках без какого-нибудь метапрограммирования отличие в ручном написании обертки. там где обертку можно автоматически генерировать — вообще никакой разницы не будет.
А собственно в каких популярных языках у нас наблюдается эффективное метапрограммирование? )
Re[126]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Нет, недостаточное знание Хаскеля может помешать аргументировать что-то его кодом мне, но никак не вам. Не стоит путать возможность читать код и возможность писать классный код на каком-то языке.
Причем тут писать/читать код? Вы приводите, например, такой аргумент
Нет, дело как раз в Хаскеле. Потому как, раз он не поддерживает связь "симула-стайл", то должен предложить что-то взамен для тех же целей.
хотя на самом деле хаскель симула-стайл связь с хранением в "объекте" ссылки на словарь поддерживает с помощью тайпклассов и экзистенциальных типов.
Разница с симула-лайк ООП будет в том, что там, где не нужна дин. диспетчеризация таскать ссылку на словарь не нужно: словарь подставит компилятор. Но на диаграмме это никак не отразится.
Потому я и говорю, что для аргументации вам лучше переключится на язык, который вы знаете, каких-то совершенно диких представлений о хаскеле вы уже достаточно приводили, но аргументацию на фантазиях не построить.
Возможно, можно построить аргументацию за недостаточность средств UML для отображения сложных иерархий классов/инстансов, но то, что средства UML окажутся невостребованными — это полная ерунда.
Потому повторяю вопросы:
1) Откуда следует, что "связь функций и данных" должна быть обязательно симула-стайл, а не какой-то другой?
Вообще, то, что функция задана на множестве объектов какого-то типа — вполне достаточно для того, чтоб были польза и смысл обозначить связь такой функйии и такого тоипа на диаграмме. Техническая же реализация этой связи и ее "виртуальность" (не знаю точно, что вы в этом случае подразумеваете) никакого принципиального архитектурного значения не имеет.
2) В чем выражается эта заточенность под симула-стайл?
Тут, думаю, никаких особых пояснений не требуется, диаграммы используют для совсем не симула-стайл языков. Естественно, для применения UML для очередного языка нужно установить/согласовать некоторые смыслы и интерпретации, отличающиеся от другого языка, но никаких необходимых расширений UML вы так и не показали.
_>Я уже не раз отвечал на это в общем виде, но как обычно у нас с вами это ни к чему продуктивному не привело и разговор пошёл по кругу.
Вы постоянно заявляете, что на что-то ответили. Вот только сослаться на ответ не можете. Вот и сейчас не сошлетесь.
_>Поэтому я и предлагаю перейти к конкретике — на ней демагогия и т.п. не работают.
Конечно не работает, потому-то вы к конкретике и не перейдете.
_>Вот я привёл максимально короткий и банальный пример. Если надо, могу даже диаграммку под него нарисовать, хотя думаю каждый может с ходу представить её в голове. И ожидаю от вас в ответ того же. После этого можем продолжать какую-то конструктивную дискуссию уже на основе этих конкретных данных.
Пример все равно не рабочий, так какой смысл воспроизводить больше, чем нужно для того, чтоб понять как это воспроизвести полностью?
K>>С помощью классов типов. Как второй вариант — с помощью "ручного управления" словарями "методов", т.е. "прототипного" подхода. Выглядеть на диаграмме это будет точно так же.
_>Это всё общие слова, а интересует конкретика.
Чем приведенный мной код не конкретика?
_>И? Где собственно код примера на Хаскеле и его UML диаграмма? Я пока вижу только пример сомнительной реализации аналога виртуальных функций. А где всё остальное? )
А чего вам еще не хватает?
_>У меня же было то всего 3 класса из нескольких строчек — это разве долго показать, если нет никаких проблем?
Это переписывается чисто механически. И что потом?
_>Ну если для обычных императивных языков действительно мало смысла повторять уже существующий (хотя и на другом языке) код, то для Хаскеля и ему подобных возможно в этом был бы смысл, т.к. в связи с иной архитектурой это возможно не был бы чистый повтор. Или же вы считаете, что и тут понадобилось бы подделываться под ООП? )
Даже если что-то, допустим, имеет смысл — это вовсе не означает, что это сделают. Думаю, что человекогоды, вложенные в любой из популярных GUI-тулкитов, вроде QT превышают человекогоды вложенные во всю инфраструктуру хаскеля, причем в разы. Т.е. при самых оптимистичных оценках увеличения производительности программиста на хаскеле, по сравнению с программистом на языке, на котором эта самая GUI библиотека реализована — воспроизведение полноценной гуи-библиотеки на хаскеле — совершенно нереальный проект для комьюнити.
_>Ну для начала композиция... А потом обработка событий была и в моём примере. Выполненная как раз по обычной ООП технике (внутри конструктора Window идёт код вида menuitem1.connect(Window::OnFileNew); и т.п.). Т.е. у вас была возможность кратенько показать, как вы говорите интересное, но что-то вы пропустили эту возможность.
И то и другое более высокоуровневые конструкции, низкоуровневое представление тут особого значения не имеет. FRP для обработки событий, например, применяется в сочетании с биндингами для популярных гуи-тулкитов. И я вам это уже показывал в примере с игрой "астероиды" выше в этой ветке (уже, наверное, больше полугода назад).
_>Рабочий пример тут уже был. С теми же самыми map'и — там этот принцип работы влиял уже даже не на быстродействия, а на результат кода, так что мы очень чётко это тут отследили. Более того, с until.all тоже пример работал, но наблюдалось падение быстродействия по сравнению с линейным кодом.
Рабочий не в том смысле, что что-то считает. А рабочий пример оптимизации. Код, который считает что нужно и для которого оптимизация работает.
_>В чём причина этого падения я не в курсе и разбираться лень, т.к. такой код у меня только на форуме и встречался.
Ну тут видимо дело в специфической субкультуре программирования, потому что убогость чего-то, обычно, превращает это в фичу "только для форумов", но вот только в какой-нибудь linq to objects используется не только на форумах, хотя судя по всему, он работает даже хуже дишных рейнджей.
K>>Наработки вполне есть. Я же вам в этом споре неоднократно демонстрировал конвейеры, оптимизирующиеся в один цикл, но все это в очередной раз уже из вашей памяти выпало. _>Вообще то здесь речь шла об автовекторизации. )
По автовекторизации тоже работы есть.
K>>Вот только векторизировать цикл вообще-то более сложная задача, чем векторизировать комбинацию комбинаторов. Потому, что во втором случае у компилятора больше информации.
_>Если мы говорим про SIMD, то вряд ли. Там же ещё специфическая векторизация...
Так какая разница? В комбинации комбинаторов более явно обозначен замысел программиста, легче интерпретировать что этот код делает.
K>>Нет, метапрограммирование в масштабах C++ и уж тем более "перегрузка операторов" на "сильные изменения языка" никак не тянет. _>Это не изменения языка, а инструменты для изменения. В основном путём построения встроенных DSL.
ОК, это инструменты, которыми "сильные изменения языка" не осуществить.
Втроенный DSL — это не изменение языка. Это "использование библиотеки". Вообще, весь смысл "встроенности" DSL в том и заключается, что язык остается тем же самым.
_>Я бы такое сказал про C... А вот у C++ имеется целый ряд оригинальных решений. Как насчёт той же move semantic? )
В C++ есть интересные решения, но к высокоуровневости и выразительности они никакого отношения не имеют.
_>Я уже не говорю про метапрограммирование на шаблонах. )
Практически все, что называют "метапрограммированием" в других языках, лучше, чем "метапрограммирование на шаблонах".
_>Хы, вот как раз в обычных реализация C++ ленивость идеально быстрая)))
Правда что-ли? А подтверждения для этого заявления какие-нибудь есть?
_>У неё другое ограничение — она скажем так работает только на подмножестве языка.
Не понятно, что это значит.
_>На самом деле после выхода C++11 практически перестал использовать. Потому как стало проще банально поставить лямбду (такая вот ленивость руками).
Это вообще не ленивость, даже если считать, что лямбда настоящая, а не плюсовая, которая лямбдой не является.
Причем "не ленивость" в данном случае означает не "испорченная" ленивость, как в случае "лямбдой не является". В данном случае это как в "ворон не конторка".
_>Эммм, запускаю компилятор этого языка и всё. И потом просто добавляю полученные объектные файлы к построению приложения на C++. А язык собственно такой: https://ispc.github.io/ispc.html#the-ispc-language.
Понятно, что вы запускаете компилятор этого языка. Вопрос был о том EDSL, который вы в этот язык транслируете.
K>>Не понятно только, какое это отношение имеет к любой из обсуждаемых нами тем. _>Это поясняет общую позицию человека. ) Ну скажем фанатик (готов всё делать на любимом языке из принципа), теоретик (превозносит некий язык из общих соображений, но никогда не делал ничего серьёзного), профи (знает и использует оптимальные инструменты на текущий момент и интересуется остальными для общего развития), неудачливый (вынужден использовать на работе ужасные инструменты и отрывается дома со всяческими игрушками), новичок и т.п.
Ну вот мы обсуждаем поддержку иммутабельности в D. Т.е. для начала мы проясняем не мою позицию. Далее, поддержка иммутабельности в D никак не зависит от того, к какому из перечисленных типажей мы с вами относимся. Такая классификация пригодится только в том случае, если кто-то захочет навешать лапши на уши, представить оппонента неадекватным, свести разговор с рельс. Вот тут подход понадобится разный для каждого типажа. Но для предметного разговора это все не нужно, нужно вам реализовать пример, который демонстрирует эту самую заявленную поддержку. Все.
Собственно, я это сделал, так что понятно, что я подразумеваю под поддержкой иммутабельности.
Что подразумеваете вы — я тоже понял: инструментарий для легковесного оборачивания мутабельных данных в "иммутабельные" интерфейсы, с возможностью извлечения из "обертки" без копирования, т.е. инвалидируя все ссылки на эту структуру данных, как на "иммутабельную". Какая-то польза в этом может и есть, но, в основном, она в том будет заключатся, что программистам жизнь медом не покажется (хотя, она наверняка уже им медом не кажется, еще до столкновения с такими чумовыми фичами).
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[128]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Т.е. вы считаете, что для реализации модели акторов необходима обязательно поддержка в синтаксисе языка? ) Очень забавная точка зрения.
В первую очередь, конечно, поддержка рантайма, вроде сегментированного стеков в куче и т.д. Но примером вы меня, как я понял, решили не удивлять.
_>А я тут даже в Прологе видел реализацию потоков в таком стиле... )))
В Прологе, это, конечно, нормально. Там все примерно одинаково недоделанное.
_>Полноценная в том смысле, что данные были реально иммутабельные.
На самом деле — нет.
K>>Это не столько оптимизация, сколько другие структуры данных, лучше подходящие для дешевого создания версий. _>Я про это и говорю.
Вы говорили "оптимизации".
_>Так последний мой пример был как раз с оптимизацией — там была реализована персистентная структура с версиями массива.
Не понимаю, на что вы рассчитываете, когда снова повторяете эту ерунду. Очень просто показать, что никакой персистентной структуры вы не реализовали, что я и сделал тут: http://rsdn.ru/forum/philosophy/5714706.1
Никакой оптимизации там тем более нет.
K>>Ну так я и сказал. В языках без какого-нибудь метапрограммирования отличие в ручном написании обертки. там где обертку можно автоматически генерировать — вообще никакой разницы не будет. _>А собственно в каких популярных языках у нас наблюдается эффективное метапрограммирование? )
А в каких популярных языках у нас наблюдается "поддержка иммутабельности" а-ля D?
Но это вообще не такая важная деталь. Вручную обертку написать можно в любом языке (хотя польза от этого всего вообще сомнительная). А вот реально полезную поддержку для иммутабельности, вроде более-менее хорошего GC, так просто в любой язык не добавишь.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[122]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>И давно nginx на erlang переписали ?
_>Nginx там только для оценочного сравнения, т.к. вообще не относится к группе исследуемых фреймворков (они же все для динамики). Т.е. фреймворка на C/C++ в данном тесте вообще не было. А первое место занял именно ерланговский фреймворк, что абсолютно не удивительно с учётом пристрастий автора теста.
Покажи ошибку в его подходе
_>В большинстве таких фреймворков сервер интегрирован во фреймворк, а не живёт где-то отдельно. )
Общие слова, ни о чем.
Re[156]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Ты можешь внятно ответить на вопрос — каким чудом один и тот же файл можно отдавать через свой сервер, но так, что бы запрос не доходил до сервера ?
_>Я тебе уже несколько раз говорил, но до тебя похоже даже прямой текст перестал доходить. Сервер отработает один раз (отдавая в CDN).
То есть, ты предлагаешь захардкодить кучу темплейтов для того, что бы отдать ровно один респонс ? Чтото я не пойму такую концепцию
_>Хотя если у нас вообще только статика на сервере, то естественно никакие фреймворки типа vibe.d вообще не нужны, т.к. привносят только ненужную сложность. Но дело именно в сложности и неудобности (в сравнение со статическим сервером), а не в меньшем быстродействие, которое мы тут обсуждали.
Не только ненужную сложность, но и потерю производительности. Пока твой код получит управление, внятный вебсервер уже успеет отдать статику.
Единственная вещь, где у тебя будет профит, это меньшие затраты дискового пространства.
Re[126]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Если с учётом библиотек, то вы очевидно не правы))) Есть множество различных техник, которые добавляются библиотеками. Это же можно целый день перечислять всякие мелочи приятные. Но для примера (просто чтобы не звучало голословно) возьмём например ту же модель акторов.
Поделись, как на этих самых библиотеках получить внятную изоляцию, что бы не дай бог не проткнуть каким нибудь левым указателем. Или бесконечную рекурсию сорганизовать. Вобщем, назови эту чудо-библиотеку, шоб без изменения языка да все фичи для акторов были реализованы.
Re[127]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Причем тут писать/читать код? Вы приводите, например, такой аргумент
Нет, дело как раз в Хаскеле. Потому как, раз он не поддерживает связь "симула-стайл", то должен предложить что-то взамен для тех же целей.
хотя на самом деле хаскель симула-стайл связь с хранением в "объекте" ссылки на словарь поддерживает с помощью тайпклассов и экзистенциальных типов.
Ну так тогда в чём проблема это продемонстрировать? )
K>Потому я и говорю, что для аргументации вам лучше переключится на язык, который вы знаете, каких-то совершенно диких представлений о хаскеле вы уже достаточно приводили, но аргументацию на фантазиях не построить.
Ещё раз повторяю: мне аргументировать на Хаскеле ничего и не надо. И соответственно я этого и не делаю. Это вам требуется продемонстрировать код на нём (плюс UML диаграммка), чтобы подтвердить свою точку зрения. А уж с прочтением его я как-нибудь постараюсь справиться. )))
K>Возможно, можно построить аргументацию за недостаточность средств UML для отображения сложных иерархий классов/инстансов, но то, что средства UML окажутся невостребованными — это полная ерунда.
Вы похоже вообще из какой-то другой реальности или просто никогда не проектировали серьёзные вещи. Да не принципиальны все эти отображения (инструментами типа автогенерации кода мало кто пользуется). Принципиальной является возможность для лёгкого построения сложной иерархической архитектуры. В первую очередь в исходниках — для этого служит грубо говоря ООП (как один из вариантов). И как вспомогательный инструмент — визуализация с помощью UML, который частично (как минимум диаграммы классов/объектов) заточен под ООП. Соответственно в случае Хаскеля (и других языков без ООП) возникает вопрос об аналогичных инструментах. Причём если говорить про код, то там ещё могут быть варианты, а вот с их визуализаций похоже всё совсем печально. И ровно 0 примеров от вас только укрепляют такое впечатление.
K>Вообще, то, что функция задана на множестве объектов какого-то типа — вполне достаточно для того, чтоб были польза и смысл обозначить связь такой функйии и такого тоипа на диаграмме. Техническая же реализация этой связи и ее "виртуальность" (не знаю точно, что вы в этом случае подразумеваете) никакого принципиального архитектурного значения не имеет.
Подразумевается рисовать типы данных значками классов и отображать в них все функции, которые принимают в качестве параметра этот тип? ) Ну даже если забыть про ситуацию с функциями многих параметров, то в обычно в ООП функции принадлежащие классу и не принадлежащие классу, видят его очень по разному... И именно в этом заключается основной смысл, а не просто в принятие скрытого параметра определённого типа.
Кстати, а для отображения связи типа вышеописанной в UML есть отдельный вид стрелочек... ) Правда они связывают не функцию (т.к. тут их не бывает по отдельности) с типами её параметров, а класс, содержащий эту функцию.
K>Тут, думаю, никаких особых пояснений не требуется, диаграммы используют для совсем не симула-стайл языков. Естественно, для применения UML для очередного языка нужно установить/согласовать некоторые смыслы и интерпретации, отличающиеся от другого языка, но никаких необходимых расширений UML вы так и не показали.
В начале надо определиться о каких конкретно диаграммах UML идёт речь. Там их большой набор и подходят они разным языкам по разному. Но здесь мы кажется говорили о диаграмме классов (как о главной структурной, позволяющей подробно задавать архитектуру приложения). Так вот, если говорить об этой диаграмме, то её применение для не ООП языков очень сомнительно. Eсли конечно не считать случая, когда мы реально задаём "ручное" ООП в программе (как иногда делают на C), но тогда это скорее означает, что мы не верно выбрали себе язык под задачу.
_>>Поэтому я и предлагаю перейти к конкретике — на ней демагогия и т.п. не работают. K>Конечно не работает, потому-то вы к конкретике и не перейдете.
Я что-то не понял, кто из нас прислал пример кода и спрашивает его аналог на Хаскеле, а получает в ответ пространные рассуждения? )
Ну на всякий случай пришлю ещё диаграммку для того примера:
По такой картинке сразу становится очевидна вся архитектура приложения.
И я по прежнему жду аналог того моего кода на Хаскеле и UML диаграмму к нему.
K>Пример все равно не рабочий, так какой смысл воспроизводить больше, чем нужно для того, чтоб понять как это воспроизвести полностью?
Что бы можно было сравнить с аналогом на C++. Пока что сравнивать нечего.
K>Чем приведенный мной код не конкретика?
Потому как он не соответствует моему коду, т.е. является каким то абстрактным примером неизвестно чего.
K>А чего вам еще не хватает?
Кода на хаскеле и диаграммы.
K>Это переписывается чисто механически. И что потом?
Потом у вас появится хоть какой-то аргумент в подтверждение ваших тезисов. Если сможете продемонстрировать требуемое. А если нет, то это будет аргументом к моим тезисам. )
K>Даже если что-то, допустим, имеет смысл — это вовсе не означает, что это сделают. Думаю, что человекогоды, вложенные в любой из популярных GUI-тулкитов, вроде QT превышают человекогоды вложенные во всю инфраструктуру хаскеля, причем в разы. Т.е. при самых оптимистичных оценках увеличения производительности программиста на хаскеле, по сравнению с программистом на языке, на котором эта самая GUI библиотека реализована — воспроизведение полноценной гуи-библиотеки на хаскеле — совершенно нереальный проект для комьюнити.
А зачем обязательно сразу Qt повторять? ) Это же собственно не просто GUI библиотека, а жирный фреймворк. Нормальные GUI библиотеки на порядки легче и пишутся очень быстро.
K>Ну тут видимо дело в специфической субкультуре программирования, потому что убогость чего-то, обычно, превращает это в фичу "только для форумов", но вот только в какой-нибудь linq to objects используется не только на форумах, хотя судя по всему, он работает даже хуже дишных рейнджей.
Да, встречается такое. Но если говорить про диапазоны D (и алгоритмы на них), то на мой взгляд это всё же не форумная игрушка, а весьма полезная вещь. Просто лично мне эта конкретная проблема так и не попалась в наших задачах на D (собственно у нас и не особо большая практика по нему), поэтому указать её решение с ходу я не могу, ну и идти ковыряться ради форумного спора тоже не собираюсь. )))
K>По автовекторизации тоже работы есть.
Любопытно) Ну т.е. автовекторизация циклов есть уже во многих компиляторах, но до настоящей (ручной) ей всегда очень далеко... Если бы кто-то сделал что-то сравнимое и при этом автоматическое, то это конечно же был бы прорыв. )
K>Практически все, что называют "метапрограммированием" в других языках, лучше, чем "метапрограммирование на шаблонах".
В соседнем сообщение это уже всплывало... Действительно существует множество языков с гораздо более мощным метапрограммированием, чем в C++. Только вот все они где-то в области маргинальных. А если мы хотим что-то из мейнстрима и при этом с МП, то... )
_>>Хы, вот как раз в обычных реализация C++ ленивость идеально быстрая))) K>Правда что-ли? А подтверждения для этого заявления какие-нибудь есть?
Так оно там такое "by design" — реализовано через МП на шаблонах и соответственно отрабатывает во время компиляции.
_>>У неё другое ограничение — она скажем так работает только на подмножестве языка. K>Не понятно, что это значит.
Это значит, что не любой код можно сделать ленивым. В смысле без доработки библиотеки под себя, а пользуясь только готовым набором из неё.
K>Это вообще не ленивость, даже если считать, что лямбда настоящая, а не плюсовая, которая лямбдой не является. K>Причем "не ленивость" в данном случае означает не "испорченная" ленивость, как в случае "лямбдой не является". В данном случае это как в "ворон не конторка".
Формально это конечно не ленивость... Но на практике, в большинстве случаев, где раньше использовалась ленивость, получилось заменить её обёртыванием нужных кусков кода в лямбды. Кода при этом чуть больше, но при этом он намного прозрачнее.
Что касается лямбд в C++... http://coliru.stacked-crooked.com/a/ce0de866fa9e05bc — с нынешними темпами развития, боюсь что это Хаскелю скоро придётся догонять. )))
K>Понятно, что вы запускаете компилятор этого языка. Вопрос был о том EDSL, который вы в этот язык транслируете.
Никаких dsl нет — просто пишется код на этом языке. И собственно зачем dsl, если этот язык приблизительнo такого же уровня как C++? )
Если уж транслировать некий edsl, то в sse интрисинки (вот они уже совсем низкоуровневые) с помощью МП. И такие решения тоже есть. Но это уже речь о совсем другой архитектуре.
K>Ну вот мы обсуждаем поддержку иммутабельности в D. Т.е. для начала мы проясняем не мою позицию. Далее, поддержка иммутабельности в D никак не зависит от того, к какому из перечисленных типажей мы с вами относимся. Такая классификация пригодится только в том случае, если кто-то захочет навешать лапши на уши, представить оппонента неадекватным, свести разговор с рельс. Вот тут подход понадобится разный для каждого типажа. Но для предметного разговора это все не нужно, нужно вам реализовать пример, который демонстрирует эту самую заявленную поддержку. Все.
Безусловно это всё не имеет отношения к нашей дискуссии, т.к. факт истинности утверждения не зависит от личности того, кто его высказывает. Однако это не мешает делать мне наблюдения за собеседниками... )
K>Собственно, я это сделал, так что понятно, что я подразумеваю под поддержкой иммутабельности. K>Что подразумеваете вы — я тоже понял: инструментарий для легковесного оборачивания мутабельных данных в "иммутабельные" интерфейсы, с возможностью извлечения из "обертки" без копирования, т.е. инвалидируя все ссылки на эту структуру данных, как на "иммутабельную". Какая-то польза в этом может и есть, но, в основном, она в том будет заключатся, что программистам жизнь медом не покажется (хотя, она наверняка уже им медом не кажется, еще до столкновения с такими чумовыми фичами).
Почти правильно. Я бы сказал, что речь идёт о самой возможности построения "иммутабельных интерфейсов", причём с гарантиями компилятора. Если язык предоставляет подобное, то всё остальное дорабатывается библиотеками очень легко. Причём можно делать как вышеописанный вариант реализации, так и множество совсем других.
Re[129]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>В первую очередь, конечно, поддержка рантайма, вроде сегментированного стеков в куче и т.д. Но примером вы меня, как я понял, решили не удивлять.
Пример в смысле библиотеки? ) Ну например вот http://www.theron-library.com есть симпатичная. Но вообще говоря для реализации модели акторов в C++ даже спец. библиотек не требуется. У нас уже есть прямо в языке std::thread, соответственно добавив к ним шаблонные функции типа send и receive и договорившись не использовать другие способы обмена данными (типа общей памяти) между потоками, мы уже получим полноценный вариант модели акторов.
K>Не понимаю, на что вы рассчитываете, когда снова повторяете эту ерунду. Очень просто показать, что никакой персистентной структуры вы не реализовали, что я и сделал тут: http://rsdn.ru/forum/philosophy/5714706.1
Дорисовать пару строчек в класс, чтобы было полноценное универсальное решение, а не для форума? ) Или вы сами в силах себе их представить? )
K>А в каких популярных языках у нас наблюдается "поддержка иммутабельности" а-ля D? K>Но это вообще не такая важная деталь. Вручную обертку написать можно в любом языке (хотя польза от этого всего вообще сомнительная). А вот реально полезную поддержку для иммутабельности, вроде более-менее хорошего GC, так просто в любой язык не добавишь.
Сомнительный аргумент. Если язык позволяет работать только с GC, то весьма вероятно у него он уже не плохой. А если не только с GC (как в D например), то можно использовать более эффективные способы (типа стека, пула и т.п.) в том числе и с иммутабельными данными.
Re[124]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Нет, вы совсем не то поняли. Речь идёт об одном нюансе, связанном именно с иммутабельностью. Дело в том, что если мы возьмём мутабельный контейнер даже в языке без всяких спец. модификаторов и т.п. на эту тему и будем использовать на нём только не меняющее его подмножество операций, то у нас на самом деле получится полноценная работа с иммутабельными данными.
Простите, но это — феерическая чушь.
Давайте проиллюстрируем это воображаемым языком, в котором вообще нет понятия типа данных. Все выражения в нём имеют один "тип" — это четыре байта.
Семантика этих четырёх байт зависит от операции, в которой они используются: если это +, то речь идёт о целочисленном сложении с дополнением до двух. Если это унарный *, то речь идёт об снятии ссылки с указателя. Если это log, то речь идёт о логарифмировании IEEE-шных single. Если toupper, то речь идёт о конкатенации zero-terminated строк. Если concat, то перед телом строки должны быть записаны их длины (в специальной кодировке: если старший бит значения по смещению -4 установлен в 1, то длина строки вычисляется как (*(str-4))&0x7FFFFFFF + (*(str-8)<<32, и так далее).
Это только типы, описанные в спецификации нашего языка. Разработчики библиотек, понятное дело, вольны использовать данные как угодно: для операции addkeyvalue() первый аргумент запросто может указывать на начало (или середину) структуры данных некоего словаря.
Важный момент вот какой: компилятор о типах не знает вообще ничего. У него очень простые правила синтакического разбора и кодогенерации.
И вот теперь я делаю утверждение, что этот язык полноценно поддерживает работу с ограниченными диапазонами целых чисел (типа 0..100).
Ведь если не выполнять над данными операций, выводящих их за пределы диапазона, то у нас на самом деле получится полноценная работа с ограниченными целыми!
Правда, все обязанности по контролю за тем, чтобы не передать в функцию число за пределами этого диапазона лежат на программисте. После каждой арифметической операции надо проверять результат вручную. Компилятор никак не намекнёт программисту, что a = a * 2 потенциально выводит число за диапазон. Более того, компилятор прекрасно позволит передать в функцию, ожидающую целое от 0 до 100, хоть флоат, хоть строку.
Лично мне такая "поддержка" не представляется "полноценной".
Точно так же и ваша "поддержка иммутабельности", построенная исключительно на самодисциплине, никак полноценной являться не может.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[125]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Простите, но это — феерическая чушь. S>Давайте проиллюстрируем это воображаемым языком, в котором вообще нет понятия типа данных. Все выражения в нём имеют один "тип" — это четыре байта. S>Семантика этих четырёх байт зависит от операции, в которой они используются: если это +, то речь идёт о целочисленном сложении с дополнением до двух. Если это унарный *, то речь идёт об снятии ссылки с указателя. Если это log, то речь идёт о логарифмировании IEEE-шных single. Если toupper, то речь идёт о конкатенации zero-terminated строк. Если concat, то перед телом строки должны быть записаны их длины (в специальной кодировке: если старший бит значения по смещению -4 установлен в 1, то длина строки вычисляется как (*(str-4))&0x7FFFFFFF + (*(str-8)<<32, и так далее). S>Это только типы, описанные в спецификации нашего языка. Разработчики библиотек, понятное дело, вольны использовать данные как угодно: для операции addkeyvalue() первый аргумент запросто может указывать на начало (или середину) структуры данных некоего словаря.
S>Важный момент вот какой: компилятор о типах не знает вообще ничего. У него очень простые правила синтакического разбора и кодогенерации.
Нет, он не не знает о них (как в динамических языках, в которых типы всё же есть), а при таком раскладе типов просто не существует. Ни в статике, ни в динамике. Т.е. это у нас тут по сути описан некий вариант ассемблера.
S>И вот теперь я делаю утверждение, что этот язык полноценно поддерживает работу с ограниченными диапазонами целых чисел (типа 0..100). S>Ведь если не выполнять над данными операций, выводящих их за пределы диапазона, то у нас на самом деле получится полноценная работа с ограниченными целыми!
Да, получится полноценная работа с ограниченными целыми. Правда это будет без всякой поддержки компилятора. Собственно это всё очевидно и можно даже легко увидеть пример такого кода, взяв пример на C++ (там будет и полноценная работа с таким типом и полный контроль компилятора корректностью) и скомпилировать его в ассемблер.
S>Правда, все обязанности по контролю за тем, чтобы не передать в функцию число за пределами этого диапазона лежат на программисте. После каждой арифметической операции надо проверять результат вручную. Компилятор никак не намекнёт программисту, что a = a * 2 потенциально выводит число за диапазон. Более того, компилятор прекрасно позволит передать в функцию, ожидающую целое от 0 до 100, хоть флоат, хоть строку.
Ну для начала никаких проверок после каждой операции не требуется. А требуется чёткое (и да, в данном случае ручное) отслеживание соответствия применяемой операции и передаваемых параметров (тип которых существует только в голове программиста). Но т.к. в данном языке подобный расклад идёт для всего, а не только для нашего специфического типа, то это как бы является нормой (для тех, кто выбирает подобные языки).
S>Лично мне такая "поддержка" не представляется "полноценной".
Поддержки тут собственно нет никакой — всё руками. Но при этом работа с этим специфическим типом является вполне полноценной. Это классический расклад для ассемблера.
Ну и лично я тоже не любитель такого программирования. Хотя изредка всё же приходится обращаться и к нему.
S>Точно так же и ваша "поддержка иммутабельности", построенная исключительно на самодисциплине, никак полноценной являться не может.
Вообще то если говорить о моих примерах поддержки иммутабельности в данной темке, то они все были реализованы на языке D, в котором как раз есть поддержка полного контроля компилятором. И соответственно никакой самодисциплины там не требуется.
Re[150]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну как бы она не решается через массив, а по сути ставится через массив.
Так бывает очень редко. Если ставить задачу "через массив", то получится, как правило, фигня.
Вот, например, если хочется сделать фильтрацию сигнала по какой-то частоте, то естественным решением кажется
1) Взять массив значений нужной нам величины в разные моменты времени
2) Преобразовать его через дискретное преобразование Фурье в массив фаз/интенсивностей по частотам
3) Свернуть этот массив с массивом 111111....10......000000, где "ненужная" нам часть спектра занулена
4) Преобразовать массив обратно через дискретное преобразование Фурье в значения-во-времени.
Если массив у нас длиной N, то этот наивный подход даст нам O(N^2). Ну, потому, что школьная формула для DFT это X[k] = sum[n=0..N-1](x[n]*exp(-2*Pi*I*n*k/N)). _>Т.е. это изначально из самой задачи (физики, математики) идёт. Соответственно, если ты захочешь применять что-то другое (я кстати пока так и не понял что), то это будет уже не естественный способ, а какая-то эмуляция.
Конечно же, никто в здравом уме не применяет "естественный способ" для вычисления ДФТ. Применяют "эмуляцию" — Fast Fourier Transform, пользуясь некоторыми свойствами комплексной экспоненты.
Таким образом, нам удастся снизить асимптоту стоимости до NlogN.
Но ведь и это — вовсе не идеальный способ. Правильное решение поставленной задачи работает за O(N). Вот только сможете ли вы его найти, если вам поставить задачу "через массив"?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[128]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ну так тогда в чём проблема это продемонстрировать? )
Так я и продемонстрировал.
_>чтобы подтвердить свою точку зрения. А уж с прочтением его я как-нибудь постараюсь справиться. )))
Я вам задаю вопросы, вы не них не отвечаете, но требуете от меня код подтверждающий мою точку зрения.
Но у меня ее по этому вопросу нет. Вы утверждаете, что для использования с ФЯ в UML 1) Нужно что-то добавить, но что — не говорите. 2) Много такого, что в ФЯ не востребовано. Тут во-первых, не понятно, что в этом является проблемой. Во-вторых, это очень сомнительное утверждение, которое вы пытались подтвердить примерами, что в хаскеле якобы нет привязки словаря методов, хотя на самом деле она есть.
Моя позиция тут заключается в том, что я не вижу, в чем проблема использовать UML с ФЯ, с учетом того, что UML используется с другими языками, в которых тот ООП, который вы классическим считаете, расширен. Собственно, других ООП языков — не расширенных — и нет. Каким образом я должен "подтверждать" свой скепсис тут?
K>>Возможно, можно построить аргументацию за недостаточность средств UML для отображения сложных иерархий классов/инстансов, но то, что средства UML окажутся невостребованными — это полная ерунда.
_>Вы похоже вообще из какой-то другой реальности или просто никогда не проектировали серьёзные вещи. Да не принципиальны все эти отображения (инструментами типа автогенерации кода мало кто пользуется).
Ни про какую автогенерацию в абзаце на который вы отвечаете нет. Откуда вы ее вдруг вытащили?
_>Принципиальной является возможность для лёгкого построения сложной иерархической архитектуры. В первую очередь в исходниках — для этого служит грубо говоря ООП (как один из вариантов). И как вспомогательный инструмент — визуализация с помощью UML, который частично (как минимум диаграммы классов/объектов) заточен под ООП.
Легким является скорее только построение легкой иерархической архитектуры. Утверждения о том, что ООП и UML подходят для описания/визуализации сложной иерархической архитектуры мне кажутся сомнительными.
Про заточенность диаграммы классов под ООП вы тоже все повторяете и повторяете, но вот только никак не можете сформулировать, в чем же эта заточенность проявляется?
_>Соответственно в случае Хаскеля (и других языков без ООП) возникает вопрос об аналогичных инструментах. Причём если говорить про код, то там ещё могут быть варианты, а вот с их визуализаций похоже всё совсем печально. И ровно 0 примеров от вас только укрепляют такое впечатление.
Про 0 примеров — это явная неправда, я в самом начале дал ссылку на UML-диаграмму для кода на хаскеле http://hackage.haskell.org/package/lens , в которой как раз симула-лайк инструментарий не используется, а то, что используется, в ООЯ отсутствует.
_>Подразумевается рисовать типы данных значками классов и отображать в них все функции, которые принимают в качестве параметра этот тип? )
В тех случаях, когда это "архитектурно" оправдано. Включение функции в "прямоугольник" типа показывает роль, которая ей архитектором отводится, а не механизм ее связи с данными.
_>Ну даже если забыть про ситуацию с функциями многих параметров
Про функции многих параметров можно смело забыть, потому что в большинстве ФЯ их нет — только функции одного параметра.
_>то в обычно в ООП функции принадлежащие классу и не принадлежащие классу, видят его очень по разному... И именно в этом заключается основной смысл, а не просто в принятие скрытого параметра определённого типа.
Да, включение функции в прямоугольник так же показывает доступ к приватным полям. Но как я уже не один раз говорил, доступ в разных языках регулируется разными способами.
_>В начале надо определиться о каких конкретно диаграммах UML идёт речь. Там их большой набор и подходят они разным языкам по разному.
Речь у нас всю дорогу шла в основном про диаграмму классов, потому как в остальных диаграммах тем более никакой языковой специфики нет.
_>Но здесь мы кажется говорили о диаграмме классов (как о главной структурной, позволяющей подробно задавать архитектуру приложения). Так вот, если говорить об этой диаграмме, то её применение для не ООП языков очень сомнительно.
Почему вы так считаете?
_>Я что-то не понял, кто из нас прислал пример кода и спрашивает его аналог на Хаскеле, а получает в ответ пространные рассуждения? )
Я вам задал конкретные вопросы, вы прислали "пример кода", причем не в качестве ответа, а вместо него. Теперь я должен переписывать его на язык, который вы все равно не читаете, а вопросы мои, видимо, так и останутся без ответа.
Меня это не устраивает, жду ответа на мои вопросы.
_>И я по прежнему жду аналог того моего кода на Хаскеле и UML диаграмму к нему.
K>>Пример все равно не рабочий, так какой смысл воспроизводить больше, чем нужно для того, чтоб понять как это воспроизвести полностью? _>Что бы можно было сравнить с аналогом на C++. Пока что сравнивать нечего.
Как нечего? Пример трансляции приведен. Если вы не можете объяснить чего вам не хватает на таком примере, то от увеличения его вам легче точно не станет.
K>>Чем приведенный мной код не конкретика? _>Потому как он не соответствует моему коду, т.е. является каким то абстрактным примером неизвестно чего.
В чем тут отличие от вашего примера?
K>>А чего вам еще не хватает? _>Кода на хаскеле и диаграммы.
Я показал, на примере одного класса трансляцию на хаскель. Чего вам не хватает помимо этого?
_>Потом у вас появится хоть какой-то аргумент в подтверждение ваших тезисов. Если сможете продемонстрировать требуемое. А если нет, то это будет аргументом к моим тезисам. )
Мои "тезисы" — это просто просьбы не обосновать даже, а хотя-бы конкретизировать ваш тезис о том, что UML для ФЯ нужно как-то дополнять. Т.е. хотя-бы показать чем дополнять и чего не хватает.
_>А зачем обязательно сразу Qt повторять? ) Это же собственно не просто GUI библиотека, а жирный фреймворк. Нормальные GUI библиотеки на порядки легче и пишутся очень быстро.
Ну да, наверное какие-нибудь GTK и WPF-ы на "порядки легче". Но на самом деле нет.
_>Да, встречается такое. Но если говорить про диапазоны D (и алгоритмы на них), то на мой взгляд это всё же не форумная игрушка, а весьма полезная вещь. Просто лично мне эта конкретная проблема так и не попалась в наших задачах на D (собственно у нас и не особо большая практика по нему), поэтому указать её решение с ходу я не могу, ну и идти ковыряться ради форумного спора тоже не собираюсь. )))
Но если вы не имеете времени что-то обосновывать, то наверное, логичным было бы и не утверждать это что-то и предлагать верить в это без всякого обоснования.
K>>По автовекторизации тоже работы есть. _>Любопытно) Ну т.е. автовекторизация циклов есть уже во многих компиляторах, но до настоящей (ручной) ей всегда очень далеко... Если бы кто-то сделал что-то сравнимое и при этом автоматическое, то это конечно же был бы прорыв. )
Речь разумеется не идет о решении всех проблем с векторизацией, а об облегчении той части, которая связана с анализом векторизуемого кода.
_>Действительно существует множество языков с гораздо более мощным метапрограммированием, чем в C++. Только вот все они где-то в области маргинальных. А если мы хотим что-то из мейнстрима и при этом с МП, то... )
Это никак не делает C++ не убогим. Это только говори о том, что в мейнстриме убогость — норма. В числе прочего — и метапрограммирование.
_>Так оно там такое "by design" — реализовано через МП на шаблонах и соответственно отрабатывает во время компиляции.
Ленивость — это оптимизация времени выполнения для нонстрикт-семантики. В компайл-тайм она, конечно, работать не может. В компайл-тайм можно только отключить ее там, где она точно не нужна (не везде, консервативно).
_>Это значит, что не любой код можно сделать ленивым. В смысле без доработки библиотеки под себя, а пользуясь только готовым набором из неё.
Код вообще нельзя "делать ленивым".
_>Формально это конечно не ленивость... Но на практике, в большинстве случаев, где раньше использовалась ленивость, получилось заменить её обёртыванием нужных кусков кода в лямбды. Кода при этом чуть больше, но при этом он намного прозрачнее.
Очевидно, что там, где ленивость можно заменить лямбдами — она не использовалась. Потому, что ленивость — это замена функции вычислителя на ее результат после первого вычисления для предотвращения повторных вычислений.
Ленивость — это такая одноразовая мутабельность, для эффективной работы с иммутабельными структурами данных и эффективной реализации нон-стрикт. Лямбды тут никак не помогут, это наивная реализация нон-стрикт.
_>Что касается лямбд в C++... http://coliru.stacked-crooked.com/a/ce0de866fa9e05bc — с нынешними темпами развития, боюсь что это Хаскелю скоро придётся догонять. )))
Ни какой язык без ГЦ по части лямбд никогда догонять не придется.
_>Никаких dsl нет — просто пишется код на этом языке. И собственно зачем dsl, если этот язык приблизительнo такого же уровня как C++? )
Затем, чтоб писать код на языке более высокого уровня, очевидно же.
_>Безусловно это всё не имеет отношения к нашей дискуссии, т.к. факт истинности утверждения не зависит от личности того, кто его высказывает. Однако это не мешает делать мне наблюдения за собеседниками... )
Наблюдения за собеседниками вы делать, конечно, можете, но на сотрудничество с моей стороны в ущерб основной теме разговора вы можете не рассчитывать.
_>Почти правильно. Я бы сказал, что речь идёт о самой возможности построения "иммутабельных интерфейсов", причём с гарантиями компилятора. Если язык предоставляет подобное, то всё остальное дорабатывается библиотеками очень легко. Причём можно делать как вышеописанный вариант реализации, так и множество совсем других.
Поскольку существует каст — никакой реальной гарантии компилятора тут нет, но лучше чем ничего, да.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[130]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Пример в смысле библиотеки?
Пример в смысле работающего кода, на котором можно производительность оценить.
_>У нас уже есть прямо в языке std::thread, соответственно добавив к ним шаблонные функции типа send и receive и договорившись не использовать другие способы обмена данными (типа общей памяти) между потоками, мы уже получим полноценный вариант модели акторов.
Спасибо, подозрения о уровне полноценности подтвердились.
_>Дорисовать пару строчек в класс, чтобы было полноценное универсальное решение, а не для форума? ) Или вы сами в силах себе их представить? )
Вы, видимо, имеете в виду копирование массива при создании версии. Ну так какое это отношение имеет к персистентным структурам данных?
_>Сомнительный аргумент. Если язык позволяет работать только с GC, то весьма вероятно у него он уже не плохой. А если не только с GC (как в D например), то можно использовать более эффективные способы (типа стека, пула и т.п.) в том числе и с иммутабельными данными.
Опять двадцать пять. 1) Для хоть сколько-нибудь нетривиальных иммутабельных структур данных вы стеком не обойдетесь. 2) С какой стати пул эффективнее ГЦ на сценариях использования иммутабельных объектов?
Вы не сможете освободить большинство пулов, в каждом останется 5% живых объектов. Эффективность, конечно, лучше некуда.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Dair, Вы писали:
D>Для меня загадка — современные алгоритмы шифрования (криптографии). Мат.аппарата не хватает
К уже сказанному выше: есть замечательная тулза Cryptool, в числе фич которой — визуализация работы тех или иных алгоритмов криптографии или криптоанализа в динамике:
Очень помогает разобраться с тем или иным алгоритмом
P.S: Если кому интересно, могу рассказать об атаках на алгоритмы криптографии и/или их реализации/способы использования
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, alex_public, Вы писали:
_>>Ну по моей ссылке только лицензия на винду стоит 25 евро/месяц. Так что будет интересно взглянуть на vps с виндой за 8 евро. ) S>За 8 долларов пойдёт? http://www.hyper-v-mart.com/hyper-v-hosting-specials-express.aspx
Так а лицензия на винду то входит в эту цену или нет? )
P.S. Цена по ссылке 10 баксов, хотя это и не принципиально тут. )))
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>Ну как бы она не решается через массив, а по сути ставится через массив. S>Так бывает очень редко. Если ставить задачу "через массив", то получится, как правило, фигня. S>Вот, например, если хочется сделать фильтрацию сигнала по какой-то частоте, то естественным решением кажется
В данной теме речь шла про числодробилки для научных задач, а не про вопросы обработки сигналов. Это абсолютно разные вещи даже по принципу применения. Но я готов поболтать и на эту темку... )
S>1) Взять массив значений нужной нам величины в разные моменты времени S>2) Преобразовать его через дискретное преобразование Фурье в массив фаз/интенсивностей по частотам S>3) Свернуть этот массив с массивом 111111....10......000000, где "ненужная" нам часть спектра занулена S>4) Преобразовать массив обратно через дискретное преобразование Фурье в значения-во-времени. S>Если массив у нас длиной N, то этот наивный подход даст нам O(N^2). Ну, потому, что школьная формула для DFT это X[k] = sum[n=0..N-1](x[n]*exp(-2*Pi*I*n*k/N)).
Вообще то даже в таком случае будет что-то вроде O(N), т.к. подобный фильтр естественно применяется не ко всему массиву (кстати, частенько "бесконечному" во времени), а к некоторому окну (размер которого зависит от требуемых частот). Просто в случае использования ДПФ будет приличное время обработки одного окна. Соответственно в случае требования реального времени (частая задача в обработке сигналов), может не получиться уложиться...
S>Конечно же, никто в здравом уме не применяет "естественный способ" для вычисления ДФТ. Применяют "эмуляцию" — Fast Fourier Transform, пользуясь некоторыми свойствами комплексной экспоненты. S>Таким образом, нам удастся снизить асимптоту стоимости до NlogN.
И БПФ точно так же работает на массиве. ) И будет отличаться от примера выше только константой.
S>Но ведь и это — вовсе не идеальный способ. Правильное решение поставленной задачи работает за O(N). Вот только сможете ли вы его найти, если вам поставить задачу "через массив"?
В случае отсутствия массива, о каком собственно N будет идти речь? )
Re[129]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Так я и продемонстрировал.
И где был какой-то вменяемый код и диаграмма к нему? )
K>Я вам задаю вопросы, вы не них не отвечаете, но требуете от меня код подтверждающий мою точку зрения. K>Но у меня ее по этому вопросу нет. Вы утверждаете, что для использования с ФЯ в UML 1) Нужно что-то добавить, но что — не говорите. 2) Много такого, что в ФЯ не востребовано. Тут во-первых, не понятно, что в этом является проблемой. Во-вторых, это очень сомнительное утверждение, которое вы пытались подтвердить примерами, что в хаскеле якобы нет привязки словаря методов, хотя на самом деле она есть.
Насколько я вижу, общетеоретические рассуждения мы оба уже повторили не один раз, знаем позиции друг друга, но это ни к чему конструктивному не привело. Поэтому я предложил перейти к примерам с конкретным кодом — там намного сложнее увильнуть от ответа. Точнее увильнуть то легко (что вы и демонстрируете последние сообщения), но во всяком случае каждому читателю станет очевиден реальный расклад по дискуссии...
K>Моя позиция тут заключается в том, что я не вижу, в чем проблема использовать UML с ФЯ, с учетом того, что UML используется с другими языками, в которых тот ООП, который вы классическим считаете, расширен. Собственно, других ООП языков — не расширенных — и нет. Каким образом я должен "подтверждать" свой скепсис тут?
Разве не очевидна разница? ) Если мы возьмём обычный популярный редактор UML и постараемся применить его к такому "расширенному" языку, то у нас возникнут только незначительные затруднения с придумыванием отображения небольшой части кода. В случае же попытки использовать такой редактор с Хаскелем, то нам собственно говоря придётся придумывать как нам отобразить хоть что-нибудь. И не уверен, что это получится без модификации редактора.
K>Легким является скорее только построение легкой иерархической архитектуры. Утверждения о том, что ООП и UML подходят для описания/визуализации сложной иерархической архитектуры мне кажутся сомнительными.
Можете назвать инструменты получше? )
K>Про заточенность диаграммы классов под ООП вы тоже все повторяете и повторяете, но вот только никак не можете сформулировать, в чем же эта заточенность проявляется?
Уже обсуждалось, не буду повторяться. Но если вы считаете, что никаких проблем у Хаскеля нет, то я по прежнему жду тот пример кода и диаграмму к нему — это будет хорошим аргументом, что никакой заточенности нет. )))
K>Про 0 примеров — это явная неправда, я в самом начале дал ссылку на UML-диаграмму для кода на хаскеле http://hackage.haskell.org/package/lens , в которой как раз симула-лайк инструментарий не используется, а то, что используется, в ООЯ отсутствует.
Речь шла про ваши примеры, а не сторонние. Но тот кстати тоже весьма показателен. )))
_>>Подразумевается рисовать типы данных значками классов и отображать в них все функции, которые принимают в качестве параметра этот тип? ) K>В тех случаях, когда это "архитектурно" оправдано. Включение функции в "прямоугольник" типа показывает роль, которая ей архитектором отводится, а не механизм ее связи с данными.
Тогда сложится интересная ситуация... В диаграммке задумка архитектора будет видна, а вот в коде ничего подобного не будет... )
Это ещё раз подчеркнёт несовместимость UML и Хаскеля. Причём из этого примера виден характер несовместимости: UML нормально задаёт такие архитектурные вещи, а Хаскель нет.
_>>то в обычно в ООП функции принадлежащие классу и не принадлежащие классу, видят его очень по разному... И именно в этом заключается основной смысл, а не просто в принятие скрытого параметра определённого типа. K>Да, включение функции в прямоугольник так же показывает доступ к приватным полям. Но как я уже не один раз говорил, доступ в разных языках регулируется разными способами.
Безусловно он регулируется по разному в разных языках. Но как это делается в Хаскеле мы уже обсудили — на уровне модулей. Сомнительное решение, ну да ладно, предположим для простоты что оно вообще идеальное (это вообще другая тема, которую мы уже затрагивали). Но отображение этого в UML уже явно не тривиально. А если это ещё и попытаться как-то совместить с главной целью (см. выше), то вообще не особо представляю себе результат.
K>...
Здесь пропустил кучу отмазок от предложения продемонстрировать тот тривиальный код и диаграммку к нему. Вообще говоря я не вижу смысла в дальнейшем продолжение дискуссии на тему UML в таком стиле (я прошу показать пример, а в ответ получаю некие пространные рассуждения и отмазки).
_>>А зачем обязательно сразу Qt повторять? ) Это же собственно не просто GUI библиотека, а жирный фреймворк. Нормальные GUI библиотеки на порядки легче и пишутся очень быстро. K>Ну да, наверное какие-нибудь GTK и WPF-ы на "порядки легче". Но на самом деле нет.
Это тоже довольно жирные. Речь скорее про какой-нибудь FLTK и т.п. ) Только в распиаренном функциональном стиле...
_>>Действительно существует множество языков с гораздо более мощным метапрограммированием, чем в C++. Только вот все они где-то в области маргинальных. А если мы хотим что-то из мейнстрима и при этом с МП, то... )
K>Это никак не делает C++ не убогим. Это только говори о том, что в мейнстриме убогость — норма. В числе прочего — и метапрограммирование.
Нууууу это двойственный вопрос. Потому как если мы скажем возьмём в учёт инструменты для языков, то убогость будет как раз у всех не мейнстрим языков.
Кстати, вот интересный вопрос у меня появился, хотя и не совсем по теме. А существует ли на ваш взгляд какой-то не убогий системный (т.е. позиционируемый на замену C/C++ — такие же задачи всё равно надо решать и сейчас) язык программирования? Пускай даже и совсем совсем не мейнстримный и с убогой инфраструктурой.
K>Ленивость — это оптимизация времени выполнения для нонстрикт-семантики. В компайл-тайм она, конечно, работать не может. В компайл-тайм можно только отключить ее там, где она точно не нужна (не везде, консервативно).
Ааа ну если вы под ленивостью подразумеваете именно аспект с кэшированием предыдущих вызовов, то это вообще по другому реализуется в языках типа C++ и не требует каких-то сложностей. Я же говорил немного о другом аспекте ленивости — очерёдности исполнения (первого вызова относительно другого кода). Это имеет немного другое применение и реализуется чаще через МП. Ну точнее так было до появления лямбд.
K>Очевидно, что там, где ленивость можно заменить лямбдами — она не использовалась. Потому, что ленивость — это замена функции вычислителя на ее результат после первого вычисления для предотвращения повторных вычислений.
Не только (см. выше).
K>Ленивость — это такая одноразовая мутабельность, для эффективной работы с иммутабельными структурами данных и эффективной реализации нон-стрикт. Лямбды тут никак не помогут, это наивная реализация нон-стрикт.
Эффективность может быть не только в кэширование, но и в вычисление данных только по требованию (т.е. один раз или вообще ни разу).
_>>Что касается лямбд в C++... http://coliru.stacked-crooked.com/a/ce0de866fa9e05bc — с нынешними темпами развития, боюсь что это Хаскелю скоро придётся догонять. ))) K>Ни какой язык без ГЦ по части лямбд никогда догонять не придется.
Ну ну))) Пример то глянули? ) Кстати, как у Хаскеля обстоят дела с функциями произвольного числа аргументов? ) И как это сочетается с лямбдами? )
_>>Никаких dsl нет — просто пишется код на этом языке. И собственно зачем dsl, если этот язык приблизительнo такого же уровня как C++? ) K>Затем, чтоб писать код на языке более высокого уровня, очевидно же.
В данном случае уровень языка отлично сочетается с задачей. ) Да, и вы так и не пояснили как мне применить конвейеры тут...
Re[131]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Пример в смысле работающего кода, на котором можно производительность оценить.
Ааа, ну это сколько угодно. Причём например тут можно глянуть уже и на готовые результаты тестов. Ну а исходники там имеются по ссылкам в самом начале.
_>>У нас уже есть прямо в языке std::thread, соответственно добавив к ним шаблонные функции типа send и receive и договорившись не использовать другие способы обмена данными (типа общей памяти) между потоками, мы уже получим полноценный вариант модели акторов. K>Спасибо, подозрения о уровне полноценности подтвердились.
И что по вашему ещё должно обязательно входить в реализацию модели акторов? )
_>>Дорисовать пару строчек в класс, чтобы было полноценное универсальное решение, а не для форума? ) Или вы сами в силах себе их представить? ) K>Вы, видимо, имеете в виду копирование массива при создании версии. Ну так какое это отношение имеет к персистентным структурам данных?
Копирование только в случае если это не последняя версия. А при расширение от последней (собственно только этот случай и происходил в той нашей задачке) никакого копирования.
K>Опять двадцать пять.
Да да, мы это уже обсуждали и вы приводили в точности такие же аргументы. Правда я не пойму как вы их повторяете сейчас, после того, как я продемонстрировал как раз пример основанный на стеке и пуле.
K>1) Для хоть сколько-нибудь нетривиальных иммутабельных структур данных вы стеком не обойдетесь.
Смотря что называть стеком. Скажем vector<Struct> лежащий в стеке (но при этом сами данные естественно где-то в динамической памяти) — это у нас как считается? )
K>2) С какой стати пул эффективнее ГЦ на сценариях использования иммутабельных объектов? Вы не сможете освободить большинство пулов, в каждом останется 5% живых объектов. Эффективность, конечно, лучше некуда.
Мы используем пул не в качестве сборщика мусара (некой универсальной штуки, работающей со всей памятью в программе), а используя знания о конкретной задаче. Т.е. используется точное "внешнее" знание о времени жизни объектов, а не отслеживание их системой. Собственно пример выше уже был, но т.к. там пул был всего один, это не было особо очевидно. Ну могу привести ещё простейший пример... Вот допустим у нас программа работает с некоторыми документами. Мы можем заводить по пулу на каждый документ, размещать в нём всё связанное с документом и соответственно убивать его при закрытие. Понятна идея? )
Но вообще говоря это всё требуется только для очень специфических задач (которые однако частенько приводят любители Java и т.п. при сравнение быстродействия с C++). А для подавляющего большинства обычный RAI в C++ является эффективнее любых сборщиков мусора.
Re[152]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Так а лицензия на винду то входит в эту цену или нет? )
Конечно. Windows Server 2012 R2/2008 R2 _>P.S. Цена по ссылке 10 баксов, хотя это и не принципиально тут. )))
Cheap Windows VPS Hosting / Hyper-V Hosting — $7.99/m
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Вообще то даже в таком случае будет что-то вроде O(N), т.к. подобный фильтр естественно применяется не ко всему массиву (кстати, частенько "бесконечному" во времени), а к некоторому окну (размер которого зависит от требуемых частот). Просто в случае использования ДПФ будет приличное время обработки одного окна. Соответственно в случае требования реального времени (частая задача в обработке сигналов), может не получиться уложиться...
Ну вы если передёргиваете, то делайте это последовательно. Если вы зафиксировали N, то, естественно, никакой асимптотики по нему не будет. Но откуда тогда O(N)? Будет тупо O(1). И c БПФ будет О(1). Но это жульничество вам ничем не поможет — потому что тем асимптотика и отличается, что при увеличении размера окна "наивная" программа быстро вылетит за пределы применимости. _>В случае отсутствия массива, о каком собственно N будет идти речь? )
Я говорю не про отсутствие массива, а о способе постановке задачи.
Вот у нас по прежнему есть массив в N отсчётов. Нужно вырезать из данных колебания с частотой выше некоторой f0.
Если вы будете настаивать на постановке в стиле "преобразовать массив" и "умножить массив на массив", то получите на выходе фигню, а не решение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[153]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>Так а лицензия на винду то входит в эту цену или нет? ) S>Конечно. Windows Server 2012 R2/2008 R2
Хех, интересно с чего это они такие щедрые... В обычных местах за неё платят приличные деньги. )
_>>P.S. Цена по ссылке 10 баксов, хотя это и не принципиально тут. ))) S>
S>Cheap Windows VPS Hosting / Hyper-V Hosting — $7.99/m
Это скидка при оплате сразу целого года вперёд — тогда и у хостинга из моего примера надо было аналогичную цену смотреть. )
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>Ну вы если передёргиваете, то делайте это последовательно. Если вы зафиксировали N, то, естественно, никакой асимптотики по нему не будет. Но откуда тогда O(N)? Будет тупо O(1). И c БПФ будет О(1). Но это жульничество вам ничем не поможет — потому что тем асимптотика и отличается, что при увеличении размера окна "наивная" программа быстро вылетит за пределы применимости.
N (размер данных для обработки) мы не фиксируем. Фиксируется (на основание данных о необходимых частотах) размер окна W. Далее, наши данные делятся на окна, каждое из которых обрабатывается с помощью ДПФ или БПФ или ещё чем-то. От выбора алгоритма соответственно зависит время обработки окна T(W). А общее время обработки нашего набора данных будет равно N*T(W)/W, т.е. O(N). Кстати, если взять например для ДПФ значение T(W) в виде C*W^2, то можно увидеть упрощённое значение для всего набора данных в виде N*W*C, которое интуитивно очевидно.
S>Я говорю не про отсутствие массива, а о способе постановке задачи. S>Вот у нас по прежнему есть массив в N отсчётов. Нужно вырезать из данных колебания с частотой выше некоторой f0. S>Если вы будете настаивать на постановке в стиле "преобразовать массив" и "умножить массив на массив", то получите на выходе фигню, а не решение.
Ну т.е. в виде исходных данных у нас всё же массив? ))) А к чему тогда было вообще заводить этот разговор? )
Re[154]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>>>P.S. Цена по ссылке 10 баксов, хотя это и не принципиально тут. ))) S>>
S>>Cheap Windows VPS Hosting / Hyper-V Hosting — $7.99/m
_>Это скидка при оплате сразу целого года вперёд — тогда и у хостинга из моего примера надо было аналогичную цену смотреть. )
Смотрите. Даже если вы будете настаивать на помесячной оплате (потому что у вашего хостинга другой нету), то $10 всё равно меньше E8, и характеристики машинки там значительно лучше.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>N (размер данных для обработки) мы не фиксируем. Фиксируется (на основание данных о необходимых частотах) размер окна W.
Частота среза — это параметр задачи, меняется от запуска к запуску. Давайте, расскажите мне о выборе окна на основе частоты среза.
_> Далее, наши данные делятся на окна, каждое из которых обрабатывается с помощью ДПФ или БПФ или ещё чем-то. От выбора алгоритма соответственно зависит время обработки окна T(W). А общее время обработки нашего набора данных будет равно N*T(W)/W, т.е. O(N). Кстати, если взять например для ДПФ значение T(W) в виде C*W^2, то можно увидеть упрощённое значение для всего набора данных в виде N*W*C, которое интуитивно очевидно.
Это вы сейчас всё ещё о постановке задачи, или уже о вашем решении?
Если о постановке — то она как бы ущербна в самом начале, т.к. вы добавляете в неё отсутствующие в формулировке задачи подробности.
S>>Я говорю не про отсутствие массива, а о способе постановке задачи. S>>Вот у нас по прежнему есть массив в N отсчётов. Нужно вырезать из данных колебания с частотой выше некоторой f0. S>>Если вы будете настаивать на постановке в стиле "преобразовать массив" и "умножить массив на массив", то получите на выходе фигню, а не решение.
_>Ну т.е. в виде исходных данных у нас всё же массив? ))) А к чему тогда было вообще заводить этот разговор? )
К тому, что вы всё время съезжаете на "постановку" задачи, в которой почему-то сразу указано решение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[51]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
_>>N (размер данных для обработки) мы не фиксируем. Фиксируется (на основание данных о необходимых частотах) размер окна W. S>Частота среза — это параметр задачи, меняется от запуска к запуску. Давайте, расскажите мне о выборе окна на основе частоты среза.
Выбор окна происходит не по параметрам фильтра, а по параметрам входного сигнала. К примеру если речь идёт о звуковом сигнале, то мы сразу вспоминаем, что человек слышит его только в пределах 16-22000 Гц, и это тут же однозначно даёт нам предельные параметры как для частоты дискретизации, так и для размера окна преобразования Фурье. Естественно можно задрать эти параметры и выше, но это будет бессмысленной тратой ресурсов. А вот скажем если мы работает с речью, то диапазон становится вообще всего 300-4000 Гц и работать ещё намного проще (успевать в реальном времени).
S>Это вы сейчас всё ещё о постановке задачи, или уже о вашем решении? S>Если о постановке — то она как бы ущербна в самом начале, т.к. вы добавляете в неё отсутствующие в формулировке задачи подробности.
Это было пояснение почему на практике и ДПФ и БПФ являются О(N) по входному сигналу. Другое дело, что в технике обработки сигналов важен как раз коэффициент при N, т.к. частенько подобная обработка идёт в реальном времени (а N соответственно является вообще "бесконечным"). В этом кстати большое отличие от классических научных числодробилок, где никаких ограничений по времени нет, но зато имеются гигабайты модельных данных (значения величин на решётках и т.п.). И кстати говоря в данной темке именно о распараллеливание таких вещей шла речь.
_>>Ну т.е. в виде исходных данных у нас всё же массив? ))) А к чему тогда было вообще заводить этот разговор? ) S>К тому, что вы всё время съезжаете на "постановку" задачи, в которой почему-то сразу указано решение.
Я так и не понял пока к чему вы влезли в тему про распараллеливание числодробилок с этим своим примером. Вы хотели как-то опровергнуть мой тезис о том, что эти задачи покрывает сочетание mpi+openmp или собственно что? )
Re[130]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>И где был какой-то вменяемый код и диаграмма к нему? )
Я переписал один класс на хаскель. Что изменится если переписать три? Диаграмма будет отличаться заменой наследования на имплементацию.
Вот полное переписывание, один-в-один:
data MyView = MyView {
drawView :: UI () -- рисуем что-то в окне
}
instance View MyView where onDraw = drawView
data MyWindow = MyWindow {
menu :: Menubar,
tools :: Toolbar,
view :: MyView,
status :: Statusbar,
onViewClear :: UI () -- реакция на меню/тулбар/хоткей
}
instance Window MyWindow
myWindow :: MyWindow -- установка элементов по местам и настройка реакций на событияdata MyApp = MyApp {
window :: MyWindow
withMyApp :: (MyApp -> UI r) -> UI r -- Инициализация/деинициализация каких-нибудь библиотек
}
instance App MyApp
main = runUI $ withMyApp mainLoop
хотя на хаскеле это скорее иначе напишут.
_>Насколько я вижу, общетеоретические рассуждения мы оба уже повторили не один раз,
Просто ваши рассуждения слишком уж общие: "какие-то проблемы есть, но я их не укажу", "чего-то не хватает, но чего именно — не скажу" и т.д.
_>знаем позиции друг друга, но это ни к чему конструктивному не привело.
Нет, содержательную часть вашей позиции я не знаю. Вы ее не озвучили.
_>Поэтому я предложил перейти к примерам с конкретным кодом
Поправка: вы предложили мне перейти к примерам с конкретным кодом. Сами же ни разбора проблем со "страшними монадами" на конкретном коде, ни реализации для моей задачки про поддержку иммутабельности так и не привели.
_>там намного сложнее увильнуть от ответа. Точнее увильнуть то легко (что вы и демонстрируете последние сообщения), но во всяком случае каждому читателю станет очевиден реальный расклад по дискуссии...
Совсем не сложно. Вы вот релевантные примеры тут не пишете, просто публикуете что-нибудь к делу не относящееся и делаете вид, что так и надо. И все нормально, даже и в то время, когда эту ветку кто-то читал.
_>Разве не очевидна разница? ) Если мы возьмём обычный популярный редактор UML и постараемся применить его к такому "расширенному" языку, то у нас возникнут только незначительные затруднения с придумыванием отображения небольшой части кода. В случае же попытки использовать такой редактор с Хаскелем, то нам собственно говоря придётся придумывать как нам отобразить хоть что-нибудь.
Непонятно, откуда вы выводите незначительные затруднения с одной стороны и значительные с другой.
Вы эту свою мысль как-то развить можете?
K>>Легким является скорее только построение легкой иерархической архитектуры. Утверждения о том, что ООП и UML подходят для описания/визуализации сложной иерархической архитектуры мне кажутся сомнительными. _>Можете назвать инструменты получше?
Могу, конечно. Это ФП.
_>Уже обсуждалось, не буду повторяться. Но если вы считаете, что никаких проблем у Хаскеля нет, то я по прежнему жду тот пример кода и диаграмму к нему —
Я вполне допускаю что проблемы есть, у меня на этот счет есть кое-какие идеи. Но мне как-то неинтересно дискутировать самому с собой, мне интересно узнать от вас, что вы считаете проблемами.
_>это будет хорошим аргументом, что никакой заточенности нет. )))
Никакого аргумента из этого не получится потому, что непонятно против чего или за что аргументировать: вы не хотите сформулировать в чем выражается заточенность. Я правда понимаю, что так и задумано изначально.
K>>Про 0 примеров — это явная неправда, я в самом начале дал ссылку на UML-диаграмму для кода на хаскеле http://hackage.haskell.org/package/lens , в которой как раз симула-лайк инструментарий не используется, а то, что используется, в ООЯ отсутствует.
_>Речь шла про ваши примеры, а не сторонние. Но тот кстати тоже весьма показателен. )))
Вы эту показательность можете как-нибудь раскрыть?
_>Тогда сложится интересная ситуация... В диаграммке задумка архитектора будет видна, а вот в коде ничего подобного не будет... ) _>Это ещё раз подчеркнёт несовместимость UML и Хаскеля. Причём из этого примера виден характер несовместимости: UML нормально задаёт такие архитектурные вещи, а Хаскель нет.
Почему? Где в хаскеле непонятна связь функции с типом, на котором она определена? Лично мне даже понятнее, с чем работает хаскельная функция, чем функция в каком-нибудь ООЯ.
_>>>то в обычно в ООП функции принадлежащие классу и не принадлежащие классу, видят его очень по разному... И именно в этом заключается основной смысл, а не просто в принятие скрытого параметра определённого типа. K>>Да, включение функции в прямоугольник так же показывает доступ к приватным полям. Но как я уже не один раз говорил, доступ в разных языках регулируется разными способами.
_>Безусловно он регулируется по разному в разных языках. Но как это делается в Хаскеле мы уже обсудили — на уровне модулей. Сомнительное решение, ну да ладно, предположим для простоты что оно вообще идеальное (это вообще другая тема, которую мы уже затрагивали). Но отображение этого в UML уже явно не тривиально. А если это ещё и попытаться как-то совместить с главной целью (см. выше), то вообще не особо представляю себе результат.
K>>...
_>Здесь пропустил кучу отмазок от предложения продемонстрировать тот тривиальный код и диаграммку к нему. Вообще говоря я не вижу смысла в дальнейшем продолжение дискуссии на тему UML в таком стиле (я прошу показать пример, а в ответ получаю некие пространные рассуждения и отмазки).
Очень смешно звучит от человека, который уже полгода придумывает как бы ему не писать пример на D с иммутабельными структурами данных, потому что понимает, что он будет страшно выглядеть и адски тормозить.
_>Это тоже довольно жирные. Речь скорее про какой-нибудь FLTK и т.п. )
Возможно какие-то такие поделки и существуют, не интересовался таким вопросом, так что ничего про них сказать не могу.
Общий подход к такой проблеме для хаскеля такой: EDSL для построения / интерпретации дерева. Deep или shallow embedding, интерпретация дерева — сворачиванием моноидами какими-нибудь.
_>Только в распиаренном функциональном стиле...
Не сказал бы, что функциональный стиль "распиарен". В лучшем случае кое-кому известен в узких кругах.
_>Нууууу это двойственный вопрос. Потому как если мы скажем возьмём в учёт инструменты для языков, то убогость будет как раз у всех не мейнстрим языков.
Да, конечно, ну так это одна из причин того, что убогие языки так широко используются. Но продвинутость инструментов не делает убогий язык не убогим, также как их убогость не делает язык убогим. На общую, интегральную оценку всего комплекса, конечно влияет, часто решающим образом.
_>Кстати, вот интересный вопрос у меня появился, хотя и не совсем по теме. А существует ли на ваш взгляд какой-то не убогий системный (т.е. позиционируемый на замену C/C++ — такие же задачи всё равно надо решать и сейчас) язык программирования? Пускай даже и совсем совсем не мейнстримный и с убогой инфраструктурой.
Нет конечно, не существует и не может существовать. Потому, что неубогость требует жертв, которые в этой области применения позволить себе нельзя. (Т.е. можно, конечно, сделать язык несколько менее убогий чем C++, но не принципиально, так что перламутровые пуговицы не перевесят труда, который уже вложен в C++). Единственный способ каким можно решить проблему убогости в этой области, это разве что генерация C из EDSL в высокоуровневых языках. В этом направлении кое-какие работы ведутся.
_>Ааа ну если вы под ленивостью подразумеваете именно аспект с кэшированием предыдущих вызовов, то это вообще по другому реализуется в языках типа C++ и не требует каких-то сложностей. Я же говорил немного о другом аспекте ленивости — очерёдности исполнения (первого вызова относительно другого кода). Это имеет немного другое применение и реализуется чаще через МП. Ну точнее так было до появления лямбд.
То, о чем вы говорите называется "нормальный порядок вычислений". Ленивость — одна из оптимизаций, которая делает реализацию такого порядка вычислений практичной, решает проблему с перевычислениями одного и того же.
_>Ну ну))) Пример то глянули? )
Да, не понял, что там выдающегося по части лямбд. Там вроде обобщенная работа с кортежами демонстрируется.
_>Кстати, как у Хаскеля обстоят дела с функциями произвольного числа аргументов? ) И как это сочетается с лямбдами? )
Никак, таких функций в хаскеле нет, аргумент у всех только один.
Можно ли на хаскеле написать конкатенацию кортежей и вообще обобщенно работать с суммами? Да, но это, конечно, не тот код, который на хаскеле легко/приятно писать.
_>В данном случае уровень языка отлично сочетается с задачей. )
Да ну?
_>Да, и вы так и не пояснили как мне применить конвейеры тут...
Чего тут объяснять? Вместо фортранолапши с циклами — комбинаторы комбинируете.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[132]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ааа, ну это сколько угодно. Причём например тут можно глянуть уже и на готовые результаты тестов. Ну а исходники там имеются по ссылкам в самом начале.
Пример работающего кода, запощенный сюда, с микробенчмарком и всей информацией необходимой для воспроизведения результата.
_>И что по вашему ещё должно обязательно входить в реализацию модели акторов? )
Что бы там по-моему не должно было быть, все вами будет, конечно, отметено как ненужное.
_>>>Дорисовать пару строчек в класс, чтобы было полноценное универсальное решение, а не для форума? ) Или вы сами в силах себе их представить? ) K>>Вы, видимо, имеете в виду копирование массива при создании версии. Ну так какое это отношение имеет к персистентным структурам данных?
_>Копирование только в случае если это не последняя версия.
Ну так иммутабельной (персистентной) структурой данных называется такая, которая в этом случае полного копирования не требует. Такая, как вы описываете — это мутабельная (эфемерная).
_>А при расширение от последней (собственно только этот случай и происходил в той нашей задачке) никакого копирования.
А если еще и не расширять — вообще ничего делать не нужно. Вот это да! Пока структуру данных не трогаешь — любая по-вашему иммутабельная, даже та, что еще не написана.
_>Да да, мы это уже обсуждали и вы приводили в точности такие же аргументы. Правда я не пойму как вы их повторяете сейчас, после того, как я продемонстрировал как раз пример основанный на стеке и пуле.
Спор в интернете не такая простая вещь как вы думаете. К примеру, если вы приводите неработающий пример — я вовсе не обязан считать его неопровержимым аргументом, как вы от меня сейчас ожидаете.
K>>1) Для хоть сколько-нибудь нетривиальных иммутабельных структур данных вы стеком не обойдетесь. _>Смотря что называть стеком. Скажем vector<Struct> лежащий в стеке (но при этом сами данные естественно где-то в динамической памяти) — это у нас как считается? )
"вы стеком не обойдетесь" в данном случае означает, что для управления памятью стека не достаточно.
K>>2) С какой стати пул эффективнее ГЦ на сценариях использования иммутабельных объектов? Вы не сможете освободить большинство пулов, в каждом останется 5% живых объектов. Эффективность, конечно, лучше некуда. _>Мы используем пул не в качестве сборщика мусара (некой универсальной штуки, работающей со всей памятью в программе), а используя знания о конкретной задаче. Т.е. используется точное "внешнее" знание о времени жизни объектов, а не отслеживание их системой.
Так в этом и проблема. В общем случае, в высокоуровневом коде знания о времени жизни нет.
_>Собственно пример выше уже был, но т.к. там пул был всего один, это не было особо очевидно. Ну могу привести ещё простейший пример... Вот допустим у нас программа работает с некоторыми документами. Мы можем заводить по пулу на каждый документ, размещать в нём всё связанное с документом и соответственно убивать его при закрытие. Понятна идея? )
А если 90% данных между документами разделяются? Вот иммутабельная структура данных — это набор таких документов. Понятна идея?
_>Но вообще говоря это всё требуется только для очень специфических задач (которые однако частенько приводят любители Java и т.п. при сравнение быстродействия с C++). А для подавляющего большинства обычный RAI в C++ является эффективнее любых сборщиков мусора.
Это естественно, потому что то, что могут позволить себе программисты на более-менее высокоуровневом языке — программисты на низкоуровневом позволить себе не могут. Разумеется, все что позволить себе нельзя объявляется ненужным и вообще "специфическим" — сегодня в колбасе потребности нет. Программисты на Java могут позволить себе работу с иммутабельными структурами, программисты на D — не могут. Ну и под "поддержкой иммутабельности" вы всю дорогу понимаете осознанную необходимость иммутабельность не использовать.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[131]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Я переписал один класс на хаскель. Что изменится если переписать три? Диаграмма будет отличаться заменой наследования на имплементацию. K>Вот полное переписывание, один-в-один: K>...
Эмм, имплементация? А что тогда будет в случае, если мы продолжим эту диаграммку выше (к примеру понятно, что View, Menubar, Toolbar и т.п. наследованы от одного общего класса, тоже библиотечного)? T.e. имплементация подходит для случая интерфейс->реализаций, но это ровно один уровень иерархии, а в любой GUI библиотеке их намного больше.
Да, и кстати, я в очередной раз не понял кого же вы хотите уже здесь назначить единицей инкапсуляции (обозначать прямоугольником на диаграмме классов). У нас были версии и про типы и про модули (хотя это мне казалось сомнительным)... Здесь же вы предлагает считать ими классы типов? Или же их экземпляры? Или что?)
K>хотя на хаскеле это скорее иначе напишут.
С удовольствием познакомлюсь как пишут подобное в Хаскеле. Я серьёзно. ) Потому как пока-что я видел на Хаскеле только использование чужих GUI библиотек с соответствующей (и давно привычной мне) архитектурой.
K>Нет, содержательную часть вашей позиции я не знаю. Вы ее не озвучили.
Основной мой тезис в этой части нашей дискуссии был такой: UML (как пример одного из важных промышленных инструментов) не адаптирован к ФП вообще и к Хаскелю в особенности (т.к. там не только ФП, но и ещё ленивость). Причём похоже никто и не шевелится что-то исправлять в данном направление. И понятно почему: хотя ФП методы активно проникают в промышленное программирование, но к построению общей архитектуры приложения (каркаса так сказать) это отношения не имеет — там царит ООП.
K>Поправка: вы предложили мне перейти к примерам с конкретным кодом. Сами же ни разбора проблем со "страшними монадами" на конкретном коде, ни реализации для моей задачки про поддержку иммутабельности так и не привели.
А чем не понравилась та последняя реализация на D? ) Там же даже цикла нет — рекурсией заменил. )))
Да, кстати, самое забавное, что решение со 100% настоящей имммутабельностью было у меня давным давно — я его первым опубликовал. И оно работало действительно очень долго (за счёт постоянного копирования всего массива). И великолепно ускорялось переходом к мутабельному коду (заменой соответствующего оператора). Я бы на вашем месте сразу же уцепился за него в качестве доказательства отсутствия оптимизации под иммутабельность и собственно говоря никто бы и не смог возразить. Но вы почему-то не увидели, что там всё по честному, и захотели чтобы для иммутабельных данных применялась специальная структура (а не стандартный массив с модификатором immutable). Ну захотели — получите. Только уже с добавленной оптимизацией и соответственно заметно быстрее версии на Хаскеле. )))
_>>Разве не очевидна разница? ) Если мы возьмём обычный популярный редактор UML и постараемся применить его к такому "расширенному" языку, то у нас возникнут только незначительные затруднения с придумыванием отображения небольшой части кода. В случае же попытки использовать такой редактор с Хаскелем, то нам собственно говоря придётся придумывать как нам отобразить хоть что-нибудь. K>Непонятно, откуда вы выводите незначительные затруднения с одной стороны и значительные с другой. K>Вы эту свою мысль как-то развить можете?
Эмм, разве не очевидно? Обычный UML редактор очевидно не умеет никаких методов выходящих за стандарт. Соответственно если мы будем с помощью него рисовать диаграммку для "расширенного ООП языка", то нам надо будет как-то придумать отображение для эти расширений. Но только для них (сколько то там процентов кода), а основная часть прорисуется вполне канонически. Собственно говоря частенько (когда на расширения приходятся всякие мелкие сервисные вещи, типа переопределения операторов для удобства и т.п.) мы можем вообще полностью описать архитектуру приложения даже и без придумывания нестандартных отображений — просто их не будет на диаграммке и всё (мы же не собираемся генерировать по ней код). В случае же Хаскеля грубо говоря вся программка целиком состоит только из таких "расширений", так что путь только один — придумывать и ещё раз придумывать. Причём даже если и сможем что-то сваять для себя, то другому программисту на Хаскеле такую диаграммку так просто и не покажешь — он же не знает "нотацию". Или что ещё хуже, у него уже есть своя, другая. )))
_>>Можете назвать инструменты получше? K>Могу, конечно. Это ФП.
О, раз вы так считаете, то может тогда подскажите какие-то ссылки на соответствующие статьи (не буду наглеть с просьбами о личном пересказе)? А то по проектированию с помощью ООП целые толстые тома есть с кучей всяких известных (которые уже даже в вики найти можно) принципов и т.п. А чего-то подобного на тему ФП я что-то не видел.
K>Возможно какие-то такие поделки и существуют, не интересовался таким вопросом, так что ничего про них сказать не могу. K>Общий подход к такой проблеме для хаскеля такой: EDSL для построения / интерпретации дерева. Deep или shallow embedding, интерпретация дерева — сворачиванием моноидами какими-нибудь.
EDSL? В Хаскеле появилось нормальное метапрограммирование?
_>>Только в распиаренном функциональном стиле... K>Не сказал бы, что функциональный стиль "распиарен". В лучшем случае кое-кому известен в узких кругах.
Имелась в виду наша дискуссия. ))) Ну а так на самом деле отдельные методы ФП сейчас весьма активно проникают в промышленное программирование. Но именно как отдельные техники, применяемые императивными языками внутри ООП каркасов. )))
_>>Кстати, вот интересный вопрос у меня появился, хотя и не совсем по теме. А существует ли на ваш взгляд какой-то не убогий системный (т.е. позиционируемый на замену C/C++ — такие же задачи всё равно надо решать и сейчас) язык программирования? Пускай даже и совсем совсем не мейнстримный и с убогой инфраструктурой.
K>Нет конечно, не существует и не может существовать. Потому, что неубогость требует жертв, которые в этой области применения позволить себе нельзя. (Т.е. можно, конечно, сделать язык несколько менее убогий чем C++, но не принципиально, так что перламутровые пуговицы не перевесят труда, который уже вложен в C++). Единственный способ каким можно решить проблему убогости в этой области, это разве что генерация C из EDSL в высокоуровневых языках. В этом направлении кое-какие работы ведутся.
Т.е. по сути вы согласны что C++ — это сейчас оптимальный выбор для определённого класса задач? Тогда наши споры приобретают несколько другой характер: обсуждения собственно границ применимости. )))
Кстати, а для не требующих мощности (низкоуровневой) C++ проектов (и если они не особо крупные) мне в последнее время нравится применять вообще Питон. Очень быстро получается результат.
А вот для Хаскеля я что-то не вижу такой однозначной ниши.
K>Да, не понял, что там выдающегося по части лямбд. Там вроде обобщенная работа с кортежами демонстрируется.
Ну демонстрировалась там собственно новинка C++ — те самые полиморфные лямбды. В общем то ничего особенного, просто лямбдам разрешили поведение как и у обычных шаблонных функций (которые могут иметь произвольное число параметров произвольных типов). Однако такой простой и очевидный шаг дал много интересных техник (через возврат замыкания и т.п.), которые частично и демонстрировались в этом коде на примере реализации классических приёмов ФП.
Да, а обобщённая работа с кортежами нормально работала и в старом стандарте, без всего этого. Просто на базе МП через шаблоны (подлиннее конечно выглядит). Хм, интересно, перепишут ли теперь или нет... )
K>Никак, таких функций в хаскеле нет, аргумент у всех только один. K>Можно ли на хаскеле написать конкатенацию кортежей и вообще обобщенно работать с суммами? Да, но это, конечно, не тот код, который на хаскеле легко/приятно писать.
Угу, на шаблонах тоже не совсем удобно было, хотя полностью работало (и с нулевым оверхедом, всё во время компиляции). Сейчас вот стало так. И это язык только разгоняется (скоро обещаются модули, концепты и ещё куча плюшек, хотя я больше всего ожидаю интроспекцию)... А как у Хаскеля с динамикой развития? )
K>Чего тут объяснять? Вместо фортранолапши с циклами — комбинаторы комбинируете.
Такой ответ уже был. После чего я попросил уточнить на конкретном примере моей конкретной задачи, т.к. я не увидел как применить такое к ней. И теперь мы снова вернулись сюда же? )
Re[133]: Есть ли вещи, которые вы прницпиально не понимаете.
Здравствуйте, Klapaucius, Вы писали:
K>Пример работающего кода, запощенный сюда, с микробенчмарком и всей информацией необходимой для воспроизведения результата.
Так вот прямо же по той моей ссылке theron-library.com/index.php?t=page&p=performance график, а под ним таблица с цифрами. А в самом начале страницы идут ссылки на описание каждого теста: постановка задачи и полный исходный код. Типа такого theron-library.com/index.php?t=page&p=threadring.
Хм, сейчас заметил, что форум работает некорректно и портит ссылки: заменяет & на &. Поменял ссылки на просто текст.
_>>И что по вашему ещё должно обязательно входить в реализацию модели акторов? ) K>Что бы там по-моему не должно было быть, все вами будет, конечно, отметено как ненужное.
Ну так в отличие от довольно мутного понятия "поддержка иммутабельности в языке" модель акторов имеет подробные описания... )
_>>Копирование только в случае если это не последняя версия. K>Ну так иммутабельной (персистентной) структурой данных называется такая, которая в этом случае полного копирования не требует. Такая, как вы описываете — это мутабельная (эфемерная).
С чего бы это? Как раз мутабельной копирование не требуется.
K>Спор в интернете не такая простая вещь как вы думаете. К примеру, если вы приводите неработающий пример — я вовсе не обязан считать его неопровержимым аргументом, как вы от меня сейчас ожидаете.
А что там этим примером? Ответ выдаёт неправильный или работает не быстро? )
K>"вы стеком не обойдетесь" в данном случае означает, что для управления памятью стека не достаточно.
Ну так если в дополнение к стеку будет разрешено делать ещё new/delete (только для больших данных) внутри классов (т.е. наружу не выходит и управляется через RAII и тот же стек), то уже будет достаточно для подавляющего числа задач.
K>Так в этом и проблема. В общем случае, в высокоуровневом коде знания о времени жизни нет.
В общем случае нет, в том смысле что мы не не можем написать что-то типа универсального сборщика мусора сразу для всех задач. Но мы без проблем можем это сделать в практически каждой конкретной задаче.
K>А если 90% данных между документами разделяются? Вот иммутабельная структура данных — это набор таких документов. Понятна идея?
Идея понятна. Но не понятен пример реальных разделяемых данных в каких-то редакторах. Я вот вспоминаю что Word, что Excel (про программистские редакторы вообще молчу), что графические, везде максимум ссылки между документами встречаются и никакого разделения. Может быть такие вот иммутабельные структуры решают очередную виртуальную академическую проблему? )
Здравствуйте, alex_public, Вы писали:
_>Эмм, имплементация? А что тогда будет в случае, если мы продолжим эту диаграммку выше (к примеру понятно, что View, Menubar, Toolbar и т.п. наследованы от одного общего класса, тоже библиотечного)? T.e. имплементация подходит для случая интерфейс->реализаций, но это ровно один уровень иерархии, а в любой GUI библиотеке их намного больше.
Ну так иерархия "интерфейсов"-то многоуровневая. Т.е. все основные средства доступные в UML задействованы.
_>Да, и кстати, я в очередной раз не понял кого же вы хотите уже здесь назначить единицей инкапсуляции (обозначать прямоугольником на диаграмме классов). У нас были версии и про типы и про модули (хотя это мне казалось сомнительным)... Здесь же вы предлагает считать ими классы типов? Или же их экземпляры? Или что?)
Да какая разница? Спецификаторы видимости из UML задействовать можно.
_>С удовольствием познакомлюсь как пишут подобное в Хаскеле. Я серьёзно. ) Потому как пока-что я видел на Хаскеле только использование чужих GUI библиотек с соответствующей (и давно привычной мне) архитектурой.
Полностью хаскельного GUI я не знаю, но есть библиотеки родственные всякому лайауту виджетов — вроде http://projects.haskell.org/diagrams/ — вот это полностью идиоматичная хаскельная библиотека. Основной принцип устройства описан здесь: http://www.cis.upenn.edu/~byorgey/pub/monoid-pearl.pdf
_>Основной мой тезис в этой части нашей дискуссии был такой: UML (как пример одного из важных промышленных инструментов) не адаптирован к ФП вообще и к Хаскелю в особенности (т.к. там не только ФП, но и ещё ленивость).
Интересный поворот. А почему ленивость важна в этом аспекте?
_>Причём похоже никто и не шевелится что-то исправлять в данном направление. И понятно почему: хотя ФП методы активно проникают в промышленное программирование, но к построению общей архитектуры приложения (каркаса так сказать) это отношения не имеет — там царит ООП.
Не обязательно. Иммутабельные "объекты" и, к примеру, "обобщенное программирование" никакого отношения к ООП не имеют, если отвлечься от того, что "ООП" обычно и употребляется как синоним "промышленное программирование", и даже если от ООП там уже вообще ничего не останется — это все равно будет "ООП" называться.
_>А чем не понравилась та последняя реализация на D? ) Там же даже цикла нет — рекурсией заменил. )))
Проблема не в наличии цикла. Циклы применять, конечно, можно. Проблема в том, что по условию задачи между стадиями конвейера данные передаются в иммутабельных структурах данных. Такой пример вы так и не написали.
_>Да, кстати, самое забавное, что решение со 100% настоящей имммутабельностью было у меня давным давно — я его первым опубликовал.
Нет, не было. Там только в одном месте для передачи данных иммутабельная структура использовалась. а в примере таких точек передачи данных десятки должны быть.
_>И оно работало действительно очень долго (за счёт постоянного копирования всего массива). И великолепно ускорялось переходом к мутабельному коду (заменой соответствующего оператора). Я бы на вашем месте сразу же уцепился за него в качестве доказательства отсутствия оптимизации под иммутабельность и собственно говоря никто бы и не смог возразить. Но вы почему-то не увидели, что там всё по честному, и захотели чтобы для иммутабельных данных применялась специальная структура (а не стандартный массив с модификатором immutable).
Я не увидел, что там "все по честному" потому, что там не все "по честному". И для иммутабельных данных должна применяться не "специальная" мутабельная структура, а структура иммутабельная. насколько она будет "специальной" уже не важно.
_> Ну захотели — получите. Только уже с добавленной оптимизацией и соответственно заметно быстрее версии на Хаскеле. )))
Прямой обман, никакой наблюдаемой разницы с аналогом на хаскеле получить не удалось.
_>Эмм, разве не очевидно? Обычный UML редактор очевидно не умеет никаких методов выходящих за стандарт.
Что, "обычный UML редактор" не поддерживает стереотипы и подписи к отношениям? А других точек расширения и не нужно.
_>В случае же Хаскеля грубо говоря вся программка целиком состоит только из таких "расширений"
На самом деле нет.
_>Причём даже если и сможем что-то сваять для себя, то другому программисту на Хаскеле такую диаграммку так просто и не покажешь — он же не знает "нотацию". Или что ещё хуже, у него уже есть своя, другая. )))
Да, то, что программист на хаскеле вообще не знает UML — вполне вероятно. Если же он знает, то вполне сможет разобраться.
_>О, раз вы так считаете, то может тогда подскажите какие-то ссылки на соответствующие статьи (не буду наглеть с просьбами о личном пересказе)? А то по проектированию с помощью ООП целые толстые тома есть с кучей всяких известных (которые уже даже в вики найти можно) принципов и т.п.
По-моему, "толстые тома" — это как раз верный признак, что проектирование с помощью ООП совсем нетривиально.
Впрочем, все наработки ООП дизайна применимы в ФП в полном объеме.
_>А чего-то подобного на тему ФП я что-то не видел.
Для EDSL метапрограммирование не нужно. Но вообще оно в хаскеле появилось больше 10 лет назад. Насколько оно нормальное — отдельная история, думаю нормальнее, чем у 95% языков.
_>Имелась в виду наша дискуссия. ))) Ну а так на самом деле отдельные методы ФП сейчас весьма активно проникают в промышленное программирование. Но именно как отдельные техники, применяемые императивными языками внутри ООП каркасов. )))
Это как раз понятно, потому что никаких выразительных средств кроме ООП инструментария в промышленных языках фактически нет. Впрочем, все равно требуется широкое толкование термина "ООП", потому что те же иммутабельные "объекты" — это, по-моему, никакое не ООП, это совсем другие подходы, которые просто энкодятся ООП средствами (единственно доступными в языках).
_>Т.е. по сути вы согласны что C++ — это сейчас оптимальный выбор для определённого класса задач?
Оптимальный выбор между чем и чем? C++ и C++?
_>Тогда наши споры приобретают несколько другой характер: обсуждения собственно границ применимости. )))
"Выбор" языка программирования вообще никак от "классов задач" не зависит. Выбор языка ограничивается наличием реализации индустриального качества и наличием программистов, знающих язык. Понятно, что во многих случаях и выбора никакого нет.
_>Кстати, а для не требующих мощности (низкоуровневой) C++ проектов (и если они не особо крупные) мне в последнее время нравится применять вообще Питон. Очень быстро получается результат.
Я крайне скептически отношусь к применению бестиповых языков для чего-то кроме написания однострочников в консоли. На хоть сколько-нибудь высокоуровневом типизированном языке писать не сложнее, а вот поддерживать потом написанный код — гораздо легче.
K>>Да, не понял, что там выдающегося по части лямбд. Там вроде обобщенная работа с кортежами демонстрируется.
_>Ну демонстрировалась там собственно новинка C++ — те самые полиморфные лямбды. В общем то ничего особенного, просто лямбдам разрешили поведение как и у обычных шаблонных функций (которые могут иметь произвольное число параметров произвольных типов).
Ну так "поливариадичность" функций это и есть, по сути, обобщенная работа с кортежами параметров, которые они принимают.
_>Однако такой простой и очевидный шаг дал много интересных техник (через возврат замыкания и т.п.), которые частично и демонстрировались в этом коде на примере реализации классических приёмов ФП.
Ну так возврат замыкания все равно без GC останется инвалидным.
_>Угу, на шаблонах тоже не совсем удобно было, хотя полностью работало (и с нулевым оверхедом, всё во время компиляции). Сейчас вот стало так. И это язык только разгоняется (скоро обещаются модули, концепты и ещё куча плюшек, хотя я больше всего ожидаю интроспекцию)... А как у Хаскеля с динамикой развития? )
Нормально в хаскеле с динамикой развития. Те же концепты обещают еще с тех времен, когда хаскеля в современном понимании можно сказать что и не было еще, так что довольно странно представлять C++ как "динамично развивающийся". По сравнению с явой или фортраном — возможно.
_>Такой ответ уже был. После чего я попросил уточнить на конкретном примере моей конкретной задачи, т.к. я не увидел как применить такое к ней. И теперь мы снова вернулись сюда же? )
Не понимаю, какая тут может быть специфика задачи. Любой цикл можно переписать в виде более понятной комбинации комбинаторов. Что бывают какие-то задачи "безциклового программирования"?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете.
Здравствуйте, alex_public, Вы писали:
_>Ну так в отличие от довольно мутного понятия "поддержка иммутабельности в языке" модель акторов имеет подробные описания... )
Не согласен. "поддержка иммутабельности в языке" понятие предельно ясное, а "модель акторов" — это скорее баззворд.
_>С чего бы это? Как раз мутабельной копирование не требуется.
Разумеется требуется. Создать версию мутабельной структуры без копирования не получится.
_>А что там этим примером? Ответ выдаёт неправильный или работает не быстро? )
Условиям задачи не соответствует. Код, работающий с вашей "иммутабельной" структурой, который неправильный ответ выдает — пишется тривиально, да и написан. Скорость не впечатляет, та же, что и у аналога на хаскеле.
_>Ну так если в дополнение к стеку будет разрешено делать ещё new/delete (только для больших данных) внутри классов (т.е. наружу не выходит и управляется через RAII и тот же стек), то уже будет достаточно для подавляющего числа задач.
У вас тут телега впереди лошади. "Подавляющим большинством задач" объявляются те, для которых достаточно "управления через RAII" — вот так вернее. Все остальные юзкейсы для программиста на низкоуровневом языке в "слепой зоне".
Как выяснилось из опытов с MLkit, управления даже с помощью менее ограниченной техники чем RAII — вывода регионов — для высокоуровневого кода недостаточно. О чем я уже писал.
_>В общем случае нет, в том смысле что мы не не можем написать что-то типа универсального сборщика мусора сразу для всех задач. Но мы без проблем можем это сделать в практически каждой конкретной задаче.
Реализация управления памятью для "практически каждой конкретной задачи" это совсем не то, что ожидается от высокоуровневого языка. Высокоуровневый язык — это абстрагирование от размещения и управление памятью, которое хорошо работает в общем случае.
_>Идея понятна. Но не понятен пример реальных разделяемых данных в каких-то редакторах. Я вот вспоминаю что Word, что Excel (про программистские редакторы вообще молчу), что графические, везде максимум ссылки между документами встречаются и никакого разделения.
10 правок дают 11 версий документов, разделяющих 90% данных. Речь, впрочем, была не про пользовательские документы, а про структуры данных, с которыми программист работает.
_>Может быть такие вот иммутабельные структуры решают очередную виртуальную академическую проблему? )
Иммутабельные структуры решают реальную проблему, которая называется "удобство программиста". Работать с персистентной версией структуры данных удобнее, чем с эфемерной как раз за счет версионности.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[133]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>Эмм, имплементация? А что тогда будет в случае, если мы продолжим эту диаграммку выше (к примеру понятно, что View, Menubar, Toolbar и т.п. наследованы от одного общего класса, тоже библиотечного)? T.e. имплементация подходит для случая интерфейс->реализаций, но это ровно один уровень иерархии, а в любой GUI библиотеке их намного больше. K>Ну так иерархия "интерфейсов"-то многоуровневая. Т.е. все основные средства доступные в UML задействованы.
Так в библиотеке же там не интерфейсы, а как раз реализации должны сидеть. Т.е. реализация Window (с самой большой кучей работающих членов), реализация View, порождённая от Window, и добавляющая пару методов и т.п.
_>>Да, и кстати, я в очередной раз не понял кого же вы хотите уже здесь назначить единицей инкапсуляции (обозначать прямоугольником на диаграмме классов). У нас были версии и про типы и про модули (хотя это мне казалось сомнительным)... Здесь же вы предлагает считать ими классы типов? Или же их экземпляры? Или что?)
K>Да какая разница? Спецификаторы видимости из UML задействовать можно.
Ну вот как раз потому что подобной определённости нет, UML и нельзя по нормальному использовать для Хаскеля. Опять же я говорю про текущий момент, а не про какую-то принципиально неразрешимую проблему.
K>Полностью хаскельного GUI я не знаю, но есть библиотеки родственные всякому лайауту виджетов — вроде http://projects.haskell.org/diagrams/ — вот это полностью идиоматичная хаскельная библиотека. Основной принцип устройства описан здесь: http://www.cis.upenn.edu/~byorgey/pub/monoid-pearl.pdf
Да, любопытно. Кстати, такие "dsl" же легко и на C++ делаются. Правда для вывода графики не помню подобных решений. Помню для других целей. Но в любом случае, это всё немного не то. Потому как главное в GUI библиотеке всё же не просто удобная обёртка над API вывода на экран, а ещё и удобная система обработчиков событий (и соответственно куча уже написанных обработчиков в библиотечных виджетах). И именно тут ООП ложится особенно логично. А для просто вывода на экран действительно ООП совсем не обязательно — эту проблему умеет решать вообще какой-нибудь postscript. )))
_>>Основной мой тезис в этой части нашей дискуссии был такой: UML (как пример одного из важных промышленных инструментов) не адаптирован к ФП вообще и к Хаскелю в особенности (т.к. там не только ФП, но и ещё ленивость). K>Интересный поворот. А почему ленивость важна в этом аспекте?
Какой ещё поворот? ) Мы же это уже подробно обсуждали раньше. Речь про применимость диаграмм деятельности и последовательности — двух самых используемых диаграмм поведения в UML.
K>Проблема не в наличии цикла. Циклы применять, конечно, можно. Проблема в том, что по условию задачи между стадиями конвейера данные передаются в иммутабельных структурах данных. Такой пример вы так и не написали.
Так у меня там собственно и конвейера нет. ) А с чего это он обязательно должен быть? ) У нас вроде как была просто задачка на простые числа в контексте разговора о поддержки иммутабельности. Данная задачка не требует обязательного конвейера.
K>Я не увидел, что там "все по честному" потому, что там не все "по честному". И для иммутабельных данных должна применяться не "специальная" мутабельная структура, а структура иммутабельная. насколько она будет "специальной" уже не важно.
Ну так с вашей точки зрения "immutable int[]" в D является иммутабельной структурой или нет? )
K>Прямой обман, никакой наблюдаемой разницы с аналогом на хаскеле получить не удалось.
Да, да, я помню эти ваши тесты. С отказом запускать присланный exe, выборами подходящих компиляторов и т.п. )))
K>Что, "обычный UML редактор" не поддерживает стереотипы и подписи к отношениям? А других точек расширения и не нужно.
Естественно поддерживает. Но этого недостаточно чтобы отображать скажем вложенные классы и т.п. ) Для обычных языков это естественно не проблема, т.к. там это обычно служит для утилитарных (а не архитектурных) вещей и обычно отображается просто в виде соответствующего префикса в имени класса. А в том же Хаскеле, если вы захотите (как вы говорили) отображать модули на диаграмме классов, это сломает весь смысл отображения.
_>>Причём даже если и сможем что-то сваять для себя, то другому программисту на Хаскеле такую диаграммку так просто и не покажешь — он же не знает "нотацию". Или что ещё хуже, у него уже есть своя, другая. ))) K>Да, то, что программист на хаскеле вообще не знает UML — вполне вероятно. Если же он знает, то вполне сможет разобраться.
Только взглянув при этом на код... Чтобы понять какую сущность обозначает данный квадратик. А вот в случае ООП понять архитектуру можно вообще без кода, только по диаграмме. Причём это не будет зависеть от используемого языка...
_>>О, раз вы так считаете, то может тогда подскажите какие-то ссылки на соответствующие статьи (не буду наглеть с просьбами о личном пересказе)? А то по проектированию с помощью ООП целые толстые тома есть с кучей всяких известных (которые уже даже в вики найти можно) принципов и т.п.
K>По-моему, "толстые тома" — это как раз верный признак, что проектирование с помощью ООП совсем нетривиально. K>Впрочем, все наработки ООП дизайна применимы в ФП в полном объеме.
Интересно. Но снова всё вращается вокруг конвейеров. В то время как в реальных задачах они мне встречаются весьма редко.
K>Я крайне скептически отношусь к применению бестиповых языков для чего-то кроме написания однострочников в консоли. На хоть сколько-нибудь высокоуровневом типизированном языке писать не сложнее, а вот поддерживать потом написанный код — гораздо легче.
Всё же на Питоне получится заметно быстрее. Если речь о "проектах" на несколько страничек кода.
_>>Ну демонстрировалась там собственно новинка C++ — те самые полиморфные лямбды. В общем то ничего особенного, просто лямбдам разрешили поведение как и у обычных шаблонных функций (которые могут иметь произвольное число параметров произвольных типов). K>Ну так "поливариадичность" функций это и есть, по сути, обобщенная работа с кортежами параметров, которые они принимают.
Ааа, ну да))) Я просто не понял, что вы кортежем обозвали собственно параметры. Тогда да, об этом и речь. Просто там в примере ещё вводится и собственно отдельная сущность tuple... )))
K>Ну так возврат замыкания все равно без GC останется инвалидным.
Мы же это уже обсуждали. Это не было инвалидным даже в старом стандарте, т.к. банальное копирование полностью решает этот вопрос. Просто получается не эффективный код. Ну а с приходом нового стандарта (и move semantics в нём) вопрос эффективной передачи данных вверх по стеку вполне решён.
K>Нормально в хаскеле с динамикой развития. Те же концепты обещают еще с тех времен, когда хаскеля в современном понимании можно сказать что и не было еще, так что довольно странно представлять C++ как "динамично развивающийся". По сравнению с явой или фортраном — возможно.
C++ и не был динамично развивающимся. Где-то до последних 5 лет. А сейчас пошёл такими темпами, что некоторые даже пугаются. ))) А другие наоборот радуются и даже перестают планировать переход на альтернативы (типа D и т.п.).
K>Не понимаю, какая тут может быть специфика задачи. Любой цикл можно переписать в виде более понятной комбинации комбинаторов. Что бывают какие-то задачи "безциклового программирования"?
Эммм, я же вроде как ясно описал, что основные циклы закодированы в спец. языке, который гарантирует их распараллеливание (в смысле SIMD). Так что там нужны именно циклы в явном виде. Ну и с какими-то там механизмами абстракций там дела ничуть не лучше голого C. ))) Как туда вставить какие-то конвейеры? Ну а в остальной части кода, которая написана на C++ и в достаточно абстрактном виде (в классических традициях ООП), каких-то подобных циклов вообще не наблюдается.
Re[135]: Есть ли вещи, которые вы прницпиально не понимаете.
Здравствуйте, Klapaucius, Вы писали:
K>Не согласен. "поддержка иммутабельности в языке" понятие предельно ясное, а "модель акторов" — это скорее баззворд.
Ну можно тогда увидеть ссылку (скажем в той же Википедии) на определение "поддержки иммутабельности в языке"? ) Ссылку на описание модели акторов я естественно без проблем предоставлю. )
_>>С чего бы это? Как раз мутабельной копирование не требуется. K>Разумеется требуется. Создать версию мутабельной структуры без копирования не получится.
Ну т.е. в том моём примере у меня значит всё же не мутабельная структура? ) Она же обходилась без копирования для создания новых версий... )
K>У вас тут телега впереди лошади. "Подавляющим большинством задач" объявляются те, для которых достаточно "управления через RAII" — вот так вернее. Все остальные юзкейсы для программиста на низкоуровневом языке в "слепой зоне". K>Как выяснилось из опытов с MLkit, управления даже с помощью менее ограниченной техники чем RAII — вывода регионов — для высокоуровневого кода недостаточно. О чем я уже писал.
Всё правильно, речь про RAII. Так вот мы же говорим о практике, а не о теории, не так ли? И соответственно если через RAII получается реализовать скажем 90% задач работы с памятью (а остальное реализуем скажем через подсчёт ссылок и т.п.), то уже получим суперэффективный код. Который будет заметно превосходить все замечательные универсальные сборщики мусора.
K>Реализация управления памятью для "практически каждой конкретной задачи" это совсем не то, что ожидается от высокоуровневого языка. Высокоуровневый язык — это абстрагирование от размещения и управление памятью, которое хорошо работает в общем случае.
Возможно. Но такова цена настоящего быстродействия. Но опять же замечу главное — это ситуация для весьма редкого класса задач. А большую часть обычных задач C++ решает эффективнее всех и без написания какого-то специального кода (стандартные методы типа RAII на стеке).
K>Иммутабельные структуры решают реальную проблему, которая называется "удобство программиста". Работать с персистентной версией структуры данных удобнее, чем с эфемерной как раз за счет версионности.
Если сама задача требует версионности, то безусловно. Вопрос опять же в том насколько это часто встречающаяся на практике задача.
Re[134]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
K>>Ну так иерархия "интерфейсов"-то многоуровневая. Т.е. все основные средства доступные в UML задействованы. _>Так в библиотеке же там не интерфейсы, а как раз реализации должны сидеть. Т.е. реализация Window (с самой большой кучей работающих членов), реализация View, порождённая от Window, и добавляющая пару методов и т.п.
Непонятно только, в каком смысле это проблема с UML. Если у нас нет наследования реализации, мы можем обходится имплементацией и агрегацией, никакого расширения UML тут не требуется.
Что касается тайпклассов в хаскеле, то "работающие члены" там делать можно, функционально это не столько аналог интерфейсов, сколько трейтов.
K>>Да какая разница? Спецификаторы видимости из UML задействовать можно. _>Ну вот как раз потому что подобной определённости нет, UML и нельзя по нормальному использовать для Хаскеля. Опять же я говорю про текущий момент, а не про какую-то принципиально неразрешимую проблему.
Не вижу, чем тут хаскель выделяется на фоне других языков, у которых есть некоторые особенности определения видимости. Например, нужно как-то договариваться как friend class в UML обозначить, означает ли это, что использовать UML с C++ нельзя?
_>Кстати, такие "dsl" же легко и на C++ делаются.
Ну да, как и в большинстве языков.
_>главное в GUI библиотеке всё же не просто удобная обёртка над API вывода на экран, а ещё и удобная система обработчиков событий (и соответственно куча уже написанных обработчиков в библиотечных виджетах).
Ну так с этого мы и начали, в самом начале разговора я пример такого кода приводил. Библиотеки на которых идиоматичная работа с событиями для хаскеля есть, https://hackage.haskell.org/package/reactive-banana-wx
например.
_>И именно тут ООП ложится особенно логично.
Непонятно, в чем заключается особенная логичность ООП для обработки событий? Даже в ООП-библиотеках для обработки событий часто используют не ООП средства (в языках где они есть, конечно).
_>Мы же это уже подробно обсуждали раньше. Речь про применимость диаграмм деятельности и последовательности — двух самых используемых диаграмм поведения в UML.
Ну и причем тут ленивость-то? Вроде мы на эту тему неоднократно заходили, и я всякий раз говорил что они вполне применимы.
_>Так у меня там собственно и конвейера нет. ) А с чего это он обязательно должен быть? ) У нас вроде как была просто задачка на простые числа в контексте разговора о поддержки иммутабельности. Данная задачка не требует обязательного конвейера.
Нет, задачка была другая, а именно:
Задача заключается в проверке "поддержки иммутабельности" в языке, посредством создания как можно большего числа промежуточных значений в виде иммутабельных структур данных таким образом, чтоб часть из них можно было выкинуть за ненадобностью, а часть нет.
Собственно, вычисление каких-то там чисел не обязательно, нужно просто использовать иммутабельные данные и создавать аналогичную нагрузку на память без оптимизации.
_>Ну так с вашей точки зрения "immutable int[]" в D является иммутабельной структурой или нет? )
Это зависит от того, какие операции определены на нем и какая у них асимптотика.
С любой точки зрения "immutable int[]" практиченой иммутабельной стрктурой не является, потому что создание версии всегда эквивалентно полному копированию. "Практичность" иммутабельности тут имеет значение потому, что речь о поддержке.
K>>Прямой обман, никакой наблюдаемой разницы с аналогом на хаскеле получить не удалось. _>Да, да, я помню эти ваши тесты. С отказом запускать присланный exe,
Я вижу смысл сравнивать воспроизводимые замеры скорости работы открытого кода. Смысл сравнивать запуски экзешников, выдающих какое-то число на экран я — наоборот — не вижу. Но если вы хотите, то вам я их с удовольствием вышлю (правда, ваши сообщения о скорости их работы как аргумент не приму).
_>выборами подходящих компиляторов и т.п. )))
Довольно странная претензия, если учесть, что тот компилятор который я выбрал генерировал более быстрый код, чем тот что выбрали вы. Ну и в любом случае я получал результат и для того, и для другого.
_>Естественно поддерживает. Но этого недостаточно чтобы отображать скажем вложенные классы и т.п.
Т.е. все языки программирования в которых они есть (а они почти везде есть) с UML не совместимы?
_>Для обычных языков это естественно не проблема, т.к. там это обычно служит для утилитарных (а не архитектурных) вещей и обычно отображается просто в виде соответствующего префикса в имени класса.
Непонятно, почему это не проблема.
_>А в том же Хаскеле, если вы захотите (как вы говорили) отображать модули на диаграмме классов, это сломает весь смысл отображения.
Так ведь не сломает.
_>Только взглянув при этом на код... Чтобы понять какую сущность обозначает данный квадратик. А вот в случае ООП понять архитектуру можно вообще без кода, только по диаграмме. Причём это не будет зависеть от используемого языка...
Какую сущность обозначает квадратик можно написать в стереотипе.
K>>По-моему, "толстые тома" — это как раз верный признак, что проектирование с помощью ООП совсем нетривиально. _>Ну тома то там больше для разъяснения.
Большинство этих принципов никакой ООП специфики не имеют.
_>Интересно. Но снова всё вращается вокруг конвейеров. В то время как в реальных задачах они мне встречаются весьма редко.
Вы редко используете более одной функции на всю программу?
_>Всё же на Питоне получится заметно быстрее. Если речь о "проектах" на несколько страничек кода.
Сомневаюсь.
K>>Ну так возврат замыкания все равно без GC останется инвалидным.
_>Мы же это уже обсуждали. Это не было инвалидным даже в старом стандарте, т.к. банальное копирование полностью решает этот вопрос. Просто получается не эффективный код.
Не понимаю, как неэффективный код может быть решением вопроса в данном случае.
_>Ну а с приходом нового стандарта (и move semantics в нём) вопрос эффективной передачи данных вверх по стеку вполне решён.
Область применимости передачи владения ограничена, для поддержки иммутабельных структур она бесполезна.
_>C++ и не был динамично развивающимся. Где-то до последних 5 лет. А сейчас пошёл такими темпами, что некоторые даже пугаются. )))
Для многих языков, особенно с малым числом пользователей и след. малой "инерцией" вроде хаскеля — это вообще-то медленные темпы. (тут должна быть ссылка на то сообщение "эта фича поддерживается уже 11 дней — у вас слишком старая версия Rust")
_>А другие наоборот радуются и даже перестают планировать переход на альтернативы (типа D и т.п.).
Да, для языков, являющихся копиями С++ с перламутровыми пуговицами — это проблема. Хотя понятно, что всех удобств D в C++ скорее всего не будет.
K>>Не понимаю, какая тут может быть специфика задачи. Любой цикл можно переписать в виде более понятной комбинации комбинаторов. Что бывают какие-то задачи "безциклового программирования"?
_>Эммм, я же вроде как ясно описал, что основные циклы закодированы в спец. языке, который гарантирует их распараллеливание (в смысле SIMD). Так что там нужны именно циклы в явном виде.
Зачем они нужны в явном виде? Их надо из комбинаторного DSL генерировать. Именно потому, что... _>с какими-то там механизмами абстракций там дела ничуть не лучше голого C
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[136]: Есть ли вещи, которые вы прницпиально не понимаете.
_>Здравствуйте, Klapaucius, Вы писали:
_>Ну можно тогда увидеть ссылку (скажем в той же Википедии) на определение "поддержки иммутабельности в языке"? ) Ссылку на описание модели акторов я естественно без проблем предоставлю. )
Определение иммутабельных структур данных и в википедии есть: http://en.wikipedia.org/wiki/Persistent_data_structure я пробежал по диагонали первый абзац, вроде все правильно, также написано зачем для поддержки нужен ГЦ, и какимим свойствами должны обладать версии.
"Поддержка" же понимается в общеупотребимом смысле, а не в вашем, когда она означает то же, что и "отсутствие поддержки".
_>Ну т.е. в том моём примере у меня значит всё же не мутабельная структура? ) Она же обходилась без копирования для создания новых версий... )
Она вообще создание новых версий не поддерживает, что я легко продемонстрировал.
_>Всё правильно, речь про RAII. Так вот мы же говорим о практике, а не о теории, не так ли?
Да мы говорим о практике, когда попробовали писать идеоматический высокоуровневый код без ГЦ, но с выводом регионов (что дает строго больше возможностей, чем стек). Выяснилось, что для написания высокоуровневого кода — даже по меркам не слишком-то высокоуровневого языка вроде ML — без ГЦ не обойтись.
_>И соответственно если через RAII получается реализовать скажем 90% задач работы с памятью (а остальное реализуем скажем через подсчёт ссылок и т.п.),
С помощью RAII можно решить 100% задач, решаемых с помощью RAII, это точно. А вот работа с иммутабельными структурами, например, не получится, если вы памятью с помощью RAII управляете.
_>то уже получим суперэффективный код. Который будет заметно превосходить все замечательные универсальные сборщики мусора.
Да, есть, конечно, такие сценарии, на которых ГЦ покажет результат хуже. Но на типичных сценариях выделения памяти для высокоуровневых языков вообще и работы с иммутабельными данными в частности ГЦ покажет большую производительность. Потому на низкоуровневых языках и пишут совсем не так, как на высокоуровневых.
_>Возможно. Но такова цена настоящего быстродействия.
Да, конечно.
_>Но опять же замечу главное — это ситуация для весьма редкого класса задач. А большую часть обычных задач C++ решает эффективнее всех и без написания какого-то специального кода (стандартные методы типа RAII на стеке).
Нет, наоборот, на C++ пишут только так, как он позволяет. Так как пишут на высокоуровневых языках на C++ не пишут, потому что это (на практике) невозможно. В частности, иммутабельные структуры данных при написании программ на C++ не используют почти никогда. При написании кода на высокоуровневых языках, вроде ФЯ, их используют — наоборот — почти всегда.
_>Если сама задача требует версионности, то безусловно. Вопрос опять же в том насколько это часто встречающаяся на практике задача.
Еще раз. Версионности требует задача "удобство для программиста". На практике встречается всегда.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Я недавно понял, что совершенно не понимаю зачем нужна сериализация. Т.е. не то, чтобы совсем не понимаю... Ну вот смотрите: сериализация — это прямой перевод структур данных в бинарный вид. Если структура данных поменялась в новой версии программы, значит старый вариант уже работать не будет. Т.о. передачи или сохранение сериализованных данных имеет крайне узкую область применения. Однако, очень многие пишут сериализацию и как существуют даже целые библиотеки под эту функциональность. Зачем так делать?
И каждый день — без права на ошибку...
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, B0FEE664, Вы писали:
BFE>Я недавно понял, что совершенно не понимаю зачем нужна сериализация. Т.е. не то, чтобы совсем не понимаю... Ну вот смотрите: сериализация — это прямой перевод структур данных в бинарный вид. Если структура данных поменялась в новой версии программы, значит старый вариант уже работать не будет. Т.о. передачи или сохранение сериализованных данных имеет крайне узкую область применения. Однако, очень многие пишут сериализацию и как существуют даже целые библиотеки под эту функциональность. Зачем так делать?
Как раз сериализация — это не прямой перевод в бинарный вид.
Делают обычно так, что бы при расширении функционалности в последующих версиях можно было прочитать данные, сохранённые в предыдущих версиях.
То есть поля структур, которые остутсвовали в прошлой версии, и, соответственно отсутствуют в сериализованом файле,
при считывании в более новой версии просто заполняются некоторыми значениями по-умолчанию.
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, icWasya, Вы писали:
BFE>>Я недавно понял, что совершенно не понимаю зачем нужна сериализация. Т.е. не то, чтобы совсем не понимаю... Ну вот смотрите: сериализация — это прямой перевод структур данных в бинарный вид. Если структура данных поменялась в новой версии программы, значит старый вариант уже работать не будет. Т.о. передачи или сохранение сериализованных данных имеет крайне узкую область применения. Однако, очень многие пишут сериализацию и как существуют даже целые библиотеки под эту функциональность. Зачем так делать?
W>Как раз сериализация — это не прямой перевод в бинарный вид.
Если это так, то чем она отличается то записи ini-файла?
W>Делают обычно так, что бы при расширении функционалности в последующих версиях можно было прочитать данные, сохранённые в предыдущих версиях. W>То есть поля структур, которые остутсвовали в прошлой версии, и, соответственно отсутствуют в сериализованом файле, W>при считывании в более новой версии просто заполняются некоторыми значениями по-умолчанию.
А что делают, когда поля переносятся из одной структуры в другую? Или, скажем, вообще удаляют из новой версии?
И каждый день — без права на ошибку...
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, B0FEE664, Вы писали:
BFE>Я недавно понял, что совершенно не понимаю зачем нужна сериализация. Т.е. не то, чтобы совсем не понимаю... Ну вот смотрите: сериализация — это прямой перевод структур данных в бинарный вид. Если структура данных поменялась в новой версии программы, значит старый вариант уже работать не будет. Т.о. передачи или сохранение сериализованных данных имеет крайне узкую область применения. Однако, очень многие пишут сериализацию и как существуют даже целые библиотеки под эту функциональность. Зачем так делать?
Для вашего случая — можно написать upgrade.
Для удобства пользователя. Данные же не только в одной программе крутятся. Мы их часто передаем по сети.
В нашей программе есть структура, мы её хотим отправить по HTTP другой программе? Обычно структуру сереализуют в JSON и на другом конце JSON десереализуют обратно.
Здравствуйте, B0FEE664, Вы писали:
BFE> Я недавно понял, что совершенно не понимаю зачем нужна сериализация. Т.е. не то, чтобы совсем не понимаю... Ну вот смотрите: сериализация — это прямой перевод структур данных в бинарный вид. Если структура данных поменялась в новой версии программы, значит старый вариант уже работать не будет. Т.о. передачи или сохранение сериализованных данных имеет крайне узкую область применения. Однако, очень многие пишут сериализацию и как существуют даже целые библиотеки под эту функциональность. Зачем так делать?
Потому что слово serialize это от слово serial, т.е. перевод произвольной структуры данных в последовательную цепочку бит. А куда потом это дело пойдёт — в сокет, по serial порту или на диск в виде файла — дело десятое.
Совместимость версий потока бит вещь опциональная, но обычно очень полезная, поэтому во многих библиотеках нередко встречается.
Притом сохранение (или даже передача) структуры данных не всегда делается сериализацией. Например, можно данные сохранить в виде записей в таблицах СУБД или подветке реестра. А проблемы с версиями те же...
Здравствуйте, lazy/cjow/rhrr, Вы писали:
LCR>Я не понимаю Теорию Категорий
Вот самая простая книга по теории категорий:
Lawvere F. W., Schanuel S. H. Conceptual mathematics: A First Introduction to Categories
Взгляните еще сюда
Я сам просмотрел по диагонали более сложные книги, поэтому что-либо объяснить не смогу.
Программировать сложно. Но не программировать еще сложнее.
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Dair, Вы писали:
D>Для меня загадка — современные алгоритмы шифрования (криптографии). Мат.аппарата не хватает
В двух словах. Есть два потока — поток данных для шифрования и поток данных из "ключа шифрования". Если длины ключа не хватает на все данные, то ключ зацикливается (иногда с определённой модификацией, но это для того, чтобы избежать ситуации, когда одинаковые блоки в исходном сообщении превращаются в одинаковые блоки в зашифрованном сообщении, что может дать какую-то опору для начальной статистики в процессе взлома).
Поток данных при шифровании/дешифровании бьется на блоки некоей ширины. Далее в этом блоке осуществляются манипуляции над битами, где номером операции и/или аргументом операции выступает текущее слово из ключа шифрования.
Популярные операции:
— простое перемешивание бит, согласно текущему слову ключа (т.е. слово является номером перестановки бит из мн-ва полной их перестановки)
— замена бит на другие из некоего специального словаря (с тщательно подобранной статистикой), где ключом является текущий блок текста+код или часть кода текущего "слова" ключа, — это разновидность предыдущей операции, но с более равномерной конечной статистикой.
— битовые операции непосредственно с исходными данными и текущим словом ключа (XOR для простых видов шифрования).
Различные виды шифрования используют разные комбинации этих методов итеративно (например, 32 раза в одном из популярных алгоритмов), каждая итерация — это плюс 1 к степенной N в оценке ON*K*L ресурсов, необходимых на взлом, где К — длина ключа, L — некая исходная характеристика алгоритма (+ конкретных таблиц подмены).
Вот хорошее описание популярной "механики" над битами в процессе шифрования: ГОСТ 28147-89
DES/AES используют примерно те же шаги.
У нас были алгоритмы, подобные AES, еще в 92-м году (т.е. раньше, чем был опубликован AES). Довелось общаться с разработчиками этого алгоритма на конференции, обменивались идеями о его аппаратной реализации. Но конечные версии этих алгоритмов остались закрытыми для широкой публики, использовались (не знаю как сейчас) в секретной связи и военке. Наработки когда-то отдали в военный ВУЗ, последний раз я о них слышал в 93-м году как о законченном алгоритме, т.е. всё еще на 5 лет раньше выхода AES. ))
Именно из-за требований к "обычной" инфраструктуре получили распространения менее криптонадежные алгоритмы, типа public/private key, зато более практичные. Для сравнения, на сегодня симметричные системы считаются надежными от 128 бит, а несимметричные от 1024 бит (и то, поговаривают, что это слишком оптимистичная оценка).
D>На практическом уровне — public key/private key понятно, но чо там внутри — чисто магия.
Если сосредоточиться только на сути получения public key/private key, то никакой магии, у одной стороны есть свой приватный полу-ключ 1 и чужой публичный полу-ключ 2, у другой стороны есть публичный 1 и приватный 2. Есть алгоритм, который порождает одинаковый ключ шифрования К из обоих вариантов {pub1, pri2} и {pri1, pub2}. Далее идёт терминологическая путаница, потому что именно полученный К является тем самым ключом шифрования. А в "базе" несимметричных алгоритмов сидит какая-нить разновидность симметричного.
Итого, в твоём вопросе можно выделить два независимых раздела:
— симметричное шифрование ("жонглирование" битами)
— несимметричное шифрование (способы получения пар полу-ключей для использования их затем в операциях из предыдущего пункта).
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, B0FEE664, Вы писали:
BFE>>>Я недавно понял, что совершенно не понимаю зачем нужна сериализация. Т.е. не то, чтобы совсем не понимаю... Ну вот смотрите: сериализация — это прямой перевод структур данных в бинарный вид. Если структура данных поменялась в новой версии программы, значит старый вариант уже работать не будет. Т.о. передачи или сохранение сериализованных данных имеет крайне узкую область применения. Однако, очень многие пишут сериализацию и как существуют даже целые библиотеки под эту функциональность. Зачем так делать?
W>>Как раз сериализация — это не прямой перевод в бинарный вид. BFE>Если это так, то чем она отличается то записи ini-файла?
Можно рассматривать запись ini-файла как один из видов сериализации
WBR, Igor Evgrafov
Re[3]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Artem Korneev, Вы писали:
AK>vim я использовал для кодинга на с/с++/erlang/tcl/python/bash много лет. Потом решил освоить emacs, но за несколько лет так и не смог отучить его от некоторых неприятных особенностей поведения. Главной неприятностью оказалась его принципиальная однопоточность, а следовательно всякие медленные операции вроде парсинга исходников нельзя перевести в фон.
Здравствуйте, Greeter, Вы писали:
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Не понимаю, как программы до сих пор работают, немотря на то, что в них столько ошибок.
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Кстати говоря, вернулся посмотреть, не вернулся ли ты и заметил важную вещь, которую пропустил на прошлом разе. Ты привел код не того алгоритма. Исходный — парсер последовательности с неоднозначной грамматикой. А у тебя вышел парсер с однозначной грамматикой и он выдает немного другой результат. В некоторых последовательностях выдаст тот же, а в некоторых — другой. Вот такое у тебя решение.
Так часто бывает, когда матан пытаются подменить эвристикой. Годы работало, а потом — опаньки !
Re: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Greeter, Вы писали:
G>Или не до конца понимаете в программировании? Для меня вот например Oracle это что-то типа пятого измерения В теории какбы понятно — деревья, логарифмические алгоритмы, интерпретаторы с перкомпиляцией, кэши разные. Но как оно все вместе так хитро собрано, и почему оно такое пц быстрое, и при этом устойчивое, и как работает его оптимизатор? Вообще не представляю.
Не понимаю свободные переменные и замыкания. Зачем всё это нужно если можно передать параметр по ссылке, например.
Sic luceat lux!
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Kernan, Вы писали:
K>Не понимаю свободные переменные и замыкания. Зачем всё это нужно если можно передать параметр по ссылке, например.
Замыкания — это технология по сути предоставляющая альтернативу ООП. В каких-то областях она хуже, а в каких-то лучше ООП. К примеру она позволяет удобным образом создавать объекты без всяких предварительных описаний классов и т.п., на лету (но при этом это не какая-то кривая динамика, а нормальная статика со всеми проверками на этапе компиляции).
Что касается глобальных переменных, то абсолютно непонятно какие вообще могут быть к ним вопросы. Изначально очевидно (кстати, если смотреть по истории языков программирования, то ведь изначально только такие переменные и были же), что они позволяют оптимизировать и размер кода и его эффективность. Однако они хорошо подходят не для всех сущностей, а только для существующих в одном экземпляре и на всём протяжение жизни данного модуля.
Re[4]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, achp, Вы писали:
IT>>Я не то что подкатывал, но даже несколько раз понимал. A>Мне почему-то сразу вспомнился анекдот про поручика Ржевского («Мадам, разрешите вам впердолить!»)
Странно. Тут все же явно напрашивается анекдот
- Бросить курить? Да это очень просто, уж поверьте мне, я сколько раз уже бросал!
Re[2]: Есть ли вещи, которые вы прницпиально не понимаете...