Здравствуйте, Klapaucius, Вы писали:
K>liftM2 f a b = a >>= \a -> b >>= \b -> return $ f a b
Ага... Ну так тут мы используем знания о типе конкретной монады используя определённый для неё оператор >>=. Если в C++ определить для каждого типа монад такой же оператор, то не будет вообще никаких проблем в аналогичной записи liftM2.
Т.е. например для boost.optional мы определим >>= как
template<typename T, typename F>
auto operator>>=(optional<T> o, F f)->decltype(f(*o)){return f(*o);}
и без проблем записываем liftM2 как
template<template<class>class M, typename R, typename T1, typename T2>
function<M<R>(M<T1>,M<T2>)> liftM2(R (*f)(T1, T2))
{return [=](M<T1> tm1, M<T2> tm2){return tm1>>=[&](T1 t1){return tm2>>=[&](T2 t2)->M<R>{return f(t1, t2);};};};}
И можем протестировать например так:
string add(int v1, double v2) {return to_string(v1+v2);}
cout<<*liftM2<optional>(add)(optional<int>(3), optional<double>(7))<<endl;//выводит 10,000000
Более того, мы можем взять совсем другую монаду, например listM и для той же самой функции add (не говоря уже о liftM2) получим
for(auto& i: liftM2<listM>(add)(listM<int>{1, 2, 3}, listM<double>{3.0, 6.0, 9.0})) cout<<i<<' ';
//выводит 4,000000 7,000000 10,000000 5,000000 8,000000 11,000000 6,000000 9,000000 12,000000
K>Реализовать ее в принципе можно, я-то говорил, что у нее будет несодержательный с точки зрения практической пользы тип (по крайней мере пока в C++ концептов нет).
И в чём несодержательность то? ) Обе функции выглядят один в один, разве что вариант на C++ имеет гораздо больше всякие скобочек и т.п. Если основная претензия к этому, то я в общем то соглашусь. ))) Но насчёт несодержательности непонятно что-то... )
K>Тогда я вообще не понимаю, о чем вы говорите. Где LINQ и где SQL? Какое отношения ограничения sql-я имеют к linq? Какие-там базовые примитивы — если комбинаторы самому писать можно?
Писать то можно... Только кто это делает? ) Почему я вижу определение грамматики через select, where и т.п.? )
K>Суть как раз в этом. Если у вас exp возвращает double, то принимая числа даже меньше 1000 он уже возвращает ерунду. Просто система обработки ерунды встроена в операции с плавучкой. Понятно, что для большинства типов такой автоматической обработки нет и ее нужно организовывать. Кроме того, я сразу написал, что монады нужны для комбинирования функций вида a -> m b, и там же написал что полезно для комбинирования функций других видов. Мне теперь это повторять в каждом предложении?
Суть в том, что на практике монады как раз нужны достаточно редко. А их частое использование в Хаскеле всего лишь следствие некоторых неудобностей языка (которые являются ценой за некоторые особенности, возможно приносящие плюсы, а возможно и нет — это мы так и не выяснили пока).