Pull to refresh

Comments 19

Не могли бы вы привести пару примеров задач, которые «через монады» решаются проще, чем методами традиционного ООП?
Пара примеров есть в статье: это построение списков и описание асинхронного процесса вычисления.

Первый можно назвать микро достижением, так как изменения затрагивают только тело метода.

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

Используя монаду State можно через код неявно протаскивать IoC-контейнер (макро достижение). Через монаду Maybe организовать хотелку C#-программистов оператор "?." (микро достижение).

Simon Peyton Jones написал потрясающую статью про реализацию STM в Haskell через монады — Beautiful concurrency.

Через монады так же реализован Parsec в Haskell — библиотека для удобного описания парсера, когда описание парсера в языке Haskell (то есть его исходный код) максимально приближено к форме БН. Хотя мне больше нравиться подход Nemerle: парсер описывается макросом, который в свою очередь при компиляции генерирует код для разбора.

Про другие применения монад можно почитать в статье Евгения Кирпичева Монады
Спасибо за статью и ответ.

А как насчет дебага всего этого дела? Могу представить что это адцкий ад наверное?
Я бы использовал Nemerle, если бы это был синтаксический суперсет от C#.
Типо языкового расширения…

А так поменяли тип и имя параметра местами в описании функций, выкинули return, другие косметические изменения ради изменений, но не пользы…
На самом деле такой синтаксис более продуман, но это не так важно, как возможность использовать преимущества макросов (например, PEG и Computation expressions).

Скоро будет релиз, в котором будет конвертер из C# в Nemerle, а так же возможность компилятором Nemerle компилировать C# файлы. То есть берем проект на C#, а новый функционал пишем уже на Nemerle)
Возможно новый функционал и продуман, но не базовый.

Базовый функционал надо писать «по-новому».

1) Поменять местами тип и название параметра в описании методов, плюс влепить между ними двоеточие. Разделять запятой, а не точкой с запятой.
3) Заменить угольные скобки на квадратные в описании генериков. Это массив или доступ по индексу?
4) Тип результата функции писать в конце метода, опять через двоеточие. Кроме того, void все еще есть :)
5) Лямбду через минус, а не через знак равно.

Вы хотите сказать, что этим косметическим изменениям есть объяснение, кроме как — мы не хотим, чтобы все было как в C, а хотим чуть-чуть из Pascal?
Конечно есть они более логичны и последовательны.

1. В случае generic-метода у нас вначале идет объявление параметра, а затем его использование:

// Nemerle
public Wrap[T](a : T) : List[T] { ... }
// C#
public List<T> Wrap<T>(T a) { ... }

Объявление переменной с указанием типа или с использованием вывода типа выглядит однородно:

// Nemerle
def a : string = "...";
def a = "...";
// C#
string a = "...";
var a = "...";


2. Ну в C# тоже запятой параметры разделяются.

3. Я не знаю почему, кажется разумной причины нет, но я как то читал, что вроде это устраняет неоднозначности и упрощает парсер языка.

4. Уже в первом пункте раскрыл.

5. Лямбда через знак равно, через минус функциональный тип описывается, например

def a : int -> string = x => x.ToString();
Вот реально чего не хватает в C#, это такого:
class MyClass 
{
  [MyTransform]  
  public int Property { get; set;}
}

abstract class PropertyTransformAttribute<T>: Attribute
{
   public string PropetyName { get; private set;}  

   public delegate void Setter(object self, ref T oldValue, T newValue);
   public delegate T Getter(object self, T oldValue);

   public virtual Expression<Setter> TransformSetter(Setter setter) { return setter; }
   public virtual Expression<Getter> TransformGetter(Getter getter) { return getter; }  
}

class MyTransformAttribute: TransformAttribute<int>
{

   public override Expression<Setter> TransformSetter(Setter setter) 
   {
      return (sender, ref oldValue, newValue) =>
      {
         if (oldValue == newValue) return;
         oldValue = newValue;
         ((MyClass)sender).RaisePropertyChanged(PropertyName);
      }      
   }
}


И чтобы эта трансформация вызывалась компилятором до codegen…
А разве все эти AOP фреймворки типа postsharp не этим занимаются?
занимаются, но конкретно с этим примером очень плохо дело обстоит.
глядя в сборку на полученный код, становится тоскливо…

хотелось бы простой трансформатор кода, без всяких AOP наворотов
Это можно будет делать, компилятор Nemerle будет понимать и .cs файлы и .n файлы, внутри .cs можно будет использовать макроатрибуты (макросы, которые выглядят как атрибуты, но переписывают код на этапе компиляции.
Вот это будет здорово!
> Скоро будет релиз, в котором будет конвертер из C# в Nemerle, а так же возможность компилятором Nemerle компилировать C# файлы. То есть берем проект на C#, а новый функционал пишем уже на Nemerle)

Уже есть. В последних инсталляторах уже есть поддержка компиляции C#-файлов. Сейчас уже основные глюки выловлены, так что можно пользоваться (хотя, конечно, какие-то ошибки будут, наверно).
«но, в отличие от C#, эти языки поддерживают концепцию более высокого уровня, которая позволяет реализовать асинхронные вычисления в стиле async/await в виде библиотеки, а не на уровне языка.»

А что мешает, собственно, в C# это реализовать в виде библиотеки?
Не будет поддержки со стороны языка. В ООП стиле можно писать и на C, но отсутствие поддержки со стороны языка делает это дело сложным. Тоже самое и тут.
> А что мешает, собственно, в C# это реализовать в виде библиотеки?

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

Для поддержки подобного в C# нужно менять компилятор. Собственно в C# 5.0 и будет введен синтаксис для подержи асинхронного программирования. Но это будет конкретная реализация которая будет гвоздями прибита к языку. В случае Nemerle реализация — это макрос. Его можно подключить в виде библиотеки, а чтобы использовать в конкретном файле проекта нужно еще открыть с помощью using.
> Имя этой концепции — монада.

В тред врывается Haskell-программист!
Уже боюсь… надеюсь я монадами ничего не напутал.
Sign up to leave a comment.

Articles