Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 29.11.11 21:34
Оценка:
Здравствуйте, коллеги!

Не так давно набрёл на большие ограничения вывода типов в generic'ах в C# (если я ничего не путаю, компилятор способен выводить типы только в generic-методах, но не классах/интерфейсах). После этого сразу вспомнил о Nemerle, где дела с выводом типов обстоят намного лучше. Стал разбираться, но всё-равно не смог решить свою задачу (либо тоже ограничение языка меня держит, либо незнание).

Формулировка задачи.
Дано:
Множество generic классов-реализаций абстрактного типа данных "дерево" (напр., BinarySearchTree[TKey,TValue], RedBlackTree[TKey,TValue] и проч.) Все эти классы реализуют интерфейс ITree[TKey,TValue]. Предположим, что работать со всеми этими типами неудобно.

Требуется: Реализовать класс-обёртку над любым из "неудобных" деревьев, реализующих ITree[TKey,TValue]. Назову этот тип TreeWrapper. Объекты класса TreeWrapper планируется создавать через фабричный метод, объявленный в самом же TreeWrapper. Класс TreeWrapper должен предоставить удобный интерфейс для работы с произвольным деревом (конкретный тип дерева указывается при создании TreeWrapper'a). Например, он должен избавить от необходимости явно указывать ключ, соответствующий значению при вставке в дерево. Поскольку TreeWrapper всё-таки должен будет передавать настоящему дереву какой-то ключ, TreeWrapper будет вычислять ключ, используя делегат, который ему специально передали при вызове фабричного метода.

Решение и проблема:
В принципе, основа решения мной получена. Проблема заключается в том, что я не могу избавиться от уродского дублирования типов ключей и значений "оборачиваемых" деревьев:
def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int], string, int](keyGenerator);


По идее, компилиятору достаточно информации, чтобы уметь работать с таким вызовом или аналогичным (если я не прав, поправьте):
// да, я знаю, что синтаксически неверны оба варианта...
def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int]](keyGenerator);
// или
def wrappedBST = TreeWrapper.Create.[BinarySearchTree, string, int](keyGenerator);


Иными словами, мой первый вопрос: поддерживает ли Nemerle "частичный вывод типов" (не знаю как правильно назвать)? Или же Nemerle как и C# эксплуатирует подход "всё или ничего"?

Второй вопрос: можно ли решить мою задачу каким-то изящным способом, не применяя макросов? Можно ли решить хотя бы с макросами (я пока с ними не знакомился, но что-то подсказывает, что они должны спасти)?

Ниже предаставлена моя попытка решения и ссылка на gist, если кому-то удобнее смотреть в нём. Заранее спасибо за любую помощь!
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Console;
using System.Linq;

interface ITree[TKey, TValue] { Add(_ : TKey, _ : TValue) : void; }

class RedBlackTree[TKey, TValue] : ITree[TKey, TValue]
{
  public Add(_ : TKey, _ : TValue) : void { }
}

class BinarySearchTree[TKey, TValue] : ITree[TKey, TValue]
{
  public Add(_ : TKey, _ : TValue) : void { }
}
    
class TreeWrapper[TKey, TValue]
{
  public static Create [TTree, TK, TV] (keyGenerator : TV -> TK) : TreeWrapper[TK, TV]
        where TTree : ITree[TK, TV], new()
        // where TK : TKey
        // where TV : TValue
  {
    def tree = TTree();
    TreeWrapper(keyGenerator, tree);
  }
    
  private this(keyGenerator : TValue -> TKey, tree : ITree[TKey, TValue])
  {
    // Сохранение неудобного в использовании объекта-реализации  tree,
    // чтобы затем работать с ним через удобный класс-обёртку TreeWrapper.
    this.tree = tree;
    this.keyGenerator = keyGenerator;
  }
    
  keyGenerator : TValue -> TKey;
  tree : ITree[TKey, TValue];
    
  public Add(value : TValue) : void
  {
    def key = keyGenerator(value);
    tree.Add(key, value);
  }
}

module Program
{
  Main() : void
  {
    def keyGenerator = @int : int => @int.ToString();
        
    // Ниже я пытаюсь выразить следующее: "Фабричный метод, создай мне обёртку над BinarySearchTree, у которого
    // ключи типа string, и значения типа int. Аргумент правильного типа также предоставляю."
    def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int], string, int](keyGenerator);
        
    // А хотелось бы не дублировать типы int и string. Вместо этого, например, писать так:
    //def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int]](keyGenerator);
    // или так
    //def wrappedBST = TreeWrapper.Create.[BinarySearchTree[?,?]](keyGenerator);
    // или так
    //def wrappedBST = TreeWrapper.Create.[BinarySearchTree[,]](keyGenerator);
    // или так
    //def wrappedBST = TreeWrapper.Create.[BinarySearchTree](keyGenerator);
        
    wrappedBST.Add(10);
  }
}
nemerle type inference generics вывод типов
Re: Упёрся в ограничения вывода типов или что-то упустил?
От: catbert  
Дата: 29.11.11 21:55
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

KK>Решение и проблема:

KK>В принципе, основа решения мной получена. Проблема заключается в том, что я не могу избавиться от уродского дублирования типов ключей и значений "оборачиваемых" деревьев:
KK>
def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int], string, int](keyGenerator);


Если честно, до конца я не прочитал но мне кажется, в Немерле есть фича, которая Вам нужна:

    def variant1 = TreeWrapper.Create(keyGenerator); // Немерле должен вывести тип вообще без параметров; но если что,
    def variant2 = TreeWrapper.Create.[BinarySearchTree[string, int], _, _](keyGenerator); // собственно фича — пропуск вместо типа
    def variant3 = TreeWrapper.Create.[_, string, int](keyGenerator); // так даже проще


Такие вещи, к сожалению, довольно сложно найти в имеющейся документации. Но ведь есть форум
Re[2]: Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 29.11.11 22:05
Оценка:
catbert, спасибо большое за подробный ответ. К сожалению, обязательно рассмотрю его подробно завтра с утра, потому что "котелок уже не варит".

> Такие вещи, к сожалению, довольно сложно найти в имеющейся документации. Но ведь есть форум

Если Вы имеете в виду, что я плохо копал документацию и засоряю форум, то прошу прощения, но оно почти так и есть. Я знакомлюсь с Немерл по "Nemerle for OOP Programmers Course", а иные источники пока не классифицировались в моей голове. Поэтому я просто не очень понимаю где искать.

Ещё раз благодарю за ответ. Если это действительно решает мою задачу, то я буду в восторге!
Re: Упёрся в ограничения вывода типов или что-то упустил?
От: WolfHound  
Дата: 29.11.11 22:06
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

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

KK>
def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int], string, int](keyGenerator);

Так сойдет?
  public static Create [TTree, TK, TV] (newTree : void -> TTree, keyGenerator : TV -> TK) : TreeWrapper[TK, TV]
        where TTree : ITree[TK, TV]
        // where TK : TKey
        // where TV : TValue
  {
    def tree = newTree();
    TreeWrapper(keyGenerator, tree);
  }

    def wrappedBST = TreeWrapper.Create(BinarySearchTree.[string, int], null);
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 29.11.11 22:22
Оценка:
Любопытство всё-таки не дало мне лечь спать!

Спасибо, WolfHound! Сочетая Ваш вариант с фичей Nemerle'а, описанной catbert'ом, получил такой вариант использования:
def wrappedBST = TreeWrapper.Create(BinarySearchTree.[_, _], keyGenerator);

Типы ключей и значений в BinarySearchTree выводятся тут из типа генератора ключей. Правда, я пока совсем не понял трюка с "newTree : void -> TTree", но это уже точно завтра на свежую голову.

Чёрт побери! Я начну пропаганду языка у себя в конторе. Подкупили возможности.

Ещё раз спасибо всем!
Re: Упёрся в ограничения вывода типов или что-то упустил?
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.11.11 23:13
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

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

KK>
def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int], string, int](keyGenerator);


Если проблема только в этом, то можно сделать так:
def wrappedBST = TreeWrapper.Create.[BinarySearchTree[_, _], _, _](keyGenerator);

Но будет уродливое дублирование "_" .

А вообще, то что ты хочешь добиться называется "rank-2 polymorphism" полиморфизм. В чистом виде его в Nemerle нет, так что как бы крут вывод типов не был, он не сможет позволить передавать в качестве параметра типов обобщенный тип вместе с параметрами типов. Ну, разве что с констрэйнами поизвращаться, как в твоем примере.

KK>По идее, компилиятору достаточно информации, чтобы уметь работать с таким вызовом или аналогичным (если я не прав, поправьте):

KK>
// да, я знаю, что синтаксически неверны оба варианта...
KK>def wrappedBST = TreeWrapper.Create.[BinarySearchTree[string, int]](keyGenerator);
KK>// или
KK>def wrappedBST = TreeWrapper.Create.[BinarySearchTree, string, int](keyGenerator);


Не уверен, что прав на 100%. Тут лучше получить консультацию Nikov-а (который, похоже, всех собак в округе поел по этому поводу). Но полная реализация "rank-2 polymorphism" на дотнете невозможна. Можно реализовать только некоторые фишки.

KK>Иными словами, мой первый вопрос: поддерживает ли Nemerle "частичный вывод типов" (не знаю как правильно назвать)? Или же Nemerle как и C# эксплуатирует подход "всё или ничего"?


Это зависит от того, что понимается под термином "частичный вывод типов" .

KK>Второй вопрос: можно ли решить мою задачу каким-то изящным способом, не применяя макросов?


Опять же сначала нужно понять что является конечной целью задачи? Если задача — создание универсальной фабрики, то она решается в сто раз проще. Нужно просто передавать функцию создающую нужный объект в качестве параметра вашей фабрике. Упрощенно это можно показать так. Меняем реализацию Create на:
public static Create[K, V](treeCtor : void -> ITree[K, V], keyGenerator : V -> K) : TreeWrapper[K, V]
{
  TreeWrapper(keyGenerator, treeCtor())
}

А код его вызова:
def wrappedBST = TreeWrapper.Create(BinarySearchTree, keyGenerator);

Т.е. вместо параметра типов передаем функции конструктор который будет создавать тип.
Как бонус получим резкое ускорение создания дерева, так как будет избавимся от создания его экземпляров через Activator.CreateInstance(), который используется при указании констрэйна new(). Activator.CreateInstance — очень медленный. Если вызовов будет много, можно получить конкретные тормоза.

KK>Можно ли решить хотя бы с макросами (я пока с ними не знакомился, но что-то подсказывает, что они должны спасти)?


Макросами можно решить почти любую проблему. В частности можно написать макру которая будет вставлять все параметры типов автоматом и как надо. Вызов такой макры будет выглядеть похоже на предыдущий вариант:
Create(BinarySearchTree, keyGenerator)

но первый параметр она будет интерпретировать как тип, а не как конструктор. Ну, а результатом будет примерно такой код:
TreeWrapper.Create.[BinarySearchTree[string, int], string, int](keyGenerator)

Кода макроса будет примерно таким:
using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

namespace MacroLibrary
{
  macro Create(type : PExpr, func : PExpr)
  {
    CreateImpl.DoTransform(Macros.ImplicitCTX(), type, func)
  }
  
  module CreateImpl
  {
    public DoTransform(typer : Typer, type : PExpr, func : PExpr) : PExpr
    {
      Macros.DefineCTX(typer);
      
      def typeVar1 = <[ $(typer.FreshTypeVar() : typed) ]>; // создаем переменную типа и запаковываем ее в выражение
      def typeVar2 = <[ $(typer.FreshTypeVar() : typed) ]>;
      
      <[ TreeWrapper.Create.[$type[$typeVar1, $typeVar2], $typeVar1, $typeVar2]($func) ]>
    }
  }
}

Макрос можно даже сделать независящим от количества параметров типов. Но это уже посложнее. Кроме того не ясно зачем все это делать .

ЗЫ

Всегда есть более простые и эффективные решения. Но их можно подобрать только если знаешь конкретную задачу. Так что лучше начать от печки и описать — что привело ко всем этим наворотам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Упёрся в ограничения вывода типов или что-то упустил?
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.11.11 23:28
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

KK>Спасибо, WolfHound! Сочетая Ваш вариант с фичей Nemerle'а, описанной catbert'ом, получил такой вариант использования:

KK>
def wrappedBST = TreeWrapper.Create(BinarySearchTree.[_, _], keyGenerator);


Вот это ".[_, _]" здесь тоже лишнее. Можно просто так:
def wrappedBST = TreeWrapper.Create(BinarySearchTree, keyGenerator);

Тут вывод типов справится.

KK>Типы ключей и значений в BinarySearchTree выводятся тут из типа генератора ключей. Правда, я пока совсем не понял трюка с "newTree : void -> TTree", но это уже точно завтра на свежую голову.


Это очень простой трюк доступный даже в C#. Этот параметр описывает ссылку на функцию. Ну, а BinarySearchTree в вызове — это ссылка на конструктор класса BinarySearchTree.

Собственно, для данной задачи параметр типов TTree не нужен. С тем же успехом можно было использовать ITree. TTree позволяет материализовать тип дерева внутри TreeWrapper. А в твоем TreeWrapper используется ссылка на ITree, так что это лишнее.

KK>Чёрт побери! Я начну пропаганду языка у себя в конторе. Подкупили возможности.




Ну, язык то действительно хороший. Только это верхушка айзебрга. В нем еще много интересного. Вариантные типы, качественный ФП и конечно же макросы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Упёрся в ограничения вывода типов или что-то упустил?
От: Ziaw Россия  
Дата: 30.11.11 06:46
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

KK>catbert, спасибо большое за подробный ответ. К сожалению, обязательно рассмотрю его подробно завтра с утра, потому что "котелок уже не варит".


>> Такие вещи, к сожалению, довольно сложно найти в имеющейся документации. Но ведь есть форум

KK>Если Вы имеете в виду, что я плохо копал документацию и засоряю форум, то прошу прощения, но оно почти так и есть.

Не надо искать сарказм. Это обычная констатация факта.
Re[3]: Упёрся в ограничения вывода типов или что-то упустил?
От: catbert  
Дата: 30.11.11 09:23
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

>> Такие вещи, к сожалению, довольно сложно найти в имеющейся документации. Но ведь есть форум

KK>Если Вы имеете в виду, что я плохо копал документацию и засоряю форум, то прошу прощения, но оно почти так и есть.

Нет, я имел в виду именно то что написал Я сам "открыл" частичную типизацию, копаясь в исходниках Немерла.

KK> Я знакомлюсь с Немерл по "Nemerle for OOP Programmers Course", а иные источники пока не классифицировались в моей голове. Поэтому я просто не очень понимаю где искать.


Рекомендую курс Grokking Nemerle, он кажется идет в поставке с компилятором. Там довольно базовые вещи, но именно поэтому можно "открыть" для себя что-то новое.
Re[2]: Упёрся в ограничения вывода типов или что-то упустил?
От: _nn_ www.nemerleweb.com
Дата: 30.11.11 09:56
Оценка: +1
Здравствуйте, catbert, Вы писали:


C>Такие вещи, к сожалению, довольно сложно найти в имеющейся документации. Но ведь есть форум


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

https://github.com/rsdn/nemerle/wiki
https://github.com/rsdn/nemerle/wiki/Sample-pack
http://nemerle.org/wiki/index.php?title=Language
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 30.11.11 10:33
Оценка:
Здравствуйте, catbert, Вы писали:

C>Нет, я имел в виду именно то что написал Я сам "открыл" частичную типизацию, копаясь в исходниках Немерла.


Значит я просто увидел двусмысленность там, где её нет. Сорри.

C>Рекомендую курс Grokking Nemerle, он кажется идет в поставке с компилятором. Там довольно базовые вещи, но именно поэтому можно "открыть" для себя что-то новое.


Спасибо, посмотрю.
Re[3]: Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 30.11.11 10:34
Оценка:
Здравствуйте, _nn_, Вы писали:

__>https://github.com/rsdn/nemerle/wiki

__>https://github.com/rsdn/nemerle/wiki/Sample-pack
__>http://nemerle.org/wiki/index.php?title=Language

Спасибо! Честно говоря, я вики не смотрел даже. Только на Nemerle.org рылся.
Re[4]: Упёрся в ограничения вывода типов или что-то упустил?
От: _nn_ www.nemerleweb.com
Дата: 30.11.11 10:40
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

KK>Спасибо! Честно говоря, я вики не смотрел даже. Только на Nemerle.org рылся.


Похоже надо это в Q&A вставить, чтобы легче находить.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 30.11.11 10:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это зависит от того, что понимается под термином "частичный вывод типов" .


Не обращайте внимания. Я слабо знаком с теорией языков программирования поэтому не знаю многих терминов.

VD>А вообще, то что ты хочешь добиться называется "rank-2 polymorphism" полиморфизм. В чистом виде его в Nemerle нет, так что как бы крут вывод типов не был, он не сможет позволить передавать в качестве параметра типов обобщенный тип вместе с параметрами типов. Ну, разве что с констрэйнами поизвращаться, как в твоем примере.

VD> ...
VD>Не уверен, что прав на 100%. Тут лучше получить консультацию Nikov-а (который, похоже, всех собак в округе поел по этому поводу). Но полная реализация "rank-2 polymorphism" на дотнете невозможна. Можно реализовать только некоторые фишки.
VD> ...
VD>Опять же сначала нужно понять что является конечной целью задачи? Если задача — создание универсальной фабрики, то она решается в сто раз проще.

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

VD> Нужно просто передавать функцию создающую нужный объект в качестве параметра вашей фабрике. Упрощенно это можно показать так. Меняем реализацию Create на ...

VD> ... Т.е. вместо параметра типов передаем функции конструктор который будет создавать тип.

Решение очень понравилось!

VD>Как бонус получим резкое ускорение создания дерева, так как будет избавимся от создания его экземпляров через Activator.CreateInstance(), который используется при указании констрэйна new(). Activator.CreateInstance — очень медленный. Если вызовов будет много, можно получить конкретные тормоза.


Это тоже отличная новость, потому что не знал, как избежать дорогого Activator.CreateInstance() в C#.

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


Именно такой подход я себе и представлял. Про макросы обязательно буду читать позднее, потому что порой их сильно не хватает в C#.

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


Это одна из причин, по которым я задал тут вопрос. Во-первых, хотел увидеть какие мысли возникнут у адептов Nemerle. Во-вторых, посмотреть насколько силён вывод типов, какие есть ограничения и какие трюки.
Сама же печка озвучена в исходном сообщении. Потребовалось обернуть семейство типов в общую обёртку. Конечно, этот конкретный пример несколько надуманный, но он помог мне узнать много нового.
Re[3]: Упёрся в ограничения вывода типов или что-то упустил?
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.11.11 15:01
Оценка:
Здравствуйте, KeyKeeper, Вы писали:

KK>Исходную задачу Вы поняли абсолютно верно.


У нас тут принято на "ты", если это не смущает, то предлагаю перейти на ты.

KK>Нужна универсальная фабрика. Вторая задача, возникшая по дороге — понять, какие подходы можно использовать, если решать на Nemerle.


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

В прочем, для начального знакомства пограммирование в стиле C#++ тоже полезно. Но лучше потренироваться на кошках (мелком проекте). А при разработке чего-то более сложного подумать над дизайном по сильнее (с учетом опыта).

Лично я уже забыл когда занимался созданием проксей или использованием разных DI-технологий. Все эти подходы, обычно, решают одну и ту же задачу — упрощение написания скучного кода. Но на немерле этот скучный код можно просто не писать! Его можно сгенерировать по модели.

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

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

Другой вариант изменение дизайна с ООП на ФП. Этот вариант оправдан когда речь идет о пакетной обработке данных. Когда есть входные данные и их нужно преобразовать в другой вид.

KK>Это тоже отличная новость, потому что не знал, как избежать дорогого Activator.CreateInstance() в C#.


В C# можно делать точно так же. Единственная проблема заключается в том, что шарп не превращает конструкторы в функции и не умеет выводить параметры типов для конструкторов, так что кода будет больше. Но работать будет.

KK>Сама же печка озвучена в исходном сообщении. Потребовалось обернуть семейство типов в общую обёртку. Конечно, этот конкретный пример несколько надуманный, но он помог мне узнать много нового.


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

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

Вот здесь
Автор: VladD2
Дата: 24.09.11
лежит статья в которой есть пример такого макроса.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Упёрся в ограничения вывода типов или что-то упустил?
От: KeyKeeper Россия  
Дата: 30.11.11 22:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>У нас тут принято на "ты", если это не смущает, то предлагаю перейти на ты.


Что ты! Абсолютно не смущает. Просто я на RSDN ещё неделю назад был только в качестве читателя. Поэтому думал, что на "ты" тут общаются только как знакомые лично люди.

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


Ну, да. Это довольно очевидный факт. Полагаю это из одного разряда с первым знакомством с SQL после императивного программирования (все проходили). Если же про ФП говорить, то и Odersky в Programming in Scala пишет то же самое про тех, кто приходит с багажом опыта программирования на Java: скала позволяет писать как на джаве, только зачем?..

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

VD>Данный подход оправдан когда объем скучного кода большой. Причем чем больше может быть кода, тем более оправдан подход.
VD>Другой вариант изменение дизайна с ООП на ФП. Этот вариант оправдан когда речь идет о пакетной обработке данных. Когда есть входные данные и их нужно преобразовать в другой вид.

К сожалению, я слишком посредственный разработчик, чтобы иметь какие-то очень сложные задачи перед собой в личных проектах, где нельзя бы было применить "силу руки" при программировании. Да и на работе проекты тоже не из разряда 'cutting edge' — Nemerle нет смысла применять. Это правда совсем не значит, что мне не любопытно. Если будут возникать проекты с серьёзным back-end'ом, постараюсь убедить коллег всерьёз рассмотреть вариант разработки на Nemerle. Слава Богу, ребята у нас из категории падких на интересное, хотя и в разумных пределах.

VD> ...Макросы позволяют читать информацию о типах и генерировать по ней код. Причем информация о типах доступна не только для типов скомпилированных в сборки (как в случае использования рефексии), но и для кода определенного в проекте. Вот здесь
Автор: VladD2
Дата: 24.09.11
лежит статья в которой есть пример такого макроса.


Обязательно прочитаю статью, но не знаю точно когда. Совсем скоро моё время будут поедать курсы английского, так что с моими программерскими интересами вне работы мне придётся поубавить темп. В любом случае, понял для себя, что с Nemerle имеет смысл знакомиться ближе, так как писать на нём намного комфортнее и быстрее, чем на C#, не теряя в качестве. А если уметь, то, наверное, и можно даже лучше.

P.S. Ещё раз спасибо за ответ по исходному вопросу, не смотря на то, что я довольно сумбурно выразил его.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.