Re[2]: Монады и STL
От: Курилка Россия http://kirya.narod.ru/
Дата: 23.11.07 17:04
Оценка: +2
Здравствуйте, Maxim S. Shatskih, Вы писали:

DC>>Таким образом, получается operator << и operator >> создают монадный интерфейс ввода/вывода в императивном языке.


MSS>Если я правильно понял хаскеллевские монады, то это как раз _привнесение императивности_ в неимперативный язык.


Имхо ты понял лишь частный случай применения монад.
Re[5]: Монады и STL
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.12.07 11:28
Оценка: +1 :)
Здравствуйте, FR, Вы писали:

MSS>>Таким образом, параллелей в Си++ монада не имеет из-за отсутствия в языке клозур (лямбду можно сделать указателем на функцию, но без клозуры она не интересна).


FR>Замыкание без проблем эмулируется классом — функтором.


А класс-функтор без проблем эмулируется структурами и указателями на фунции, т.е. структрным программированием.

А структрное программирование без проблем эмулируется с помощью ассемблера.

Да здравствует ассемблер!
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Монады и STL
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.07.07 09:21
Оценка: 2 (1)
Здравствуйте, dr.Chaos, Вы писали:

DC>Я понял что ты про определение в ТК, но я туда даже не заглядывал. И подозреваю, что очень отдаленно представляю, что такое функтор и морфизм. Посему увидеть их мне достаточно трудно.


Если есть несколько минут — можно начать отсюда:
http://en.wikibooks.org/wiki/Haskell/Category_theory
Там очень просто и как раз про функторы и монады.

DC>Если я правильно понял то для класса типов Monad морфизм unit — это return, а join — это >>=.


return — да, это unit.
>>= — это bind (:: m a -> (a -> m b) -> m b)
а join — это join (:: m (m a) -> m a). Он определён в Control.Monad.

Связь между ними такая:

join m = m >>= id
m >>= f = join (fmap f m)


L>>Покажи. Я пока не догнал, о чём ты. У манипуляторов тип не похож на bind, IMHO. Ты не об этом?


DC>В той теме Булат рассахаривал IO монаду, вот если представить так выполнение цепочки операторов <<, то выглядит очень похоже.


DC>
DC>ostream &s1 = operator<<(arg1,s0);
DC>ostream &s2 = operator<<(arg2,s1);
DC>


DC>Просто при использовании ФВП монаду совсем не видно.


Понял, меня что смущает — в bind мы связываем монаду с обработкой значения того типа, который эта монада оборачивает.
Т.е. если монада (m a), то обработчик у нас (a -> m b).
У тебя же это значение (:: a) содержит изначально сам обработчик (Out(5)).

Если говорить о схожести, это по моему единственное отличие. Так что больше не буду цепляться
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Монады и STL
От: dr.Chaos Россия Украшения HandMade
Дата: 18.07.07 10:25
Оценка:
Навеяло вот этим
Автор: lomeo
Дата: 12.02.07
.

Вобщем смотрю я на монады и думаю, что все это, что-то мне напоминает.

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

Таким образом, получается operator << и operator >> создают монадный интерфейс ввода/вывода в императивном языке.

Правда тип bind m a->(a->m b)->m b несколько не стыковывается, т.к а и б тут одинаковые, а operator<< принимает не поток, а другой тип. Хотя поток байт можно считать базовым для всех типов или точнее у каждого типа передаваемого в operator << есть преобразование в поток.

Если я ничего не напутал, получается что в имеперативных языках монады таки используются. Причем потоковый ввод/вывод одно из самых красивых, гибких и практичных решений в STL. Правда я сомневаюсь, что создатель знал про монады.
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
Re: Монады и STL
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 18.07.07 15:51
Оценка:
Здравствуйте, dr.Chaos, Вы писали:

DC>Вобщем смотрю я на монады и думаю, что все это, что-то мне напоминает.


DC>Возьмем в С++ operator <<(). Он принимает basic_ostream и возвращает его только в обновленном состоянии, т.е. по сути это операция связывания, а вот действие которое связано спрятано в перегрузках оператора, т.е. по умолчанию это функция преобразования некоторого типа в поток байт. Есть там и действия которые передаются явно (манипуляторы потока). Можно кстати и вывод примерно так представить, но это будет выглядеть некрасиво


Прикольно. Но, мне кажется, это не так. Не буду сейчас говорить о том, что тип не совпадает для bind, но есть одно из отличительных свойств у монад. Это свойство вытекает из ТК-определения монады. Оно говорит о том, что у монады должен быть join.

(Вообще монада -- это функтор с двумя морфизмами — unit :: X -> M X, join :: M (M X) -> M X, где X — это любой объект категории С, над которой определён функтор M).

Так вот, если мы видим, что наш тип, являясь функтором, имеет join, значит, скорее всего это монада. Почему join, а не bind? Мне кажется, потому что его проще увидеть.

Так вот, в случае LINQ во первых — сразу видно, что это функтор (select prop from obj_list -- явный map). Во вторых, связка списков (таблиц, множеств) есть join, он даже в SQL так называется Из объектов одного перечисления мы связкой получаем другие перечисления, а потом объединяем в одно: т.е. IEnumerable<IEnumerable<T>> -> IEnumerable<T>.

В случае ostream что есть join?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Монады и STL
От: dr.Chaos Россия Украшения HandMade
Дата: 18.07.07 16:49
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Здравствуйте, dr.Chaos, Вы писали:


DC>>Вобщем смотрю я на монады и думаю, что все это, что-то мне напоминает.


DC>>Возьмем в С++ operator <<(). Он принимает basic_ostream и возвращает его только в обновленном состоянии, т.е. по сути это операция связывания, а вот действие которое связано спрятано в перегрузках оператора, т.е. по умолчанию это функция преобразования некоторого типа в поток байт. Есть там и действия которые передаются явно (манипуляторы потока). Можно кстати и вывод примерно так представить, но это будет выглядеть некрасиво


L>Прикольно. Но, мне кажется, это не так. Не буду сейчас говорить о том, что тип не совпадает для bind, но есть одно из отличительных свойств у монад. Это свойство вытекает из ТК-определения монады. Оно говорит о том, что у монады должен быть join.


L>(Вообще монада -- это функтор с двумя морфизмами — unit :: X -> M X, join :: M (M X) -> M X, где X — это любой объект категории С, над которой определён функтор M).


Погоди, что есть морфизм, а то я не пойму о чем ты говоришь.

L>Так вот, если мы видим, что наш тип, являясь функтором, имеет join, значит, скорее всего это монада. Почему join, а не bind? Мне кажется, потому что его проще увидеть.


L>Так вот, в случае LINQ во первых — сразу видно, что это функтор (select prop from obj_list -- явный map). Во вторых, связка списков (таблиц, множеств) есть join, он даже в SQL так называется Из объектов одного перечисления мы связкой получаем другие перечисления, а потом объединяем в одно: т.е. IEnumerable<IEnumerable<T>> -> IEnumerable<T>.


L>В случае ostream что есть join?


Что я увидел, так это "неявное" протаскивание параметра по цепочке.

Тут еще такое дело получается что если operator << () параметризовать функтором char->stream<char>, то его реализацию можно будет менять для всех типов. Т.е. это что-то типа перегрузки оператора последовательности.

Просто я в монады только въезжаю, но тут я вижу схожесть того что получаем с помощью монад с тем что сделано в STL. А вот является ли это монадой — .
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
Re[3]: Монады и STL
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 18.07.07 19:57
Оценка:
L>>(Вообще монада -- это функтор с двумя морфизмами — unit :: X -> M X, join :: M (M X) -> M X, где X — это любой объект категории С, над которой определён функтор M).

DC>Погоди, что есть морфизм, а то я не пойму о чем ты говоришь.


Я говорю о том, что понятие "монада" имеет чёткое математическое определение в теории категорий. Следовательно, если случай подпадает под это определение, значит это монада, иначе нет. Грубо говоря, если любой тип можно завернуть в наш, и если из дважды завернутого в наш тип можно сделать единожды, то это монада. Это очень примитивно, на самом деле там ещё несколько условий, но это те, по которым обычно можно сориентироваться.

L>>В случае ostream что есть join?


DC>Что я увидел, так это "неявное" протаскивание параметра по цепочке.


Покажи. Я пока не догнал, о чём ты. У манипуляторов тип не похож на bind, IMHO. Ты не об этом?

DC>Тут еще такое дело получается что если operator << () параметризовать функтором char->stream<char>, то его реализацию можно будет менять для всех типов. Т.е. это что-то типа перегрузки оператора последовательности.


DC>Просто я в монады только въезжаю, но тут я вижу схожесть того что получаем с помощью монад с тем что сделано в STL. А вот является ли это монадой — .


Схожесть — да, наверное, есть. Но, мне кажется, это не монада.
Re[4]: Монады и STL
От: Dusty Россия  
Дата: 19.07.07 05:45
Оценка:
Здравствуйте, lomeo, Вы писали:

DC>>Тут еще такое дело получается что если operator << () параметризовать функтором char->stream<char>, то его реализацию можно будет менять для всех типов. Т.е. это что-то типа перегрузки оператора последовательности.


DC>>Просто я в монады только въезжаю, но тут я вижу схожесть того что получаем с помощью монад с тем что сделано в STL. А вот является ли это монадой — .


L>Схожесть — да, наверное, есть. Но, мне кажется, это не монада.


Если бы ostream после вывода туда char становился бы ostream<char>, после вывода int — ostream<int>, а после вывода CSomeClass — ostream<CSomeClass> (т.е. если бы тип фозвращаемого результата определялся бы типом параметра последнего вызова) — то это была бы монада. А так мы имеем результат применения монады к char (не забудем, что монада — это конструктор типов). Примерный эквивалент ostream на Хаскеле будет такой:
  type Ostream a = WriterT [a] IO ()

а отнюдь не
  type Ostream a = IO а

Приведенная первой конструкция вполне себе может использваться в Хаскелевских EDSL, и она сделана на монадах — но она не монада.
Re[5]: Монады и STL
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.07.07 08:03
Оценка:
Здравствуйте, Dusty, Вы писали:

D>Если бы ostream после вывода туда char становился бы ostream<char>, после вывода int — ostream<int>, а после вывода CSomeClass — ostream<CSomeClass> (т.е. если бы тип фозвращаемого результата определялся бы типом параметра последнего вызова) — то это была бы монада. А так мы имеем результат применения монады к char (не забудем, что монада — это конструктор типов).


Что такое "применение монады к char"?

D>Примерный эквивалент ostream на Хаскеле будет такой:

D>
D>  type Ostream a = WriterT [a] IO ()
D>


Почему?

D>Приведенная первой конструкция вполне себе может использваться в Хаскелевских EDSL, и она сделана на монадах — но она не монада.


Почему не монада? Это же полный аналог IO [a] и значит можно

newtype Ostream a = Ostream { runOstream :: IO [a] }

instance Functor Ostream where
    fmap f (Ostream io) = Ostream $
        do xs <- io
           return (fmap f xs)

instance Monad Ostream where
    return x = Ostream (return [x])
    (Ostream io) >>= f = Ostream $
        do xs <- io
           liftM concat $ runOstream $ mapM f xs


Законы соблюдаются.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Монады и STL
От: dr.Chaos Россия Украшения HandMade
Дата: 19.07.07 09:04
Оценка:
Здравствуйте, lomeo, Вы писали:

L>>>(Вообще монада -- это функтор с двумя морфизмами — unit :: X -> M X, join :: M (M X) -> M X, где X — это любой объект категории С, над которой определён функтор M).


DC>>Погоди, что есть морфизм, а то я не пойму о чем ты говоришь.


L>Я говорю о том, что понятие "монада" имеет чёткое математическое определение в теории категорий. Следовательно, если случай подпадает под это определение, значит это монада, иначе нет. Грубо говоря, если любой тип можно завернуть в наш, и если из дважды завернутого в наш тип можно сделать единожды, то это монада. Это очень примитивно, на самом деле там ещё несколько условий, но это те, по которым обычно можно сориентироваться.


Я понял что ты про определение в ТК, но я туда даже не заглядывал. И подозреваю, что очень отдаленно представляю, что такое функтор и морфизм. Посему увидеть их мне достаточно трудно.

Если я правильно понял то для класса типов Monad морфизм unit — это return, а join — это >>=.

L>>>В случае ostream что есть join?


DC>>Что я увидел, так это "неявное" протаскивание параметра по цепочке.


L>Покажи. Я пока не догнал, о чём ты. У манипуляторов тип не похож на bind, IMHO. Ты не об этом?


В той теме Булат рассахаривал IO монаду, вот если представить так выполнение цепочки операторов <<, то выглядит очень похоже.

ostream &s1 = operator<<(arg1,s0);
ostream &s2 = operator<<(arg2,s1);


Просто при использовании ФВП монаду совсем не видно.

А теперь смотри если мы определим функцию bind:
template<typename Func>
stream& bind(Func f, stream& s)
{
   return f(s);
}


Передать туда мы можем любой функтор, а саму bind переопределить как нам надо.
template<typename T>
struct Out
{
   Out(T p)
   : m_param(toStr(p)),
   : m_size(strlen(m_param))
   {}
   stream& operator() (stream& s)
   {
      s.write(m_param,m_size);
      return s;
   }
 private:
   char* m_param;
   long m_size;
};

template<typename T>
struct In
{
   In(T &p)
   : m_param(p),
   {}
   stream& operator() (stream& s)
   {
      int N = sizeof(T);
      char * raw = new char[N];
      s.read(raw,N);
      m_param = fromStr(raw);
      return s;
   }
 private:
   T& m_param;
};

//В таком случае
//bind(Out(5),cout) <=> cout << 5;
// а
//int n;
//bind(In(n),cin) <=> cin >> n;


Те конкретная операция намертво зашита в соответствующих операторах.

DC>>Тут еще такое дело получается что если operator << () параметризовать функтором char->stream<char>, то его реализацию можно будет менять для всех типов. Т.е. это что-то типа перегрузки оператора последовательности.


DC>>Просто я в монады только въезжаю, но тут я вижу схожесть того что получаем с помощью монад с тем что сделано в STL. А вот является ли это монадой — .


L>Схожесть — да, наверное, есть. Но, мне кажется, это не монада.


До монады не доделали . Но вот направление явно в сторону монад.
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
Re[6]: Монады и STL
От: Dusty Россия  
Дата: 19.07.07 09:41
Оценка:
Здравствуйте, lomeo, Вы писали:

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


D>>А так мы имеем результат применения монады к char (не забудем, что монада — это конструктор типов).


L>Что такое "применение монады к char"?


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

D>>Примерный эквивалент ostream на Хаскеле будет такой:

D>>
D>>  type Ostream a = WriterT [a] IO ()
D>>

L>Почему?
Я вижу два следующих сближающих признака:
1. Протягиваем между вызовами объект потока (явно в С++, неявно в Хаскеле) — и только его.
2. Независимо от типа переданных параметров, функция, возвращающая Ostream a в конечном итоге сводит все к (cenzored) а.
Для настоящей монады оба эти ограничения не работают.

D>>Приведенная первой конструкция вполне себе может использваться в Хаскелевских EDSL, и она сделана на монадах — но она не монада.


L>Почему не монада? Это же полный аналог IO [a] и значит можно

(skip)
L>Законы соблюдаются.
Для IO [a] законы-то соблюдаются... А вот попробуй написать соответствующие инстансы для моего определения Ostream.
Re[7]: Монады и STL
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.07.07 10:27
Оценка:
Здравствуйте, Dusty, Вы писали:

L>>Что такое "применение монады к char"?


D>В терминах С++ — результат инстанцирования шаблона с соответствующим аргументом. В терминах Хаскеля — применение конструктора типов (который является экземпляром класса Monad) к типу. Т.е. IO a — монада, IO Char — результат применения монады IO к Char...

D>Может, выразился неудачно — есть для этого стандартная терминология?

Угу, правильно. Это кажется type application и называется, я просто не понял, о чём ты.

D>>>Примерный эквивалент ostream на Хаскеле будет такой:

D>>>
D>>>  type Ostream a = WriterT [a] IO ()
D>>>

L>>Почему?
D>Я вижу два следующих сближающих признака:
D>1. Протягиваем между вызовами объект потока (явно в С++, неявно в Хаскеле) — и только его.
D>2. Независимо от типа переданных параметров, функция, возвращающая Ostream a в конечном итоге сводит все к (cenzored) а.
D>Для настоящей монады оба эти ограничения не работают.

Всё равно не понял. Как из этого вытекает тип \a -> WriterT [a] IO ()?

L>>Законы соблюдаются.

D>Для IO [a] законы-то соблюдаются... А вот попробуй написать соответствующие инстансы для моего определения Ostream.

OK, только я сделаю его новым типом, а не синонимом.
У синонимов проблемы с type application.

newtype Ostream a = Ostream { runOstream :: WriterT [a] IO () }

ioToOstream = Ostream . WriterT
ostreamToIo = runWriterT . runOstream

instance Functor Ostream where
    fmap f os = ioToOstream $
        do ((), xs) <- ostreamToIo os
           return ((), fmap f xs)
                     
instance Monad Ostream where
    return x = ioToOstream (return ((), [x]))
    os >>= f = ioToOstream $
        do ((), xs) <- ostreamToIo os
           liftM (\((), xs) -> ((), concat xs)) $ ostreamToIo $ mapM f xs


Это практически тот же код, и он также соблюдает законы, т.к. IO [a] изоморфно WriterT [a] IO () по "a".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Монады и STL
От: Dusty Россия  
Дата: 20.07.07 06:21
Оценка:
Здравствуйте, lomeo, Вы писали:

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


D>>Может, выразился неудачно — есть для этого стандартная терминология?

L>Угу, правильно. Это кажется type application и называется, я просто не понял, о чём ты.
Да по английски-то понятно... А по русски — устоявшегося термина нет.

D>>Я вижу два следующих сближающих признака:

D>>1. Протягиваем между вызовами объект потока (явно в С++, неявно в Хаскеле) — и только его.
D>>2. Независимо от типа переданных параметров, функция, возвращающая Ostream a в конечном итоге сводит все к (cenzored) а.
D>>Для настоящей монады оба эти ограничения не работают.
L>Всё равно не понял. Как из этого вытекает тип \a -> WriterT [a] IO ()?
Понятно, что не вытекает автоматом. Просто я а) сформулировал, что мне не нравится в ostream как монаде, б) наткнулся — случайно — на эту аналогию, в) привел его. Может, она и не правильная, но мне помогает...

Кстати: речь у меня идет не о a -> WriterT [a] IO (), а о b -> WriterT [a] IO () (иначе непонятно, с чего бы пункт 2)

L>>>Законы соблюдаются.

D>>Для IO [a] законы-то соблюдаются... А вот попробуй написать соответствующие инстансы для моего определения Ostream.

L>OK, только я сделаю его новым типом, а не синонимом.

L>У синонимов проблемы с type application.
[skip]
Понял. Красивый код...
Но — мне кажется — что перейдя к новому типу, ты разрушил суть моей аналогии. А поскольку это именно аналогия, а не точная эквивалентность — то и смысл потерялся.

Что будет делать твой код, если его перевести на С++? Фаткически — перекодировать файлы (точнее — содержимое потоков) : из ostream<wchar> в ostream<char>, из ostream<char> в ostream<edbic_char> и т.д.
В то же время operator<< перекодирует все, что угодно в char (или wchar — в зависимости от типа потока).

Хотя... Я тут подумал: вывод значений в поток действительно не меняет его типа. Но вот использование манипуляторов — в некотором смысле меняет; только это не отражается в системе типов С++.
В этом смысле можно смотреть на ostream и как на монаду... Но лично мне кажется все-таки, что такой взгляд — контрпродуктивен.
Re[9]: Монады и STL
От: dr.Chaos Россия Украшения HandMade
Дата: 20.07.07 07:52
Оценка:
Здравствуйте, Dusty, Вы писали:

D>Кстати: речь у меня идет не о a -> WriterT [a] IO (), а о b -> WriterT [a] IO () (иначе непонятно, с чего бы пункт 2)


А что a не может таким, же как и b?

L>>>>Законы соблюдаются.

D>>>Для IO [a] законы-то соблюдаются... А вот попробуй написать соответствующие инстансы для моего определения Ostream.

L>>OK, только я сделаю его новым типом, а не синонимом.

L>>У синонимов проблемы с type application.
D>[skip]
D>Понял. Красивый код...
D>Но — мне кажется — что перейдя к новому типу, ты разрушил суть моей аналогии. А поскольку это именно аналогия, а не точная эквивалентность — то и смысл потерялся.

D>Что будет делать твой код, если его перевести на С++? Фаткически — перекодировать файлы (точнее — содержимое потоков) : из ostream<wchar> в ostream<char>, из ostream<char> в ostream<edbic_char> и т.д.

D>В то же время operator<< перекодирует все, что угодно в char (или wchar — в зависимости от типа потока).

Ну если взять iostream, то есть и обратное преобразование.

D>Хотя... Я тут подумал: вывод значений в поток действительно не меняет его типа. Но вот использование манипуляторов — в некотором смысле меняет; только это не отражается в системе типов С++.

D>В этом смысле можно смотреть на ostream и как на монаду... Но лично мне кажется все-таки, что такой взгляд — контрпродуктивен.

Ну тут сама суть ИМХО важна, народ попытался получить гибкое решение, и получил его. Вот только решение очень на монаду смахивает.
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
Re[9]: Монады и STL
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 20.07.07 08:37
Оценка:
Здравствуйте, Dusty, Вы писали:

D>Понятно, что не вытекает автоматом. Просто я а) сформулировал, что мне не нравится в ostream как монаде, б) наткнулся — случайно — на эту аналогию, в) привел его. Может, она и не правильная, но мне помогает...


D>Кстати: речь у меня идет не о a -> WriterT [a] IO (), а о b -> WriterT [a] IO () (иначе непонятно, с чего бы пункт 2)


Ты написал:

type Ostream a = WriterT [a] IO ()


а не

type Ostream b = forall a. WriterT [a] IO ()


Поэтому я и подумал. А так — да.

D>Но — мне кажется — что перейдя к новому типу, ты разрушил суть моей аналогии. А поскольку это именно аналогия, а не точная эквивалентность — то и смысл потерялся.


Да, да, если "b", а не "a", то это совсем не то

D>Что будет делать твой код, если его перевести на С++? Фаткически — перекодировать файлы (точнее — содержимое потоков) : из ostream<wchar> в ostream<char>, из ostream<char> в ostream<edbic_char> и т.д.

D>В то же время operator<< перекодирует все, что угодно в char (или wchar — в зависимости от типа потока).

т.е. это класс Show
Если серьёзно, то dr.Chaos увидел аналогию с монадой, а не саму монаду, а я это неверно понял и стал доказывать, что он ошибается.

D>Хотя... Я тут подумал: вывод значений в поток действительно не меняет его типа. Но вот использование манипуляторов — в некотором смысле меняет; только это не отражается в системе типов С++.

D>В этом смысле можно смотреть на ostream и как на монаду... Но лично мне кажется все-таки, что такой взгляд — контрпродуктивен.

+1
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: Монады и STL
От: Dusty Россия  
Дата: 20.07.07 10:02
Оценка:
Здравствуйте, lomeo, Вы писали:

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


D>>Кстати: речь у меня идет не о a -> WriterT [a] IO (), а о b -> WriterT [a] IO () (иначе непонятно, с чего бы пункт 2)


L>Ты написал:


type Ostream a = WriterT [a] IO ()


L>а не


type Ostream b = forall a. WriterT [a] IO ()


L> Поэтому я и подумал. А так — да.

Не-не-не! Я говорил о том, что С++сному
ostream<char>& operator<<(ostream<char>&, int);

должно соответствовать Хаскелевское
haskell]
(<<) :: Int -> WriterT [Char] IO ()
[/haskell]
Мы говорим о самом классе/типе потока, и забываем, что операции вывода в него — они с параметрами...
А экзистенциальные типы я отнюдь не имел в виду...


D>>Что будет делать твой код, если его перевести на С++? Фаткически — перекодировать файлы (точнее — содержимое потоков) : из ostream<wchar> в ostream<char>, из ostream<char> в ostream<edbic_char> и т.д.

D>>В то же время operator<< перекодирует все, что угодно в char (или wchar — в зависимости от типа потока).

L>т.е. это класс Show

Угу, в некотором роде

L>Если серьёзно, то dr.Chaos увидел аналогию с монадой, а не саму монаду, а я это неверно понял и стал доказывать, что он ошибается.


D>>Хотя... Я тут подумал: вывод значений в поток действительно не меняет его типа. Но вот использование манипуляторов — в некотором смысле меняет; только это не отражается в системе типов С++.

D>>В этом смысле можно смотреть на ostream и как на монаду... Но лично мне кажется все-таки, что такой взгляд — контрпродуктивен.

L>+1
Re[10]: Монады и STL
От: Dusty Россия  
Дата: 20.07.07 10:07
Оценка:
Здравствуйте, dr.Chaos, Вы писали:

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


D>>Кстати: речь у меня идет не о a -> WriterT [a] IO (), а о b -> WriterT [a] IO () (иначе непонятно, с чего бы пункт 2)


DC>А что a не может таким, же как и b?


а может быть таким же, как и b. Но а не может быть не таким, как а.

DC>Ну тут сама суть ИМХО важна, народ попытался получить гибкое решение, и получил его. Вот только решение очень на монаду смахивает.


Только что на IO/ST. На Maybe или List — уже нет, а ведь это тоже примеры монад (если так можно выразиться — "неимперативных").
Re: Монады и STL
От: Maxim S. Shatskih Россия  
Дата: 23.11.07 15:40
Оценка:
DC>Таким образом, получается operator << и operator >> создают монадный интерфейс ввода/вывода в императивном языке.

Если я правильно понял хаскеллевские монады, то это как раз _привнесение императивности_ в неимперативный язык.
Занимайтесь LoveCraftом, а не WarCraftом!
Re[3]: Монады и STL
От: Maxim S. Shatskih Россия  
Дата: 23.11.07 21:24
Оценка:
К>Имхо ты понял лишь частный случай применения монад.

Возможно. Но монадный bind, как я помню, возвращает _лямбду_, при вызове которой возвращается уже объект с измененным состоянием. Си++ ostream::operator<<() возвращает сразу объект.

Таким образом, параллелей в Си++ монада не имеет из-за отсутствия в языке клозур (лямбду можно сделать указателем на функцию, но без клозуры она не интересна).
Занимайтесь LoveCraftом, а не WarCraftом!
Re[4]: Монады и STL
От: FR  
Дата: 24.11.07 12:27
Оценка:
Здравствуйте, Maxim S. Shatskih, Вы писали:

MSS>Таким образом, параллелей в Си++ монада не имеет из-за отсутствия в языке клозур (лямбду можно сделать указателем на функцию, но без клозуры она не интересна).


Замыкание без проблем эмулируется классом — функтором.
Re[6]: Монады и STL
От: Maxim S. Shatskih Россия  
Дата: 06.12.07 11:56
Оценка:
FR>>Замыкание без проблем эмулируется классом — функтором.

VD>А класс-функтор без проблем эмулируется структурами и указателями на фунции, т.е. структрным программированием.


VD>А структрное программирование без проблем эмулируется с помощью ассемблера.


VD>Да здравствует ассемблер!


Я думаю, что интерпретатор Хаскеля именно так и реализован.
Занимайтесь LoveCraftом, а не WarCraftом!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.