stdray: (pic#896193)
Написал, точнее переписал (процесс продолжается) весь слой загрузки данных из внешних стрёмных источников. Переписал не из чувства прекрасного, а по следующим причинам:
1. целиком и полностью изменилось внутренне представление данных
2. невозможно поддерживать существующий код
3. невозможно анализировать работу существующих процессов загрузки

Я с некоторых пор не любитель писать с нуля, но здесь вынужденно во все тяжкие. И если с первым пунктом все понятно, то про два других подробней. Это про то, почему «написал», а не «переписал». )
stdray: (Default)
Часто слышу от своих знакомых, программирующих на C# и использующих ReSharper, что едва ли не самой полезной возможностью решарпера является проверка стиля кодирования. То есть решарпер проверяет правильность именования переменных, всякие там Pascal Casing для имен типов, Camel Casing для переменных и прочее такое. В этом есть смысл, поскольку многие программисты style guide не читают, а я читал, но почти ничего не помню. И тоже полагаюсь на ReSharper, хоть и регулярно возникают с ним разногласия.

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

[MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Assembly)] \

macro CapitalTypeNames(alertType : string)

NameConventionImpl.CapitalTypeNames(Macros.Manager(), alertType)


А при его вызове, собрать типы, объявленные в сборке, отфильтровать имеющие некорректные названия и вывести информацию указанным образом. Read more... )
stdray: (Default)
Пока в сети продолжаются споры от том нужны DSL или не очень, я решил разобраться, как на макросах Nemerle реализуются встраиваемые языки. Потребность такая может возникнуть, даже при наличии макросов, расширяющих синтаксис языка. Дело в том, что менять правила лексера и препарсера нельзя, а значит определенные последовательности символов будут невалидными, например непарные скобки, хотя я подозреваю, что ими ограничения не исчерпываются. Для выхода из ситуации используются рекурсивные строки, внутри которых пишется код на интересующем языке, а потом транслируется в AST Nemerle. Подобным образом реализованы xml-литералы и linq query syntax.

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


Реализация МИКРОБЕЙСИКА )
stdray: (Default)
Бывает, ради эксперимента пишу какие-то макросы, чтобы разобраться что позволяет макро-подсистема Nemerle, а что - нет. Если будет получаться что-то забавное, стану выкладывать это сюда.


Расширяемые анонимные типы

По мотивам хотелок [personal profile] metaclass. На сколько я понял, ему нужны анонимные типы, которые можно расширять, добавляя новые элементы, а также передавать за пределы той области видимости, в которой они были объявлены. В языке Nemerle нет анонимных типов, однако ими все пользуются, поскольку они реализованы через макросы.

def obj = new(name = "anon", age = 10, created = DateTime.Now);


В общий чертах, работает это так: макрос new по переданным параметрам генерирует генерик-класс с макро-атрибутом [Record] вида

[Record] class AnonType[name, age, created] {

public name : name;

public age : age;

public created : created;

}


Макрос [Record] создает конструктор с аргументами для всех полей, а потом вызов макроса переписывается в конструктор только что созданного класса.
После раскрытия макроса new
Read more... )
stdray: (Default)
Решил посмотреть, чем ребята из соседнего комьюнити F# в плане unit-тестов промышляют. И нашел вот такой шаблон проекта. Скачал, установил, стал смотреть, чего там в файле проекта такого особенного. А ничего! То есть вообще самый обычный проект библиотеки классов!

Ну ок, качаю сборку Nemerle для 2012 студии. Это кстати оказалось труднее, чем я думал. Самое новьё сейчас доступно по ссылке http://tc.rsdn.ru/, там надо выбрать интересующую платформу и версию студии, потом выбрать последний удачный билд и на вкладке Artifacts уже можно забрать желанный msi. Я какбэ с TeamCity никогда не сталкивался, потому достаточно долго разбирался что и где.

Ладно, поставил Nemerle и интеграцию с 2012 студией. Создал проект библиотеки, добавил в зависимости уже поднадоевшую VisualStudio.QualityTools.UnitTestFramework.dll, написал два теста, собрал и... ВСЕ ТЕСТЫ ПОЯВИЛИСЬ САМИ. И даже отладка доступна и вообще все робит из коробки. То есть, я там вытанцовываю с бубном вокруг студии в стиле прыщавого админа, а прогресс рядом. MS, видать, переработали систему, избавившись от тех невменяемых ограничений и теперь все хорошо.

Правда, сама интеграция Nemerle с 2012 студий пока нестабильна, хотя большую часть времени работает весьма сносно. И я как-то побаивался переходить, но, думаю, безгеморройные тесты являются весомым аргументом.
stdray: (Default)
Написал про вуду-тесты для Nemerle в студии и уже хотел смотреть зомбоящик, как внезапно в голову пришла мысль, что возможно студия фильтрует проекты с тестами банально по расширению файла проекта. А ради совместимости с сишарповским тулзами Nemerle умеет компилировать достаточно большое подмножество C# и, соответственно, работать с проектами csproj.

Отлично, как и в прошлый раз создаю немерлевую библиотеку, добавляю Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll, пишу тесты. Компилирую - все собирается. Теперь удаляю проект из решения. Меняю ему расширение с .nproj на .csproj. Открываю файл проекта в текстовом редакторе и в самую первую секцию PropertyGroup копирую:

<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>


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

Отличия от предыдущего метода:
1) Там есть лишний проект, тут - нет
2) Там нельзя дебагером отлаживать тесты, тут - можно.
3) Там работал немерлевый автокомлит, тут - нет.

Я думаю, что так-то поудобней будет. Даже с учетом того, что автокомплит поломался. Но может и этот вопрос решаемый.
stdray: (Default)
Для написания unit-тестов я пользуюсь стандартными студийными возможностями - "Создать тестовый проект Visual C#" и пихаю туда тесты (суть классы и методы помеченные специальный атрибутами). Я не то чтобы фанат тестирования, просто писать тесты быстрее и проще, чем каким либо иным способом проверять написанную функциональность. И хотя я понимаю, что надо бы прочитать что-то про разработку через тестирование, про лучшие средства для него и тд, текущее положение дел меня вполне устраивает.

Однако, этот подход перестает работать, если пишешь код на чем-то отличном от C#/VB.NET/C++.NET, поскольку то ли в студию, то ли в mstest зашито данное ограничение. И хоть писать тесты на C# вполне приемлемо, это сильно раздражает. Как вообщем-то и ставить какие-то сторонние тулзы вроде NUnit большого желания нет, поскольку, во-первых, я уже привык к студийным возможностям вроде ведения списков тестов, ко всяким связанным с ними окошкам, а, во-вторых, предпочитаю по мере возможности пользоваться средствами из коробки.

Вообщем, мне надоело писать тесты к Nemerle на C# и я решил разобраться в проблеме. И хочу рассказать про вуду-решение, подходящее не только для Nemerle, но и для любых других языков .Net, не заапрувленных MS, вроде того же F#.

Первое, надо добавить в решение проект библиотеки на Nemerle (в моем случае это Nemerle.Mixins.Tests). К ней в зависимости добавить Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll, открыть соответствующее пространство имен и написать пару тестов. Что-то вроде такого:

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]

public class SimpleTest {

[TestMethod] public Fail() : void { Assert.IsTrue(1 == 2); }

[TestMethod] public Win() : void { Assert.IsTrue(1 == 1); }

}


Read more... )
stdray: (Default)
В вики Nemerle существует вот такая страничка, на которой рассказывается, как могли бы вести себя трейты, будь они реализованы в языке. Но пока что "not yet done", хотя тема неоднократно поднималась на форуме. Как я полагаю, это все следствие размышлений на тему "Как бы нам вернуть обратно множественное наследование". То есть сейчас в дотнетах оно есть, но в значительно урезанном виде: интерфейсы позволяют наследовать только требования к объектам, а уж реализацию приходится пилить вручную, что конечно же раздражает.

Мне в этом описание понравилась идея выставлять требования для объектов, к которым возможно "подселять" трейты. Однако, мне не очень нравится идея реализовывать это дело внутри интерфейсов, поскольку такой объект будет некорректным с точки зрения, допустим, C#. К тому же такие трейты не смогут иметь собственное состояние, что очень сильно ограничивает варианты их использования.

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

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

[DefMixin]

public module Foo {

public interface Require {

getX() : int;

setX(v: int) : void;

}

public class Provide[T] where T: Require {

public inc() : void { self.setX(self.getX() + 1); }

}

}


Узнать больше про примеси в Nemerle )
stdray: (Default)
[personal profile] xeno_by написал, что макры для скалы почти вот-вот будут готовы. А люди как-то не очень радуются. Я почитал комментарии, мне что-то не понравилось такое обсуждение.


Макросы - это признание поражения. "Наш язык оказался недостаточно хорошо, нам придется генерировать программы на нём, чтобы продолжать притворяться, что мы пишем на нём".

Во-первых, тут явно подразумевается, что кодогенерация является чем-то плохим и доказывает несостоятельность языка, как средства для написания программ. Из моего ежедневного: редактировать форму мне удобней в графическом дизайнере, просматривать схему базы данных и редактировать связи между таблицами опять же удобней в графическом представлении. По-моему, очевидно, что если существуют разные способы выполнить одну работу, то надо выбирать самый удобный. И либо у нас есть серебряная пуля, либо для каждой задачи существует свой самый удобный инструмент. А чтобы это все как-то между собой взаимодействовало о совмещалось, надо приводить к одному знаменателю. Например, к текстовому представлению в виде кода на определенном языке программирования. Этот способ не единственный, но, на мой взгляд, достаточно практичный и удобный.
Read more... )
stdray: (Default)
Меня преследуют странные мысли о полиморфизме высших порядков (rank-2 и rank-n) и тайпклассах. Мне привиделось, что можназделоть что-то такое на макросах в Nemerle и теперь голова этим забита. То есть какой-то синтаксис, например poly

        def t1 = poly T[_];         // T1 [ T2 ] 
        def t2 = poly T[_  , _];   // T1 [ T2, T3 ] 
        def t3 = poly T[int, _];   // T1 [int, T2] 

по ентой записи делает представление . Примерно как дотнеты хранят как-то информация о generic-параметрах

        WriteLine(typeof(Dictionary.[_,_]));
       //System.Collections.Generic.Dictionary`2[TKey,TValue]
        WriteLine(typeof(Dictionary.[string,int]));
       //System.Collections.Generic.Dictionary`2[System.String,System.Int32]

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

        def с1 = t1 apply [List]; // List[T2]
        def r1 = с1 apply [int];  // List[int]

И у apply должен быть тип PolyType -> YobaType, где YobaType - это тип-вариант из PolyType (если у нас все еще слишком неконкретные для дотнета типы) и System.Type (когда тип стал конкретным, надо бы его прямо в код поставить).

И надо сделать такие вот тайпклассы

    typeclass Functor [ poly C[_] ] {
         abstract fmap[a,b](f: a->b, c: C[a]) : C[b];
    }
 

И все это дело будет превращаться в контейнер с квази-циатами. Будут хранится типы-параметры в виде YobaType, будут хранится сигнатуры методов, а также тела методов, если они не объявлены как abstract. И затем можна будет использовать все это дело каким-то макро аттрибутом вроде

    [ instance Functor[List] ]
    module ListF {    }
 

И тогда в ентот модуль ListF будут переписаны, все методы из Functor, сигнатуры будут конкретизированы List. Для методов помеченных abstract в базовом классе будет выдана ошибка с требованием реализовать такой-то метод. Методы, имеющие тела в базовом классе, будут переписаны в дочерний, если в том уже не содержится метод с данным именем и данной сигнатурой. Понавешать атрибутов [instance] на один модуль можно много, потому могут возникать конфликты. На самом деле, это не так серьезно, как может показаться, поскольку Nemerle умеет в перегрузку методов (в отличии от некоторых), потому конфликтовать будут только методы с одинаковой сигнатурой и именем, да и то если они они имеют реализацию в базовых классах. Ну и тут надо, как-то выкрутился, но я пока не понял как. Мне думает, это скорее вопрос соглашений, так как информации достаточно и реализовать-то можно всякое поведение.

И вот пытаюсь сделать что-то такое и до [profile] wizzard0 докопался и до чатика. Пока еще даже не определился, как должны PolyType и YobaType выглядеть. Также мучает вопрос "а не поехал ли я", но тут без разницы, если действительно можназделоть.
stdray: (Default)
Пришло время написать макрос. Макрос сам себя не напишет.

Я тут некоторое время писал кое-какую мелочевку на Nemerle, и, можно сказать, язык пришелся мне по нраву. Очень похоже на F# хотя и своими особенностями. У меня пару раз возникало желание написать макрос, который будет заниматься небольшой кодогенерацией по месту, но, после небольшого размышления, я отказывался от этой затеи. Отчасти из-за неприязни к особым формам и неявному поведению (странно, что при этом я обожаю всяческий синтаксический сахар), отчасти из-за сложности написания самих макросов. Чтобы выяснить, что же меня больше смущает, я решил научиться их писать. В этом посте, я старался систематизировать то, что узнал о синтаксических макросах Nemerle.

макросы такие макросы )

В один пост все не влезает. Остальное можно прочитать вот здесь.
stdray: (Default)
Пришло время написать макрос. Макрос сам себя не напишет.

Я тут некоторое время писал кое-какую мелочевку на Nemerle, и, можно сказать, язык пришелся мне по нраву. Очень похоже на F# хотя и своими особенностями. У меня пару раз возникало желание написать макрос, который будет заниматься небольшой кодогенерацией по месту, но, после небольшого размышления, я отказывался от этой затеи. Отчасти из-за неприязни к особым формам и неявному поведению (странно, что при этом я обожаю всяческий синтаксический сахар), отчасти из-за сложности написания самих макросов. Чтобы выяснить, что же меня больше смущает, я решил научиться их писать. В этом посте, я старался систематизировать то, что узнал о синтаксических макросах Nemerle.
макросы такие макросы )
stdray: (Default)
Почему в F# и Nemerle списки, которые в коробке, являются энергичными, ведь с их помощью нельзя обрабатывать сколько-нибудь значительные объемы данных? В том же F# списки можно использовать только для написания симпатичных примерчиков вроде
  1. let rec insertions x = function  
  2.     | []             -> [[x]]  
  3.     | (y :: ys) as l -> (x::l)::(List.map (fun x -> y::x) (insertions x ys))  
  4.   
  5. let rec permutations = function  
  6.     | []      -> [ [] ]  
  7.     | x :: xs -> List.concat ( List.map (insertions x) (permutations xs) )  

но даже его, для реального использования необходимо переписывать через sequence. А sequence, в свою очередь, является простой оберткой на IEnumerable, для которого не определена определена операция Cons(head, tail), то есть в сопоставлении с образцом использовать нельзя, кроме как введением костылей вроде
  1. let (|SeqEmpty|SeqCons|) (xs: 'a seq) = //'  
  2.   if Seq.isEmpty xs then SeqEmpty  
  3.   else SeqCons(Seq.head xs, Seq.skip 1 xs)  

которые безбожно тормозят, поскольку каждый Skip порождает новую цепочку вычислений, которую надо разворачивать с самого начала. То есть матчить sequence нельзя, а для повторного использования результатов вычислений его постоянно оборачивают в Seq.cache. А на все вопросы относительно такого поведения, так называемые гуру дают ответ, что надо просто использовать LazyList из FSharpPowerPack. Ленивый список ок, его можно матчить и семантически он аналогичен кешированному Seq, но для него не определены computation expression, хотя это совсем незначительный эстетический недостаток.

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

Так же, у меня сложилось мнение, что немерлисты односвязанному ииммутабельному списку предпочитают родные дотнетовские List[T] и oh shi~ Array[T] с соответствующими императивными паттернами, даже специальная конструкция для выхода из множества вложенных циклов есть. То есть ЧИСТОТА не в почете.

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


PS: Забыл сказать, что идет июньский конкурс по функциональному программированию. Мое текущее решение на Nemerle отрабатывает за 42 секунды на нетбуке. Хочу попробовать переписать код с использованием ассинхронных вычислений, надеюсь побыстрее будет. Может кто-то хочет показать класс, решив задачу еще быстрее?

December 2019

S M T W T F S
1234567
891011121314
15161718192021
222324252627 28
293031    

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags