Monáda (funkcionální programování)
datový typ From Wikipedia, the free encyclopedia
Remove ads
Monáda je funktoriální datový typ vybavený dvěma přirozenými transformacemi umožňujícími asociativní skládání operací nad monádami. Formálně je monáda monoidem v kategorii endofunktorů v kategorii typů (v Haskellu kategorie Hask). Obecně je-li tenzorová kategorie (kde je bifunktor a ), monády jsou monoidy v .
Přirozené transformace jsou u každé monády multiplikace a jednotka splňující a . Ve funkcionálním programování se tyto operace zpravidla nazývají join a unit. Příkladem monády je kontinuace, kde je funkcí z do definovaná jako a speciální operace vázání je , přičemž je .
Monády umožňují formulovat kód s vedlejšími efekty tak, aby byl referenčně transparentní, a tedy „čistý“ (ve funkcionálním smyslu). Monády jsou zpravidla generické a jejich druh je .
Z každého endofunktoru lze vytvořit volnou monádu.
Remove ads
Příklad
Kontinuace v C++ lze reprezentovat (s využitím statického polymorfismu) následující třídou:
template<typename T> class Cont {
std::function<std::any(const std::function<std::any(T)>&)> fn;
public:
Cont(const decltype(fn)& f) : fn(f) {}
Cont(T&& x) : fn([x](auto f) { return f(x); }) {}
std::any operator()(const std::function<std::any(T)>& f) const { return fn(f); }
};
Aby byla Cont funktorem, musíme implementovat fmap nebo bind:
template<template<typename> class M, typename T, typename U> struct Bind;
template<typename T, typename U> struct Bind<Cont,T,U> {
std::function<Cont<U>(T)> f;
auto operator()(const Cont<T>& m) {
return [this,m](auto g) {
return m([this,g](auto x) { return f(x)(g); });
};
}
};
C++ nemá typy vyšších druhů, nicméně pomocí specializace šablon můžeme dosáhnout stejného efektu. Konkrétně můžeme například definovat generické monadické operace fmap a join.
template<template<typename> class M, typename T, typename U> struct Fmap {
std::function<U(T)> f;
auto operator()(const M<T>&) const;
};
template<template<typename> class M, typename T> struct Join {
auto operator()(const M<M<T>>&) const;
};
template<template<typename> class M, typename T, typename U> auto Fmap<M,T,U>::operator()(const M<T>& m) const {
std::cerr << "generic fmap" << std::endl;
return Bind<M,T,U>{[&](auto x) { return M<U>{f(x)}; }}(m);
}
template<template<typename> class M, typename T> auto Join<M,T>::operator()(const M<M<T>>& m) const {
std::cerr << "generic join" << std::endl;
return Bind<M,M<T>,T>{[](M<T> x) { return x; }}(m);
}
Takto koncipovaný kód má tu výhodu, že poskytuje definice monadických funkcí bez ohledu na konkrétní typ. Proto stačí pro konkrétní monadický typ implementovat pouze buď bind, nebo fmap a join, podobně jako v čistě funkcionálních jazycích à la Haskell.
Remove ads
Externí odkazy
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads