List+Tuple=Listuple
От: artelk  
Дата: 14.01.15 17:27
Оценка:
  Развлекался тут на досуге
public interface IListupleVisitor
{
    void Invoke<T>(T arg);
}

public interface L
{
    void Apply(IListupleVisitor listupleVisitor);
}

public sealed class Nil : L
{
    public static readonly Nil Value = new Nil();
    private Nil() {}
    public void Apply(IListupleVisitor listupleVisitor) {}
}

public interface L<out THead, out TTail> : L
    where TTail : L
{
    THead Head { get; }
    TTail Tail { get; }
}

public sealed class Cons<THead, TTail> : L<THead, TTail> where TTail : L
{
    private readonly THead head;
    private readonly TTail tail;

    public Cons(THead head, TTail tail)
    {
        this.tail = tail;
        this.head = head;
    }

    public THead Head
    {
        get { return head; }
    }

    public TTail Tail
    {
        get { return tail; }
    }

    public void Apply(IListupleVisitor listupleVisitor)
    {
        listupleVisitor.Invoke(Head);
        Tail.Apply(listupleVisitor);
    }
}

public static class Listuple
{
    public static L<THead, TTail> Add<THead, TTail>(this TTail tail, THead head)
        where TTail : L
    {
        return new Cons<THead, TTail>(head, tail);
    }

    public static L<THead, TTail> Push<THead, TTail>(this TTail tail, THead head)
        where TTail : L
    {
        return tail.Add(head);
    }

    public static TTail Pop<THead, TTail>(this L<THead, TTail> list, Action<THead> consume)
        where TTail : L
    {
        consume(list.Head);
        return list.Tail;
    }

    public struct SeedPair<T, TL>
        where TL : L
    {
        public readonly T Value;
        public readonly TL List;

        public SeedPair(T value, TL list)
        {
            Value = value;
            List = list;
        }
    }

    public static SeedPair<T, TL> Seed<T, TL>(this TL list, T value)
        where TL: L
    {
        return new SeedPair<T, TL>(value, list);
    }

    public static SeedPair<TOutput, TTail> Pop<THead, TTail, TInput, TOutput>(this SeedPair<TInput, L<THead, TTail>> pair,
                                                                                Func<TInput, THead, TOutput> aggregate)
        where TTail : L
    {
        return pair.List.Tail.Seed(aggregate(pair.Value, pair.List.Head));
    }

    public static TOutput Pop<THead, TInput, TOutput>(this SeedPair<TInput, L<THead, Nil>> pair,
                                                        Func<TInput, THead, TOutput> aggregate)
    {
        return aggregate(pair.Value, pair.List.Head);
    }
}


  Пример использования
private static void Main()
{
    L<DateTime, L<double, L<string, L<int, Nil>>>> list = 
        Nil.Value.Add(42).Add("Hi").Add(3.1415927).Add(DateTime.Now);

    list.Pop(v => Console.WriteLine(v))
        .Pop(v => Console.WriteLine(v))
        .Pop(v => Console.WriteLine(v))
        .Pop(v => Console.WriteLine(v));

    var value = list.Seed("")
                    .Pop(Add)
                    .Pop(Add)
                    .Pop(Add)
                    .Pop(Add);
    Console.WriteLine(value);

    list.Apply(WriteLineListupleVisitor.Instance);
}

private static string Add<T>(string s, T v)
{
    return string.IsNullOrEmpty(s) ? v.ToString() : s + "; " + v;
}

private sealed class WriteLineListupleVisitor : IListupleVisitor
{
    public static readonly WriteLineListupleVisitor Instance = new WriteLineListupleVisitor();

    public void Invoke<T>(T arg)
    {
        Console.WriteLine("Type: {0}; Value: {1}", typeof(T).FullName, arg);
    }
}


Когда оно может быть полезным пока не придумал.
Re: List+Tuple=Listuple
От: btn1  
Дата: 14.01.15 18:01
Оценка: +1 :)
Здравствуйте, artelk, Вы писали:

A>Развлекался тут на досуге

A>public static class Listuple

А теперь можно написать класс Zvezduple! Пример использования:

var star = new Zvezduple(mnogo_babla);
star.push(fabrika_zvezdei());
star.Pop(Lena_Terleeva);


Зачем оно надо — ну... примерно затем же, что и Листупле.
Re[2]: List+Tuple=Listuple
От: Artem Korneev США https://www.linkedin.com/in/artemkorneev/
Дата: 14.01.15 19:38
Оценка:
Здравствуйте, btn1, Вы писали:

B>star.Pop(Lena_Terleeva);


А кто это? о_О
С уважением, Artem Korneev.
Re[2]: List+Tuple=Listuple
От: artelk  
Дата: 14.01.15 19:54
Оценка:
Здравствуйте, btn1, Вы писали:

B>Здравствуйте, artelk, Вы писали:


A>>Развлекался тут на досуге

A>>public static class Listuple

B>А теперь можно написать класс Zvezduple! Пример использования:


B>
B>var star = new Zvezduple(mnogo_babla);
B>star.push(fabrika_zvezdei());
B>star.Pop(Lena_Terleeva);
B>


B>Зачем оно надо — ну... примерно затем же, что и Листупле.


Не, Zvezduple так просто не получить, тем более чтоб объект Lena_Terleeva в Pop.
Re: List+Tuple=Listuple
От: Spiceman  
Дата: 15.01.15 10:06
Оценка:
Здравствуйте, artelk, Вы писали:

A>Когда оно может быть полезным пока не придумал.


Какую задачу хоть решал?
Re[2]: List+Tuple=Listuple
От: artelk  
Дата: 15.01.15 13:00
Оценка:
Здравствуйте, Spiceman, Вы писали:

S>Здравствуйте, artelk, Вы писали:


A>>Когда оно может быть полезным пока не придумал.


S>Какую задачу хоть решал?


Ну, в общем, захотелось сдалать такой Tuple, который можно представить в виде коллекции (неизменяемый односвязный список), к которому можно добавить элемент (причем любого типа), удалять элемент (голову списка), пройтить по элементам и применить некую (параметрически) полиморфную функцию (Invoke<T> в IListupleVisitor). И чтоб все статически типизировано.

В дотнете есть класс ObjectResult&lt;T&gt;, реализующий IEnumerable<T> и у которого есть метод GetNextResult<TElement>(), возвращающий ObjectResult<TElement>.
Т.е. тут подразумевается цепочка вызовов, выгребающая объекты разных типов. Возможно где-то еще есть что-то подобное.
Если реализовать для моего Listuple какие-то алгоритмы, то их можно будет использовать для ObjectResult<T> (и для других подобных классов) путем написания несложных обвязок и хэлперов.
Re[3]: List+Tuple=Listuple
От: Spiceman  
Дата: 16.01.15 07:28
Оценка: 3 (1) +2
Здравствуйте, artelk, Вы писали:

S>>Какую задачу хоть решал?


A>Ну, в общем, захотелось сдалать такой Tuple,


Я, наверное, уже старый и отстаю от жизни, но задачу-то ты какую решал?
Re: List+Tuple=Listuple
От: _NN_ www.nemerleweb.com
Дата: 16.01.15 19:38
Оценка:
Здравствуйте, artelk, Вы писали:

Обычный неизменяемый односвязный список.
А 'Tuple' тут при чем ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: List+Tuple=Listuple
От: artelk  
Дата: 17.01.15 14:11
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, artelk, Вы писали:


_NN>Обычный неизменяемый односвязный список.

Не так чтоб совсем обычный. Add конструирует новый тип, заворачивая исходный.
_NN>А 'Tuple' тут при чем ?
По сути это Tuple — упорядоченный набор разнотипных значений со статической проверкой типов. Просто создается он путем последовательного добавления элементов в обратном порядке. И вместо, например, Item2 (или функции snd) нужно писать list.Tail.Head и т.п.
Re[3]: List+Tuple=Listuple
От: _NN_ www.nemerleweb.com
Дата: 18.01.15 09:04
Оценка: +1
Здравствуйте, artelk, Вы писали:

_NN>>Обычный неизменяемый односвязный список.

A>Не так чтоб совсем обычный. Add конструирует новый тип, заворачивая исходный.
Не приметил гетерогенность списка.
_NN>>А 'Tuple' тут при чем ?
A>По сути это Tuple — упорядоченный набор разнотипных значений со статической проверкой типов. Просто создается он путем последовательного добавления элементов в обратном порядке. И вместо, например, Item2 (или функции snd) нужно писать list.Tail.Head и т.п.

Вместо L<H, T> можно было бы нагенерировать несколько классов вида L<T0> .. L<T0...Tn>
Тогда доступ был бы всегда через Item(n) , а Add реализовать так:
class L<T0>
{ 
  L<T0, T1> Add(T1 t1) { return new L<T0, T1>(Item0, t1); }
}

...
// Ну и создание можно упростить как бы:
static class ListTuple
{
 public static L<T0> Create(T0 t0) { return L<T0>(t0); }

...
 public static L<T0..Tn> Create(T0 t0...Tn tn) { return L<T0..Tn>(t0..tn); }
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: List+Tuple=Listuple
От: artelk  
Дата: 18.01.15 11:04
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Вместо L<H, T> можно было бы нагенерировать несколько классов вида L<T0> .. L<T0...Tn>


Да. Только тогда они повторяли бы уже существующие Tuple<T0...Tn>, лучше уж использовать сразу их.

_NN>Тогда доступ был бы всегда через Item(n) , а Add реализовать так:

_NN>
_NN>class L<T0>
_NN>{ 
_NN>  L<T0, T1> Add(T1 t1) { return new L<T0, T1>(Item0, t1); }
_NN>}

_NN>...
_NN>// Ну и создание можно упростить как бы:
_NN>static class ListTuple
_NN>{
_NN> public static L<T0> Create(T0 t0) { return L<T0>(t0); }

_NN>...
_NN> public static L<T0..Tn> Create(T0 t0...Tn tn) { return L<T0..Tn>(t0..tn); }
_NN>}
_NN>


Create у туплов уже есть, методы Add можно нагенерить для всех вариантов их "длин". А еще нужно нагенерить методы GetTail() для обратной декомпозиции. А еще нагенерить Apply...
Re[5]: List+Tuple=Listuple
От: _NN_ www.nemerleweb.com
Дата: 18.01.15 12:14
Оценка:
Здравствуйте, artelk, Вы писали:

A>Create у туплов уже есть, методы Add можно нагенерить для всех вариантов их "длин". А еще нужно нагенерить методы GetTail() для обратной декомпозиции. А еще нагенерить Apply...


И оформить в NuGet .
Ну так делов-то, скрипт на питоне пишется за минуту.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: List+Tuple=Listuple
От: artelk  
Дата: 18.01.15 21:27
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, artelk, Вы писали:


A>>Create у туплов уже есть, методы Add можно нагенерить для всех вариантов их "длин". А еще нужно нагенерить методы GetTail() для обратной декомпозиции. А еще нагенерить Apply...


_NN>И оформить в NuGet .

_NN>Ну так делов-то, скрипт на питоне пишется за минуту.

Вот смотри, допустим мы захотели подружить Listuple с ObjectResult<T>:

public static class ObjectResultListupleExtensions
{
    public static Fetcher<T, Nil> Fetch<T>(this ObjectResult<T> objectResult)
    {
        return new Fetcher<T, Nil>(objectResult, Nil.Value);
    }

    public struct Fetcher<T, TTail>
        where TTail : L
    {
        private readonly ObjectResult<T> objectResult;
        public readonly L<IReadOnlyList<T>, TTail> Result;

        public Fetcher(ObjectResult<T> objectResult, TTail tail)
        {
            this.objectResult = objectResult;
            Result = tail.Add(objectResult.ToList());
        }

        public Fetcher<TNext, L<IReadOnlyList<T>, TTail>> Next<TNext>()
        {
            return new Fetcher<TNext, L<IReadOnlyList<T>, TTail>>(objectResult.GetNextResult<TNext>(), Result);
        }
    }
}


Использование:

ObjectResult<int> objectResult = //...

var fetchedResult = objectResult.Fetch<int>()
                                .Next<string>()
                                .Next<double>()
                                .Next<bool>()
                                .Result;


Для туплов пришлось бы генерить методы Next. И вообще на каждый чих пришлось бы генерить пачку методов для всех возможных туплов. А все потому, что для туплов на уровне системы типов нельзя выразить "тупл, полученный путем добавления такого-то значения к такому-то туплу".

Хотя нагенерить методы Create, GetItemN() и еще FromTuple/ToTuple было бы полезно — что-то удобней выражается через туплы, а что-то — через вот такой вот Listuple.
Re[7]: List+Tuple=Listuple
От: Sinix  
Дата: 19.01.15 06:25
Оценка:
Здравствуйте, artelk, Вы писали:

A>Использование:

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

Так что я пожалуй присоединюсь к Spiceman: что-то я не вижу, где такую штуку можно использовать
Re[8]: List+Tuple=Listuple
От: artelk  
Дата: 19.01.15 11:20
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, artelk, Вы писали:


A>>Использование:

S>Не, это абсолютно нереалистичный сценарий. Никто не будет мучаться с полу-типизацией (типы есть, семантической нагрузки нет), когда есть более простые и удобные решения. Обычно или используют POCO (тем более что их можно создать по использованию за секунду), или анонимные типы, или, на крайний случай, передают дальше датасет.

ObjectResult — оно про хранимки, возвращающие множественные резалтсеты. POCO как раз используются (я в примере примитивные типы поставил, каюсь; там как раз POCO должны стоять).

S>Так что я пожалуй присоединюсь к Spiceman: что-то я не вижу, где такую штуку можно использовать


В батчевых запросах можно еще использовать — набиваешь батч запросами (IQueryable), выполняешь и получаешь Listuple с результатами.
Re[9]: List+Tuple=Listuple
От: Sinix  
Дата: 19.01.15 12:30
Оценка:
Здравствуйте, artelk, Вы писали:

A>ObjectResult — оно про хранимки, возвращающие множественные резалтсеты.

Ну, это всё-таки очень частный случай.
Я бы не вытаскивал информацию о порядке запросов за пределы DAL и ограничился бы стандартным подходом.
Re[10]: List+Tuple=Listuple
От: artelk  
Дата: 19.01.15 14:03
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, artelk, Вы писали:


A>>ObjectResult — оно про хранимки, возвращающие множественные резалтсеты.

S>Ну, это всё-таки очень частный случай.
S>Я бы не вытаскивал информацию о порядке запросов за пределы DAL и ограничился бы стандартным подходом.

А я не настаиваю на вытаскивании этой информации из DAL.
Код по ссылке:
private static CategoriesProducts GetAllCategriesAndProducts()
{
    CategoriesProducts categProd = new CategoriesProducts();
    categProd.Categories = new List<Category_SprocResult>();
    categProd.Products = new List<Product_SprocResult>();
    using (var dbContext = new StoreDBEntities())
    {
        var results = dbContext.GetAllCategorisAndProducts();
        //Get first enumerate result set
        categProd.Categories.AddRange(results);
        //Get second result set
        var products = results.GetNextResult<Product_SprocResult>();
        categProd.Products.AddRange(products);
        //Return all result sets
        return categProd;
    }
}


У results и products тип как раз ObjectResult<T>. Почему ты противопоставляешь "стандартный подход" моему?
В моем случае было бы как-то так:
private static CategoriesProducts GetAllCategriesAndProducts()
{
    using (var dbContext = new StoreDBEntities())
    {
        var results = dbContext.GetAllCategorisAndProducts()
                               .Fetch<Category_SprocResult>()
                               .Next<Product_SprocResult>
                               .Result
                               .ToTuple();
        return new CategoriesProducts { Categories = results.Item1, Products = results.Item2 };
    }
}


Порядок типов при выгребании данных важен. С моим подходом он виден лучше.
Re[11]: List+Tuple=Listuple
От: Sinix  
Дата: 19.01.15 14:15
Оценка:
Здравствуйте, artelk, Вы писали:

A>У results и products тип как раз ObjectResult<T>. Почему ты противопоставляешь "стандартный подход" моему?

    categProd.Categories = new List<Category_SprocResult>();
    categProd.Products = new List<Product_SprocResult>();

Клиенту уйдёт готовый список.

A>Порядок типов при выгребании данных важен. С моим подходом он виден лучше.

Только типы другие. И обычно код закладывается на последовательность "прочитали всё, затем вызвали GetNextResult()". Твой вариант может упасть с сторонними провайдерами.
Re[12]: List+Tuple=Listuple
От: artelk  
Дата: 19.01.15 14:22
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, artelk, Вы писали:


A>>У results и products тип как раз ObjectResult<T>. Почему ты противопоставляешь "стандартный подход" моему?

S>
S>    categProd.Categories = new List<Category_SprocResult>();
S>    categProd.Products = new List<Product_SprocResult>();
S>

S>Клиенту уйдёт готовый список.

Ничо не понял. У меня там будет IReadOnlyList<T> вместо List<T>. К этому претензия?

A>>Порядок типов при выгребании данных важен. С моим подходом он виден лучше.

S>Только типы другие. И обычно код закладывается на последовательность "прочитали всё, затем вызвали GetNextResult()". Твой вариант может упасть с сторонними провайдерами.

Конструктор Fetcher сразу делает objectResult.ToList(), все так же будет выполнятся.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.