Re[27]: Портирование нитры.
От: novitk США  
Дата: 16.02.17 17:44
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>При этом в любом языке где можно доказать завершимость можно доказать зевершимость функции Аккерманна.

При чем здесь Ackermann? Я говорю лишь о наличие контроля, тотальность всего лишь один из его видов. Вывод типов в Джаве/Шарпе не тормозит потому что там в системе типов ничего нельзя. В Скале позволено больше и получаем тормоза.
Re[40]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 17:51
Оценка:
Здравствуйте, novitk, Вы писали:

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


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

N>Поэтому меня надо слушать, а вас нет.


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

VD>>И тут получается, что тот же Немерл это и есть вывод типов как в OCaml или Haskell, только в чем-то немного мощнее, но менее обобщеннее.

N>LOL на "чем-то немного мощнее". Вы же простейший пример из Питона, C++, Скалы, Хаскеля повторить не можете.

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

Алгоритм вывода типов немерла имеет только два недостатка:
1. Он выводит только конкретные типы (хотя и наиболее близкий общий).
2. Он довольно медленный.

Зато он умеет выводить типы из использования. Это дает возможность писать код практически не прибегая к указанию типов, даже если типы могут быть выведены только сильно после использования. Классический пример — работа с хэш-таблицей:
def print(ht /* выводит : Dictionary[string, int] */, key /* выводит : string */) /* выводит : void */
{
  System.Console.WriteLine(ht[key]) // выводит перегрузку WriteLine(value : int) : void
}
def ht = Dictionary(); /* выводит : Dictionary[string, int] */
ht.Add("sss", 42);
print(ht, "sss");


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

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

N>В плюсовых авто-лямбдах и шаблонах нет никакой статики.

Ну, это уже какой-то махровое дилетантство. Иди разберись в терминологии. Динамика — это когда типы известны только в рантайме. В С++ — это, очевидно, не так. Все типы становятся известны во время компиляции (статически).

Другое дело, что в С++ используется утиная типизация. По сути типизация идет уже в контексте конкретной подстановки. Шаблоны раскрываются как мкросы и уже полученный АСТ компилируется.

N>Для статики в плюсах нужно ждать концепты и оно имхо не масштабируется как типклассы, но тут я не уверен. Пусть alex_public примерчик на них перепишет, будем смотреть.


Концепты тут не добавят гибкости и вообще ничего не изменят. Они просто позволят проверить типы еще до подстановки. Все будет по старому. Зато сообщения об ошибках компилятора можно будет получить еще до подстановки шаблона. И IDE будет работать качественнее.

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

VD>>Собственно обе фичи можно сэмулировать шаблонами. Вот только на практике не нужно.

N>"сэмулировать" можно все на свете, только здесь ничего "эмулировать" не нужно. Красивое решение уже есть.

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

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

В плюсах же генерируется по две специализации для лямбды с арифметкиой и для фолда (агрегейта). Так что ты в корне не прав. В плюсах статика, а в Питоне динамика, но результат один и тот же.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[40]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 18:12
Оценка:
Здравствуйте, novitk, Вы писали:

N>Решает, только по сравнению с Хаскелем это очень нетривиальные костыли с грязью. Пока не появились нормальные подсказки в IDE вообще был мрак.


Потому все и говорят, что Скала перегружена.

N>Никакого "позже" там нет, тайпкласс появляется сразу. "+" и "*" его тривиально выводят.

N>Prelude> :t myFunc
N>myFunc :: Num a => a -> a -> a

А, т.е. ты о Num говорил? Но чем это от просто типа отличается?

Вот будь в дотнете такой Num и никакие тайпклассы не понадобились бы.

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

N>Правильно, потому что система типов в .NET говно, как и в Джаве, с иерархией прибитой гвоздями.


Не то чтобы уж совсем говно, но вот этот момент упущен.

N>Поэтому в Скале сделали свою и implicit.


Кривой кастыль. Учитывая, что Скала генерирует специализации — еще и не нужный костыль.

N>В Хаскеле все просто, видишь fmap -> Functor, видишь fold -> Foldable, видишь "+" -> Num.

N>Все это комбинируется как угодно по желанию левой пятки, пример: https://wiki.haskell.org/Num_instance_for_functions

Я в курсе. Но в данном случае все это не надо. Это надо для подключения fold-а к чему-то отличному от списка, для чего функция fold не написана. И к сожалению, это не бесплатно. Они там в рантайме какую-то информацию таскают.

N>OMG! myFunc ^ может быть на две страницы, то есть твое "я просто напишу две лямбды" не катит.


Если это большая функция, то какая проблема обобщить в ней арифметику передав для этого функцию в параметре?

N>В настоящий момент в мейнстриме мы имеем или полную динамику в плюсах


Что?

N>или костыли из дополнительных параметров как ты предложил ниже.


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

А если это лямбда, то она будет конкретной, так как их всегда подставляют по месту.

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

Именно по этому данный пример является высосанной из пальца пенесометрией и никак не демонстрирует реальные преимещества языка.

Вот на С++ с этим примером проблем нет, но только полный маньяк будет утверждать, что С++ хорош для задач автоматизации, для которых обычно и применяют скрипты. А вот применение Немерла для автоматизации вполне оправдано и показала на практике отличные результаты.

N>>>Например в линейной алгебре где матрицв может быть над полем R или C. Или в растровой графике где идет параметризация алгоритма по colorspace.

VD>>Ну, вот дай мне ссылку на реальный проект. Хоть посмотрю на это чуду. Только что-то подсказывает мне, что ссылки не будет.
N>https://github.com/boostorg/ublas/blob/develop/include/boost/numeric/ublas/lu.hpp

Ну, и где там арифметика с цветами? Или что ты там хотел показать?

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

N>Это костыли и компромисс. Напомню про цель — "статика так же удобна как динамика".


В вашем любоимо С++ 90% сделано через костыли и компромисы. И тут вдруг пошла борьба с компромиссами для совершенно высосанного из пальца случая.

В конкретных случаях всегда можно придумать более интересные решения. Вот для тех же матриц можно придумать вот такое:
http://omega.sp.susu.ru/books/conference/PaVT2011/full/117.pdf

Можно такое сделать на С++ или Питоне?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[24]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 18:37
Оценка:
Здравствуйте, novitk, Вы писали:

N>У тебя эта первая часть продолжает быт turing-complete?


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

N>Если да, то что мешает иметь в ней тормоза?


То что 99% года дует на на языке общего назначения, а на ЯЗС. А он не позволяет зациклиться и обеспечивает расчет за линейное время.

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

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

Так что основной проблемой макроса становится не ошибки, а просто большой объем действий, которые ему нужно сделать. Во время компиляции — это не критично, так как 1-2 секунды не особо напрягают. А вот в режиме IDE это может стать проблемой.

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

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

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

N>Например макро, которое будет выводить поля в типе из метаданных таблицы DB, разве не будет иметь IO в первой части?


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

Можно сделать некий вочдог, который будет пасти изменение структуры БД и запускать перечитывание символов и полную перетипизацию всего проекта. Учитывая, что происходить это будет карйне редко, программист не будет испытывать никаких проблем с этим даже если этот процесс окажется не самым быстрым.

В результате же работы такого макроса будут загружены символы не отличимые от тех, что будут загружены из внешних библоитек или получены из исходников. Так что дальнейшая работа с ними будет единообразной и не будет влиять на скорость работы IDE.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[35]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 18:39
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Это деталь реализации. Никто не мешает компилятору хаскеля генерировать специализации на каждый чих.


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

Так то понятно, что можно сделать как в С++. Но при этом получается не совсем гибкое решение.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[41]: Портирование нитры.
От: novitk США  
Дата: 16.02.17 19:13
Оценка:
Здравствуйте, VladD2, Вы писали:

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

Про улучшенный вывод типа в Н я тоже наслышан, но ты зачем то сравнился с Хаскелем, где вывод типов работает тупо всегда и везде кроме экспериментальных расширений системы типов в отличие от Немерле. Сравнил бы с той же скалой, вопросов бы не было.
import qualified Data.HashTable.IO as H
main = do
     ht <- H.new
     H.insert ht "sss" 42
     print ht

Типов нет вообще, ht создается до вставки, все как у тебя. Предваряя, не надо мне объяснять про невозможность в ХМ использовать подтипы из ООП, я тут тоже в курсе.
Re[33]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 19:32
Оценка: 6 (1)
Здравствуйте, DarkEld3r, Вы писали:

DE>Это работает в обе стороны: С++ сейчас нужен или из-за легаси, которое выкинуть жалко или там, где не подходит GC. Можно, конечно, рассказывать как люди ошибаются, но это, вряд ли, на что-то повлияет. А там, где устраивает GC возьмут другой язык и всё.


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

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

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

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

Возьмем к примеру работу компилятора. Вот парсим мы файл. Мы можем создавать временные объекты в приватной куче потока, а АСТ в специальной куче создаваемой явно корневой функцией парсера. Выразить это можно так:
heap AstHeap { accessibility: thread; }

class Parser
{
  [GC(Temp(CollectAfterReturn), AstHeap(CollectAfterReturn))]
  public Parse(text : string) : AstHeap#Ast
  {
    ...
    def root = new AstHeap#Root();
    ...
    def stringBuilder = ...; // stringBuilder ссылается на приватную кучу потока
    // указываем ToString, что нужно создать строку в куче "AstHeap":
    root.RootNamespace = new AstHeap#Namespace(stringBuilder.ToString[AstHeap#]()); // ОК
    root.RootNamespace = new AstHeap#Namespace(stringBuilder.ToString()); // Ошибка! Строка в другой куче!
    root.RootNamespace = new Namespace(stringBuilder.ToString()); // Ошибка! Namespace не в той куче!
  }
}

Фактически куча AstHeap в данном примере (на псевдокоде) это пул в котором вообще не надо производить сборку мусора, а все объекты из временной кучи умрут после завершения метода Parse, так что их сборка не будет ничего стоить. Все что нам нужно сделать, чтобы рантайм не валял дурака и не собирал мусор во время работы метода Parse — это пометить метод Parse неким атрибутом. В данном примере это атрибут:
  [GC(Temp(CollectAfterReturn), AstHeap(Never))]

Он говорит ратнайму, что в методе Parse:
1. Допустимо использовать только две кучи:
* Temp — стандартная приватная куча потока.
* AstHeap — специализированная куча в которую попадают только узлы AST.
2. CollectAfterReturn — говорит, что мусор из кучи (для которой он указан) нужно собрать только после выхода из метода Parse или при нехватке памяти в систем (что в нормальных условиях не случится). Другими словами, данный атрибут запрещает сборку мусора внутри метода и заставляет рантайм собрать его после выхода. Рантайм может произвести сборку мусора нулевого поколения до входа в функцию и позволить потоку гадить только в нулевое поколение. Таким образом после выхода из функции сборка мусора будет практически бесплатна.
3. Never — говорит, что мусор из кучи (для которой он указан) не нужно собирать вовсе. Мы заранее знаем, что мусорных объектов в AstHeap помещаться не будет. Стало быть и собирать его не следует.

В AstHeap могут быть ссылки только на объекты внутри этой же куче, на объекты из глобальной кучи, на уникальные объекты (размещаемые в куче уникальных объектов) и на объекты из кластера куч, если куча добавлена в кластер.

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

Так мы можем создать кластер для символов (и прочих объектов создаваемых во время типизации) и размещать ссылки на них в объектах размещенных в кучах входящих в кластер. Это позволяет нам императивно менять менять АСТ гарантируя, что в него попадут ссылки только на объекты из кластера.

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

DE>Кстати, в D, на данный момент, это самое отключение ведёт к невозможности использовать многое из стандартной библиотеки. Сейчас идут какие-то подвижки в этом направлении, но долгоe время не заморачивались, что ещё раз говорит о не слишком удачном позиционировании языка (как замену С++).


Скорее это говорит о том, что нет особого смысла отключать GC. Надо тебе жить без него — используй объекты размещаемые на стеке.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Портирование нитры.
От: novitk США  
Дата: 16.02.17 19:57
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>То что 99% года дует на на языке общего назначения, а на ЯЗС. А он не позволяет зациклиться и обеспечивает расчет за линейное время.

Интересно. На ЯЗС посмотрю еще раз.

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

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

VD>Типизация же по верхам (как мы это называем) позволят производить только те расчеты, что нужны для работы IDE, а всю действительно тяжолую работу откладывать на потом (на стадию компиляции).

Готов поверить.

N>>Например макро, которое будет выводить поля в типе из метаданных таблицы DB, разве не будет иметь IO в первой части?

VD>Такой макрос просто будет отрабатывать в время загрузки типов из внешних сборок. Так что во время редактирования кода эти типы уже будут загружены.
Почему опять внешние сборки? Нитра, 2017 год, WTF? Я хочу вот так писать, включая в REPL:

val people = dbTable(mydb, "people")
val maxAge = people.map(_.аge).max

Ессно готов подождать на первой строчке, но не на второй.
Re[42]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 20:30
Оценка:
Здравствуйте, novitk, Вы писали:

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


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

От отсутствия классов типов или концептов С++ не становится динамикой или не статикой (что одно и тоже).

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

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

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

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


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

N>
N>import qualified Data.HashTable.IO as H
N>main = do
N>     ht <- H.new
N>     H.insert ht "sss" 42
N>     print ht
N>

N>Типов нет вообще, ht создается до вставки, все как у тебя. Предваряя, не надо мне объяснять про невозможность в ХМ использовать подтипы из ООП, я тут тоже в курсе.

А что нужно сделать, чтобы этот Data.HashTable.IO загрузить?

Мне орут:
<no location info>: error:
    Could not find module ‘Data.HashTable.IO’
    Perhaps you meant
      Data.Hashable (from hashable-1.2.5.0@hashable-1.2.5.0-D2qhjboTBST6rFOSUg03ZP)

А я в Хаскеле не силен.

Ну, можно полностью пример воспроизвести (с объявлением функции до использования)?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[26]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 21:36
Оценка:
Здравствуйте, novitk, Вы писали:

N>Интересно. На ЯЗС посмотрю еще раз.


Посмотри. Штука интересная и красивая получилась. Чем-то похоже на Хаскель (в смысле того, что все вычисления зависят друг от друга), но при этом могут считаться как лениво, так и энергично. Плюс для АСТ и символов (а это считай система типов для ЯЗС) поддерживается множественное наследование. Это позволяет производить очень качественную декомпозицию не дублируя код вовсе. Так же интересно, что мы умудрились обойтись без циклов и fold-ов/map-ов. Списки АСТ в Нитре наследуют ЗС от своих элементов, что позволяет производить вычисления над списками без циклов и функций. Просто если у элемента свойства есть ЗС, то оно появляется и у списка. Присваивание значения свойству списка передает их каждому элементу. Если надо "протащить" значение через элементы, на то есть inout-свойства. Суешь значение в in-свойство списка и оно протаскивается между каждым элементом (на вход элементу оно присваивается в in-свойство, а на выход берется из out-свойства). В итоге результат можно взять в out-свойстве списка.

При этом все ЗС, как и в функциональных языках, можно присваивать только один раз. Но выглядит это как императивное присвоение.
Вот пример типичного кода на ЗС:
// определение ветки AST производящей декларацию символа
abstract declaration Rule : RuleType, Container, SyntaxElementContainer // множественное наследование
{
  symbol // вот эта секция определяет символ
  {
    SpanClass = NitraLang.RuleSpanClass;
    Kind      = "syntax";
    Scope     = MemberTable;
  }

  // Вычисления на ЗС

  // Присвоение значения ЗС списка. Оно "протаскивает" значения между элементами.
  // Элементы могут возвращать в своем LiteralsOut-свойстве измененное значение.
  Members.LiteralsIn           = LiteralsIn;
  Members.ContainingTable      = Symbol.MemberTable;
  Members.Scope                = Scope.HideWith(Symbol.MemberTable);
  Members.Parent               = Symbol;
  Attributes.Scope             = Scope;

  // Структурные поля AST. Данные сюда попадают из дерева разбора
  Members    : RuleBodyMember*;
  Attributes : RuleAttribute*;
}


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


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

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

Конечно, это не гарантирует от тормозов вызванных большим объемов самих вычислений. Но по крайней мере проблем С++ связанных с тем, что нужно разобрать все инклюды и закэшировать результат — нет. Макра просто является скомпилированной функций. Если она не применяется в данном файле, то и не жрет время.

VD>>Такой макрос просто будет отрабатывать в время загрузки типов из внешних сборок. Так что во время редактирования кода эти типы уже будут загружены.

N>Почему опять внешние сборки? Нитра, 2017 год, WTF? Я хочу вот так писать, включая в REPL:

А Репл тут чем отличается? Ты когда в Хаскеле репл запускаешь, Хаскель тоже грузит некий набор модулей. Просто у хаскеля то что я называю сборкой называется модулем. И все. В репле хаскеля даже есть менюшка "Clear Modules". По сути это перезагрузка дефолтных модулей со сбросом состояния репла.

N>val people = dbTable(mydb, "people")

N>val maxAge = people.map(_.аge).max

N>Ессно готов подождать на первой строчке, но не на второй.


Вообще ждать не надо. И писать можно не так как у тебя, а так:
def people = MyDB.People;
def maxAge = People.Max(_.аge);

или просто:
def maxAge = MyDB.People.Max(_.аge);

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

Более того без проблем можно будет сделать и поддержку всего SQL, чтобы писать как-то так:
def maxAge = select Max(аge) from MyDB.People where name like 'A%';

В общем, это уже больше от фантазии зависит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[41]: Портирование нитры.
От: novitk США  
Дата: 16.02.17 22:02
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А, т.е. ты о Num говорил? Но чем это от просто типа отличается?

Ессно, а ты о чем думал?

VD>Вот будь в дотнете такой Num и никакие тайпклассы не понадобились бы.

По-моему ты до сих пор не догоняешь. Ты все думаешь что если MS пропишет Num в базе Double или Complex, то проблема решится. Эти классы тогда будут обобщенны, но что сделать с классом SupеrMatrix, которую ты взял у Васи?

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

VD>И в дотнете тоже дженерики сгенерировали бы специализации для фолдов сгенерили бы.
При чем тут fold? Какие нафиг специализации? Fold в этом примере всегда над листом и поэтому имеет ровно одну специализацию. Или ты про какие-то детали реализации?

VD>Это надо для подключения fold-а к чему-то отличному от списка, для чего функция fold не написана.

Это надо для всего.

VD>И к сожалению, это не бесплатно. Они там в рантайме какую-то информацию таскают.

Это вопрос реализации, тебе уже Волфхаунд сказал.

N>>OMG! myFunc ^ может быть на две страницы, то есть твое "я просто напишу две лямбды" не катит.

VD>Если это большая функция, то какая проблема обобщить в ней арифметику передав для этого функцию в параметре?
Не уверен, что мы до конца понимаем друг друга. Передавать надо не функцию, a в терминах Немерле интерфейс/трейт, скажем INumeric<Т> в котором будут определены обобщенные plus, minus и т.д.

Проблем две:
Во-первых, одна большая функция вызывает другую большую функцию в которую этот интерфейс тоже надо передавать. Комок говна растет.
Во-вторых, вместо нормальной нотации "(a+b)/2" надо писать "num.divide(num.plus(a, b), num.fromInt(2))".

N>>В настоящий момент в мейнстриме мы имеем или полную динамику в плюсах

VD>Что?
Здесь и дальше: динамика == "утиная типизация"

VD>Ну, вот и давай разберемся часто ли нужны такие костыли? Я вот что-то в своем коде не вижу такого.

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

VD>И они постоянно используются. Проблемы возникают только с арифметкой. Но ее крайне мало. И вот в тех не реально редких случаях когда это нужно, можно спокойно обойтись костылем в виде ФВП в качестве параметра такой функции.

Сделай библиотеку для линейной алгебры на Nemerle и посмотри на результат.

VD>Вот на С++ с этим примером проблем нет, но только полный маньяк будет утверждать, что С++ хорош для задач автоматизации, для которых обычно и применяют скрипты. А вот применение Немерла для автоматизации вполне оправдано и показала на практике отличные результаты.

Я согласен, но это довольно низкая планка.

N>>>>Например в линейной алгебре где матрицв может быть над полем R или C. Или в растровой графике где идет параметризация алгоритма по colorspace.

VD>>>Ну, вот дай мне ссылку на реальный проект. Хоть посмотрю на это чуду. Только что-то подсказывает мне, что ссылки не будет.
N>>https://github.com/boostorg/ublas/blob/develop/include/boost/numeric/ublas/lu.hpp
VD>Ну, и где там арифметика с цветами? Или что ты там хотел показать?
Это пример по "Например в линейной алгебре где матрицв может быть над полем R или C."

N>>Это костыли и компромисс. Напомню про цель — "статика так же удобна как динамика".

VD>В вашем любоимо С++ 90% сделано через костыли и компромисы.
Я не люблю C++. Очень неудобный язык, но когда нужна скорость вариантов нет.

VD>В конкретных случаях всегда можно придумать более интересные решения. Вот для тех же матриц можно придумать вот такое:

VD>http://omega.sp.susu.ru/books/conference/PaVT2011/full/117.pdf
VD>Можно такое сделать на С++ или Питоне?
В гугле забанили?
http://thrust.github.io/
https://devblogs.nvidia.com/parallelforall/copperhead-data-parallel-python/
https://docs.continuum.io/numbapro/CUDAJit
Re[39]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 22:05
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Сила скриптовых языков в простоте и краткости.


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

_>Что касается МП, то если в некоторых сложных проектах на Питоне оно действительно применяет, то в коротеньких скриптах (а у меня Питон работает в основном для этих целей) оно точно не требуется.


Дык МП используется не только когда ты пишешь метакод, но и когда ты используешь библиотеки. Я когда пишу "скрипты", использую кучу макросов из стандартной библиотеки. Я уже не говорю о том, что в Немерле if и foreach — это макросы, но уж такие мелкие полезняшки, как макрос Record, используются постоянно.
[Record] // добавляет конструктор включающий все поля не помеченные атрибутом RecordIgnore
class Author
{
  publuc FirstName;
  publuc SurName;
  [RecordIgnore] publuc Articles : List[Article] = List();
}


Уверен, что и Питоне тоже самое. Ты можешь даже не знать, что некоторая фича сделана через МП, но ты можешь ее использовать.

_>Да, да, в Немерле2 совершенно точно надо предоставить полноценный параметрический полиморфизм, а не это убожество (дженерики) из .net.


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

_>Кстати, с точки зрения производительности реализация из C++ естественно самая лучшая, т.к. гарантирует инлайнинг (Хаскель тут далеко отстаёт), но при этом такой подход мешает нормальной модульности. Хотя в D (где тоже шаблоны) проблему с модулями вроде как-то решили (не копался во внутренностях, так что не знаю как именно).


На самом деле модульности он не мешает. Просто надо:
1. Шаблоны компилировать в АСТ (помещать их в модули в виде аннотированного АСТ-а). Сериализовывать АСТ и символы мы уже умеем средствами Нитры.
2. Шаблоны не должны быть вычислимыми (Тьюринг-полными). Это очень важно и для скорости и для модульности.
3. Для шаблонов нужно реализовать аналог кострэйнов из дженериков или планируемых (вот уже 17 лет) концептов С++. Возможно надо подумать о том нельзя ли для этого воспользоваться идеями классов типов из Хаскеля. Но тут надо быть осторожным, чтобы фича не требовал поддержки в рантайме, раз уж шаблоны подставляются во время компиляции.

В общем, сделать нечто вроде дженериов времени компиляции с возможностью констрэйнов на все то, что не поддерживают дженерики.

Если получится хорошо бы вообще сделать шаблоны как расширение дженериков. Типа дописываем к описанию дженерик-типа ключевое слово template и получаем недостающее поведение:
template class A<T>
  where T: _+_ // T поддерживает бинарный оператор сложения
{
  public Sum(a : T, b : T) : T
  {
    a + b
  }
}
...
def x = A().Sum(40, 2);              // OK x == 42
def x = A().Sum(36, 0.6);            // OK x == 36.6
def x = A().Sum("Hello ", "World!"); // OK x == "Hello World!"
def x = A().Sum("Hello ", 42);       // Error: нет неявного приведения между числом и строкой
def x = A().Sum(A<int>(), A<int>()); // Error: A<T> не поддерживает оператор "+"
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[34]: Портирование нитры.
От: WolfHound  
Дата: 16.02.17 22:41
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Возьмем к примеру работу компилятора. Вот парсим мы файл. Мы можем создавать временные объекты в приватной куче потока, а АСТ в специальной куче создаваемой явно корневой функцией парсера. Выразить это можно так:

Может прежде чем что-то изобретать, таки изучишь то что тут написано?
Re: Мысли о эффективном автоматическом управлении памятью
Автор: WolfHound
Дата: 29.10.14

Re[2]: Мысли о эффективном автоматическом управлении памятью
Автор: WolfHound
Дата: 29.10.14

Re[2]: Мысли о эффективном автоматическом управлении памятью
Автор: WolfHound
Дата: 30.10.14

Re[2]: Мысли о эффективном автоматическом управлении памятью
Автор: WolfHound
Дата: 30.10.14

Там всё гораздо лучше продумано чем у тебя.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[43]: Портирование нитры.
От: novitk США  
Дата: 16.02.17 22:51
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я тебя не пытаюсь унизить. Сказал чушь. Я тебе на это указываю. Я не телепат и не могу знать из-за чего ты это делаешь.

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

VD>В дотнете есть сущность сходная концептам — это констрэйны на дженериках. Аналогом классов типов (в дотнете) являются интерфейсы. В купе с консрэйнами они дают нужную функциональность.

Нет не дают, для полных typeclass еще нужен implicit.

VD>Классы типов гибче тем, что их можно реализовать для внешнего типа, а интерфейсы только для вновь создаваемых. Если бы в дотнете ввели интерфейс INat, как в Хаскеле. То проблема бы решилась сама собой и классы типов для этого не понадобились.

Ну допустим он есть, как мне сделать теперь:
val a = List(1, 2, 3)
val b = List(3, 4, 5)
a * b

VD>Я особо не сравнивал с Хаскелем.

но мнение имеешь...

VD>Так, например, не поддерживаются неявные приведения типов, перегрузки и т.п.

Не нужно. В скале все это впихнули, вышло плохо.

VD>А что нужно сделать, чтобы этот Data.HashTable.IO загрузить?

сейчас нет под рукой нужного компа(*), но что-то типа:
cabal update
cabal install hashtable

VD>Ну, можно полностью пример воспроизвести (с объявлением функции до использования)?

import qualified Data.HashTable.IO as H

printKey d k = do
     v <- H.lookup d k
     print v

main = do
     ht <- H.new
     H.insert ht "sss" 42
     printKey ht "sss"

не проверял из за (*) ^!
Отредактировано 16.02.2017 22:53 novitk . Предыдущая версия .
Re[42]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 22:54
Оценка:
Здравствуйте, novitk, Вы писали:

N>Ессно, а ты о чем думал?


Я думал ты о Foldable говоришь.

N>По-моему ты до сих пор не догоняешь. Ты все думаешь что если MS пропишет Num в базе Double или Complex, то проблема решится. Эти классы тогда будут обобщенны, но что сделать с классом SupеrMatrix, которую ты взял у Васи?


Num должен быть просто интерфейсом. В нем должны быть методы Add(), Sub(), Mul, Div() и т.п. Тогда создатель SupеrMatrix просто его реализует и я смогу использовать его там где ожидается Num. А если даже не реализует, я смогу создать наследника SupеrMatrix и реализовать интерфейс для него.

Я как бы согласен, что классы типов хороши тем, что их можно описать независимо от типа. Но и внесение интерфейса Num решило бы проблему с арифметикой.

N>При чем тут fold? Какие нафиг специализации? Fold в этом примере всегда над листом и поэтому имеет ровно одну специализацию. Или ты про какие-то детали реализации?


При том, они будут работать со списками разных типов, и если типы — это вэлью-типы (не ссылочные), то надо генерировать разные специализации.

Дотнет так и поступает, если функция принимает интерфейс (или класс) один из параметров типов которого является вэлью-типом.

VD>>И к сожалению, это не бесплатно. Они там в рантайме какую-то информацию таскают.

N>Это вопрос реализации, тебе уже Волфхаунд сказал.

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

N>Не уверен, что мы до конца понимаем друг друга. Передавать надо не функцию, a в терминах Немерле интерфейс/трейт, скажем INumeric<Т> в котором будут определены обобщенные plus, minus и т.д.


Можно просто вынести зависящий от типа аргументов кусок кода в функцию:
SomeBigMethod(xs : Seq[T], alghoritm : T * T -> T) : T
{
  // много кода
  foreach (x in xs)
  foreach (y in ys)
    DoSome(alghoritm(x, y));
  // много кода
}

SomeBigMethod([1, 2, 3],       (x, y) => (x + y) / 2);
SomeBigMethod([1.1, 2.1, 3.3], (x, y) => (x + y) / 2.0);


N>Во-первых, одна большая функция вызывает другую большую функцию в которую этот интерфейс тоже надо передавать. Комок говна растет.

в случае применения паттерна описанного выше этой проблемы нет.

N>Во-вторых, вместо нормальной нотации "(a+b)/2" надо писать "num.divide(num.plus(a, b), num.fromInt(2))".

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

N>Здесь и дальше: динамика == "утиная типизация"


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

N>Потому что ты не пишешь библиотеки параметризуемые дженериками, а только используешь. Ну и не до конца вкурил FP


Ну, почему же? Приходится иногда.

N>Сделай библиотеку для линейной алгебры на Nemerle и посмотри на результат.


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

VD>>Вот на С++ с этим примером проблем нет, но только полный маньяк будет утверждать, что С++ хорош для задач автоматизации, для которых обычно и применяют скрипты. А вот применение Немерла для автоматизации вполне оправдано и показала на практике отличные результаты.

N>Я согласен, но это довольно низкая планка.

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

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

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

По факту это демонстрация пары фич действительно удачно реализованных в С++ и Питоне. При этом другие языки из этих классов данных фичей могут и не иметь.

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

Ну, и главное, что мы не можем взять фичи всех перечисленных языков для реализации своих задач. В Питоне будет недоставать скорости кода и статических проверок. В С++ придется тратить много усилий чтобы следить за правильным использованием памяти, да и код получается более громоздкий. В Хаскеле жопа с императивом. Вот и воходит, что языки типа Немерла (Ну, может еще Котлина и Скалы) — это некий компромисс. Эдакий Гиви Абрамович Чингачгук (из одного анекдота, в котором еврей хотел понравиться группе девушек с разными вкусами). И у него это неплохо получается. Меня реально не тянет взять Питон.

Но, конечно, минусы есть. Вот один из них тут показали. Я могу и сам привести ряд других по мере значимости (для меня):
1. Медленная компиляция (компилятора). Почти уверен, что Н2 ее решит. Там в основном виноват вывод типов. На базе ЗС он должен получиться лучше.
2. Более медленное исполнение кода. Оно в основном вызвано худшей оптимизацией кода и джит-компиляцией. Последнее решается ngen-ом. А вот первое требует смены кодогенератора. МС 10 лет не может этой проблемой заняться всерьез. Ну, естественно, вносят свою лепту рантайм-проверки и разные мемори-барьеры, нужные для устранения пауз GC. По каждому из вопросов есть идеи как их решить. Но все это требует наличия собственного рантайма с собственной кодогенерацией и тюнинга работы с GC. Что касается конкретно GC, то большие надежды на локальный GC. Кроме ускорения и возможности отказаться от мемори-барьеров (в некоторых случаях) это так же позволяет привнести в язык дополнительный контроль за временем жизни объектов и лучше контролировать повисшие ссылки (когда объект по логике автора должен был умереть, но по ошибке жив).
3. Клюки и тормоза в IDE.
4. Побочные эффекты от работы макросов (об этом я тут рядом уже писал).
5. Не бесплатность лямбд и замыканий. В Немерле для них зачастую создаются объекты, что дороже, чем императивный подход.
6. Не гибкость дженириков. Причем этот не просто самая последняя по списку проблема. На практике она вообще мало значима. Хотя, я и не отказался бы иметь быстрые дженерики с улучшенными констрэйнами или шаблоны.

N>Я не люблю C++. Очень неудобный язык, но когда нужна скорость вариантов нет.


Вообще-то есть С и Ди.

VD>>В конкретных случаях всегда можно придумать более интересные решения. Вот для тех же матриц можно придумать вот такое:

VD>>http://omega.sp.susu.ru/books/conference/PaVT2011/full/117.pdf
VD>>Можно такое сделать на С++ или Питоне?
N>В гугле забанили?
N>http://thrust.github.io/
N>https://devblogs.nvidia.com/parallelforall/copperhead-data-parallel-python/
N>https://docs.continuum.io/numbapro/CUDAJit

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

Это примерно тоже самое, что на твои претензии с арифметикой в дженериках со сылкой на шаблонную их реализацию на С++, дать ссылку на готовую библиотеку умножения матриц для дотнета, да еще и написанную на С.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[35]: Портирование нитры.
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.17 23:02
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Возьмем к примеру работу компилятора. Вот парсим мы файл. Мы можем создавать временные объекты в приватной куче потока, а АСТ в специальной куче создаваемой явно корневой функцией парсера. Выразить это можно так:

WH>Может прежде чем что-то изобретать, таки изучишь то что тут написано?

Это и есть "что-то изобретать".

WH>Там всё гораздо лучше продумано чем у тебя.


Любишь ты себя любимого похвалить.

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

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

Синтаксические решения там не самое важное. В реальности они все изменятся, так как изменились решения в том же парсере и АСТ-е. Важно продумать способы использования на практике. Задачи то разные бывают, и решение должно быть универсальным, накрывающим разные случаи использования.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[36]: Портирование нитры.
От: WolfHound  
Дата: 16.02.17 23:25
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Любишь ты себя любимого похвалить.

Ну что поделать если я два года назад придумал решение, которое лучше твоих фантазий.
Как ты будешь передавать кучу в метод?
А возвращать из метода?
А передавать в другой поток?
А объединять две кучи?
А выводить что в какой куче лежит? Ибо захламлять код всяким мусором типа указания кучи явно не наш метод.
У меня всё это прописано. А у тебя даже намёков нет.

VD>Синтаксические решения там не самое важное. В реальности они все изменятся, так как изменились решения в том же парсере и АСТ-е. Важно продумать способы использования на практике.

А я и не про синтаксис говорю. Там ещё и механика всего этого дела расписана.

VD>Задачи то разные бывают, и решение должно быть универсальным, накрывающим разные случаи использования.

Любая система типов отсекает некоторое множество решений.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[33]: Портирование нитры.
От: alex_public  
Дата: 17.02.17 05:08
Оценка:
Здравствуйте, DarkEld3r, Вы писали:

DE>Это работает в обе стороны: С++ сейчас нужен или из-за легаси, которое выкинуть жалко или там, где не подходит GC. Можно, конечно, рассказывать как люди ошибаются, но это, вряд ли, на что-то повлияет. А там, где устраивает GC возьмут другой язык и всё.


Не только там, где не подходит GC. На самом деле всё достаточно просто: любые вменяемые команды предпочитают работать только с мейнстрим языками — это обеспечивает вменяемую инфраструктуру (библиотеки, инструменты, сообщество). Так вот из нативных (т.е. не требующих отдельной установки специального рантайма и позволяющих эффективно работать с системным API на любой платформе) языков у нас к мейнстриму сейчас относятся наверное всего четыре: C, C++, Go, Swift. Но Swift вычёркиваем сразу, если мы не хотим ограничиться мирком Apple. Из оставшихся: Go — имеет слабую кроссплатформенность и быстродействие, C — неудобный и небезопасный язык. И оба они отстают от C++ по набору библиотек и возможностям языка. Так что выбор как бы очевиден.

DE>Кстати, в D, на данный момент, это самое отключение ведёт к невозможности использовать многое из стандартной библиотеки. Сейчас идут какие-то подвижки в этом направлении, но долгоe время не заморачивались, что ещё раз говорит о не слишком удачном позиционировании языка (как замену С++).


Не надо там ничего отключать. Достаточно его просто не использовать и всё.
Re[40]: Портирование нитры.
От: alex_public  
Дата: 17.02.17 05:38
Оценка:
Здравствуйте, novitk, Вы писали:

N>В плюсовых авто-лямбдах и шаблонах нет никакой статики. Для статики в плюсах нужно ждать концепты и оно имхо не масштабируется как типклассы, но тут я не уверен. Пусть alex_public примерчик на них перепишет, будем смотреть.


Да не будет там ничего интересного. Если взять скажем этот http://rsdn.org/forum/philosophy/6698765.1
Автор: alex_public
Дата: 14.02.17
примерчик, то с концептами он станет выглядеть как-нибудь так:
template<typename T> concept bool MyNum=requires(T a, T b) { {a+b}->T; {a/b}->T; };
//..
list<double> v={1.0, 2.0, 3.0}; //список
set<int> s={1, 2, 3, 3}; //множество
auto f=[](const MyNum& s, const MyNum& x) {return (s+x)/2;}; //MMA
cout<<accumulate(v.cbegin(), v.cend(), 0.0, f)<<' '<<accumulate(s.cbegin(), s.cend(), 0, f)<<endl; //выводит 2.125 2

что на мой взгляд не добавляет ни красоты, ни безопасности. Единственная разница будет в сообщениях об ошибках. Если мы попробуем вместо коллекции чисел использовать в таком коде коллекцию строк, то в первом варианте получим такое сообщение об ошибке:
error: no match for 'operator/' (operand types are 'std::__cxx11::basic_string<char>' and 'int')
  auto f=[](const auto& s, const auto& x) {return (s+x)/2;}; //MMA
                                                  ~~~~~^~

а во втором варианте такое:
error: no matching function for call to 'main()::<lambda(const auto:9&, const auto:9&)>::operator()(const std::__cxx11::basic_string<char>&, const std::__cxx11::basic_string<char>&) const'
note: candidate: main()::<lambda(const auto:9&, const auto:9&)> [with auto:9 = std::__cxx11::basic_string<char>]
note:   constraints not satisfied
note: within 'template<class T> concept const bool MyNum<T> [with T = std::__cxx11::basic_string<char>]'
 template<typename T> concept bool MyNum=requires(T a, T b) { {a+b}->T; {a/b}->T; };
                                   ^~~~~
note:     with 'std::__cxx11::basic_string<char> a'
note:     with 'std::__cxx11::basic_string<char> b'
note: the required expression '(a / b)' would be ill-formed

И я бы не сказал, что второй вариант мне нравится сильно больше первого. )))
Отредактировано 17.02.2017 5:40 alex_public . Предыдущая версия . Еще …
Отредактировано 17.02.2017 5:39 alex_public . Предыдущая версия .
Re[41]: Портирование нитры.
От: alex_public  
Дата: 17.02.17 06:34
Оценка:
Здравствуйте, VladD2, Вы писали:

N>>"сэмулировать" можно все на свете, только здесь ничего "эмулировать" не нужно. Красивое решение уже есть.

VD>Далеко не все. Не говори глупости. Например, С++-ное решение нельзя поместить в обобщенный указатель на функцию и вызвать для разных типов используя приведение типов. А Питоне же с этим проблем не возникнет.

Ну вообще то в C++ это тоже элементарно делается, только уже чуть по другому:
typedef any<ostreamable<>, const _self&> printable;
function<void(printable)> current_printer;
void Test() {current_printer(1); current_printer(1.0); current_printer("1"s);}
//...
current_printer=[](printable x) {cout<<x<<endl;};
Test();
current_printer=[](printable x) {cout<<"\t"<<x<<endl;};
Test();

Это кстати весьма близко к внутреннему устройству Хаскеля.

Кстати, на C# и Java подобное тоже конечно же элементарно записывается, но будет работать в динамике (а тут всё статично) через тормозную рефлексию.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.