Haskellの<$>と<*>をC++で書いてみる
はじめに
これは実用的でゎなぃ
無駄にcompile-timeを増やしているだけな気が
もともとは<$>
演算子と<*>
演算子を定義できないかな?
って思って試しに検討してみたものです
C++では、オーバーロードできる演算子が制限されているので
もちろんこんな事はできないです
しかし非常に近い事はできそうです
今回は<$>
を<Fa>
に、<*>
を<Ap>
に代用させて作ってみました
(好きな演算子を自由に定義できるようにならないかな・・・)
以下の順序で実装を検討します
-とても簡単な多相型(Box型)
- Maybe型の改造
-<Fa>
演算子
-<Ap>
演算子
Box型
部分適応した関数を保有させる必要があります
なので以前作ったものから、抜本的に改造する必要があります
今回はMaybe型からNothing判定を削った、つまりただの箱の多相型
を使って話を進めます
まず、以前のように内部変数を指定した具体型で受取るような方式を
考えてみます
途中まで考察していたのですがやめました
やはりMaybe型をベースに考えます
Maybe型(その1)
template<typename A> struct Maybe { enum{Nothing=false,Just} Opt; A a_; Opt b_; Maybe(A a):a_(a),b_(Just ){} Maybe( ):a_( ).b_(Nothing){} A get(){return (b_)?a_:0;} }; template<typename A> Maybe<A> Just(A a) { return Maybe<A>(A a); } template<typename A=int> Maybe<A> Nothing( ) { return Maybe<A>( ); }
そのままですね
A=std::function<R(Args...)>
であっても
そのまま受取ればよいです
次にfmap関数を定義します
// bind1stを定義 template<typename F,typename A> auto bind1st(F f,A a) {return[=](auto... args){ return f(a,args...); };} // function<B(A)>とBox<A>を受取ってBox<B>を返す template<typename B> friend auto fmap(std::function<B(A)> f, Maybe a)->Maybe<B> { // Maybeではここで評価している return (a.b_) ? Maybe<B>( f(a.a_) ) : Maybe<B>( ); } // function<B(A,Args...)>とBox<A>を受取ってBox<std::function<B(Args...)>>を返す template<typename B,typename... Args> friend auto fmap(std::function<B(A,Args...)> f, Maybe a)->May<std::function<B(Args...)>> { // Maybeではここで評価している return (a.b_) ? Maybe<std::function<B(Args...)>>( my::bind1st(f,a.a_) ) : Maybe<std::function<A(Args...)>>(); }
こちらは結構改造する必要があります
まずfmapが受取る関数の引数が1つとは限らなくなります
そのため
1.関数型Func<B(A)>
とMaybe型Maybe<B>
を受取って、Maybe型Maybe<B>
を返すfmap関数と
2.関数型Func<B(A,...)>
とMaybe型Maybe<B>
を受取って、Maybe型Maybe<Func<B(...)>>
を返すfmap関数
の2種類の関数をオーバーロードする必要があります
これはめんどくさい・・・
bind_1_関数は定形ですが
新しい型を定義するたびに、この2つのfmap関数を書かねばなりません
Maybe型(その2)
次に、そもそも関数型を保持するように改造してみます
template<typename F> struct Maybe {}; template<typename A,typenaem... Ts> struct Maybe<std::function<A(Ts...)>> { using F = std::function<A(Ts...)>; enum : bool {Nothing=false,Just} Opt; F a_; Opt b_; Maybe(F a):a_(a),b_(Just ){} Maybe( ):a_( ).b_(Nothing){} A get(){return (b_)?a_():0;} }; template<typename A> Maybe<A> Just(A a) { return Maybe<std::function<A()>>([=]{return a;}); } template<typename A=int> Maybe<A> Nothing( ) { return Maybe<std::function<A()>>( ); }
以前との違いは値をそのまま保有せずにlambda式で包んで持っているところです
そのため、Just関数では引き数をlambdaに包んでコンストラクタに引き渡しています
また関数型がそのまま渡される場合のコンストラクタを定義してあげる必要があります
(変わりに値型のコンストラクタは不要になります)
また、この場合は型引数としてstd::functionで分岐する必要がないので 以下のように戻り値型と引き数型だけ受取ってもできます
template<typename A,typenaem... Ts> struct Maybe { using F = std::function<A(Ts...)>; enum : bool {Nothing=false,Just} Opt; F a_; Opt b_; Maybe(F a):a_(a),b_(Just ){} Maybe( ):a_( ).b_(Nothing){} A get(){return (b_)?a_():0;} }; template<typename A> Maybe<A> Just(A a) { return Maybe<A>([=]{return a;}); } template<typename A=int> Maybe<A> Nothing( ) { return Maybe<A>( ); }
fmap関数の定義
HaskellではMaybe型のfmap関数は以下のように定義されています
instance Functor Maybe where fmap :: (a -> b) -> f a -> f b fmap _ (Nothing) = Nothing fmap f (Just a) = just ( f a )
Maybe(その2)型にinstanceされたfmapは以下のようになります
// bind1stを定義 template<typename F,typename A> auto bind1st(F f,A a) {return[=](auto... args){ return f(a,args...); };} template<typename A, typename... Ts> struct Maybe { //... template<typename B,typename... Args> friend auto fmap(std::function<B(A,Args...)> f, Maybe a) -> Maybe<B,Args...> { // Maybeではここで評価している -> a_ではなくa_() return (a.b_) ? Maybe<B,Args...>( my::bind1st(f,a_()) ) : Maybe<B,Args...>(); } //... };
Maybe(その1)と比較した場合に
この方式は大きなメリットが一つあります
それは実装者が再定義するfmap関数が一つになる事です
liftA関数の定義
同様にしてliftA関数も定義します HaskellではMaybe型のliftA関数は以下のように定義されています
instance Applicative Maybe where liftA :: f (a -> b) -> f a -> f b liftA _ (Nothing) = Nothing liftA (Just f) (Just a) = Just (f a)
関数型を格納できるFanctor型クラスが
Applicative Functor型クラスになります
と言うわけで、C++での実装は以下のようになります
template<typename A, typename... Ts> struct Maybe { //... template<typename B,typename... Args> friend auto lift( Maybe<B,A,Args...> f, Maybe a) -> Maybe<B,Args...> { // Maybeではここで評価している -> a_ではなくa_() return (a.b_) ? Maybe<B,Args...>( my::bind1st(f.a_,a_()) ) : Maybe<B,Args...>(); } //... };
あとはこの二つを演算子で呼び出せれば完成です
<Fa>
の定義方針
最終的にはA<Fa>B
をfmap(A,B)
に置き換えます
置き換えるまでに、2つの型を経由しています
// 2つめ template<typename F> struct Fa_impl_{}; //dummy template<typename R, typename Arg1, typename... Args> struct Fa_impl_<std::function<R(Arg1,Args...)>> { std::function<R(Arg1,Args...)> f_; Fa_impl_(std::function<R(Arg1,Args...)> f):f_(f){} template<template<typename...>class T,typename A> friend auto operator>(Fa_impl_ f,T<A> t)-> T<R,Args...> {return fmap(f.f_,t);} }; // 1つめ struct Fa_{ template<typename F> friend Fa_impl_<F> operator<(F f,Fa_){return Fa_impl_<F>(f);} } Fa;
一つ目の型はFa_
型です
この型は唯一つの関数として<
演算子を持っています
<
演算子はfriend関数で、引き数として右辺に自分の型(Fa_
)を取ります
左辺には任意の型を取ります
これは1つ以上の引き数をもつstd::function型でなければなりません
この関数は返し値としてFa_impl_
型の値を返します
そして二つ目の型がこのFa_impl_
型です
この関数はコンストラクタと<
演算子を持っています
コンストラクタはクラステンプレートの型引数で指定した型を引き数に取ります
ここでは部分特殊化を利用し、引き数を1つ以上持つ関数でなければ受取れないようになっています
問題なく関数型の型引き数を受取れば、実体化します
>
演算子はfriend関数で、引き数として左辺に自分の型(Fa_impl_
)を取ります
そして右辺には任意の型を取ります
こちらも制限があり、Fa_impl_インスタンス化の際にクラステンプレートの型引数で指定した関数型の第1引き数と
同じ型を型引き数にもつ別のクラステンプレートのみを受取る事ができます
無事に型制約を満たし他場合にはfmap関数を呼び出しコンストラクタで受取った関数型と左辺を引き数に呼び出します
したがって、全体の処理を追って行くと、以下のようになります
std::function<B(A)> f; Maybe<A> m; auto a = f <Fa> m; // auto a = f < Fa > m; // auto a = ( f < Fa ) > m; // auto a = Fa_impl_{} > m; // auto a = fmap(f,m);
このようにして、左から順に型が置き換わっていき、最終的にfmapが呼ばれます
<Ap>
の定義方針
<Fa>
同様に最終的にはlift(A,B)
に置き換えます
template<typename F> struct Ap_impl_{}; //dummy template<template<typename...>class T, typename A, typename... Args> struct Ap_impl_<T<std::function<R(A,Args...)>>>{ T<std::function<R(A,Args...)>> t_; Ap_impl_(T<std::function<R(A,Args...)>> t):t_(t){} template<typename A> friend auto operator>(Ap_impl_ a,T<A> t) -> T<Args...> {return lift(a.t_,t);} }; struct Ap_{ template<typename F> friend Ap_impl_<F> operator<(F f,Ap_){return Ap_impl_<F>(f);} } Ap;
まとめ
後で書く
勝手にplaceholderを補正してくれるbind
前回作ったmake_placeholderを利用したもの
http://melpon.org/wandbox/permlink/gz7q4bMgPhLh9Xz7
Generic lambdaを使用したもの
N個のplaceholderを作って展開する
はじめに
任意の関数型変数を引き数として受取り、
第1引数を1にbindしてretrunする方法に関してのメモです
template<typename R, typename A,typename... Args> auto bind_1_1(std::function<R(A,Args...) f> { return //std::bind(f,1,make_placeholders<Args...>{}...); //理想イメージ } int main() { std::function<int(int,int,int,int)> f = [](int x,int y,int z,int w){return x+y+z+w;} std::function<int(int.int,int)> g = bind_1_1(f) //=> [](int y,int z,int w){return 1+y+z+w;} }
こんなの
独自のplaceholder
標準ライブラリのほうでstd::placeholder::_N
(Nは1,2,3,...)などが用意されています
std::bind
は関数のすべて引数を変数・定数で束縛するために使用されますが
std::placeholder::_N
を使うと,引数を引数で束縛する事が可能になります.
std::function<int(int,int)> f = [](int x,int y){ return x+y; } auto g = std::bind(f,3,5) //=> []( ){ return 3+5; } auto h = std::bind(f,3,std::placeholder::_1); //=> [](int i){ return 3+i; }
最初に行う準備として
non-template parameter(ようはint)引数で整数を受取れる
class template(構造体)を定義し、std::placehoder
と関連付けをします
//独自のplaceholder namespace my{ template<int N> struct placehoder{}; } namespace std { template<int N> struct is_placeholder<my::placeholder<N>> : public integral_constant<int, N> {}; }
これをやると例えばmy::placeholder<1>
はstd::placeholder::_1
と
同じ働きをするようになります
数値Nを受取り、1~Nまでの数列の生成する
これは簡単ですね
//Ns...をただ包むだけの型 template<int... Ns> struct num_pack {}; // num_pack<1,2,3,...>という用に定数リストを持てる template<int N,int Ns...> struct num_pack_impl //otherwise { typedef typename num_pack_impl<N-1,N,Ns...>::type type; }; template<int... Ns> struct num_pack_impl<1,Ns...> //<1,...> { typedef num_pack<1,Ns...> type; } template<typename... Args> using num_sequence = typename num_pack_impl<sizeof...(Args)>::type; // num_pack<1,2,...,(sizeof...(Args))>
これで 例えばnum_sequence<int,int,int,int,int>
はnum_pack_impl<5>::type
となり
num_pack<1,2,3,4,5>
になります
placeholdersの作成
上記を利用して作ります
// template<typename R, typename A,typename... Args,int... Ns> auto bind_1_1_impl(std::function<R(A,Args...)> f, num_pack<Ns...> ) { return std::bind( f, 1, placeholder<Ns>{}... ); } //ユーザーが呼び出すほうの関数 template<typename R, typename A,typename... Args> auto bind_1_1(std::function<R(A,Args...) > f> { return bind_1_1_impl( f, num_pack_impl<Args...>{} ); //bind_1_1impleを呼び出す }
ここで,my::placeholder<Ns>...
と言うものがありますが,Ns...=1,2,3
の場合
my::placeholder<Ns>...
はmy::placeholder<1>,my::placeholder<2>,my::placeholder<3>
となります.
また,<Args...>
からnum_sequence関数を使って<Ns...>
を作る事は出来ますが
<Ns...>
型からNs...
型を取り出してmy::placeholder
の型引数などに利用するためには,
補助関数bind_1_1_impl
を用意してやる必要があります
まとめ
上記をまとめると以下のようになります
#include <iostream> #include <functional> //独自のplaceholder namespace my{ template<int N> struct placeholder{}; } namespace std { template<int N> struct is_placeholder<my::placeholder<N>> : public integral_constant<int, N> {}; } template<int... Ns> struct num_pack {}; template<int N,int... Ns> struct num_sequence { typedef typename num_sequence<N-1,N,Ns...>::type type; }; template<int... Ns> struct num_sequence<1,Ns...> { typedef num_pack<1,Ns...> type; }; template<typename... Args> using num_pack_impl_= typename num_sequence<sizeof...(Args)>::type; template<typename R, typename A,typename... Args,int... Ns> auto bind_1_1(std::function<R(A,Args...)> f, num_pack<Ns...> ) { return std::bind( f, 1, my::placeholder<Ns>{}... ); } // userが使用するほう template<typename R, typename A,typename... Args> auto bind_1_1(std::function<R(A,Args...)> f) { return bind_1_1(f,num_pack_impl_<Args...>{}); } int main(){ std::function<int(int,int,int,int)> f1 = [](int a,int b,int c,int d){return a+b+c+d;}; auto a= bind_1_1(f1); std::cout<< a(1000,100,10) <<std::endl; }
http://melpon.org/wandbox/permlink/5NfIBcn0ZjDjN1vz
参考:
http://stackoverflow.com/questions/21192659/variadic-templates-and-stdbind
https://gist.github.com/anonymous/400983
HaskellをC++で書いてみる(getLineとputStrLineとIO型とMonad型クラス)
はじめに
また性懲りもなく
今回は以前にもまして穴だらけですが
いつか理解できるまでの手前用のメモとして
IO型
(いつかリベンジしたい)
Haskellでは以下のように定義されています
--data IO a *->* newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
IO型は(GHCでは)newtype
で定義されています
しかし、私はIOの定義を理解できていません
今回は関数型(function型)を内部に保持する型として再現を試みましたが
これから勉強をして、この定義を理解したときにリベンジしたいと思います
(あ、絶対にしないやつだわ、これ)
C++では以下のようにしてみました
template<typename T> struct IO { std::function<T()> f_; IO(std::function<T()>const& f):f_(f){} IO(std::function<T()>&& f):f_(f){} ~IO()=default; T operator*( ) { return f_(); } };
main(IO型)
-- main main :: IO ()
実はmain
は少しだけ他のIO()
型とは異なるようで
main
の変数に束縛?(=)したIO()
型の変数は実行時に評価されるようです
また(>>)
演算子を使う事で、以前のIO()
型変数を棄てて新しいIO
()型変数を
再代入できるので、複数のIO()
型変数を評価する事も可能なようです
私の頭ではIO()
型とはぜんぜん別物ではないのか?となりました
というか、それ以外の解が思いつきませんでした・・・
ということでC++では別の型を作りました
(これもいつかリベンジしたいです)
// Main :: IO () struct Main : IO<void> { static void run(IO<void>>const& io) { a.f_(); } Main():IO<void>([]{}){} Main& operator=(IO<void>&& i){ run(std::list<IO_>(l)); } Main(std::initializer_list<IO_>&& l):IO<void>([]()->void{}){ run(std::list<IO_>(l)); };
ようは代入演算子で受取ったIO()
型変数を
実行するだけの型です
getLine関数
-- getLine getLine :: IO String
標準入力(コンソール)から値を貰い、文字列に変換します
std::cin
をラップしただけでいけますね
// (stdio) -> IO String auto getLine() { return IO<std::string>( []{ std::string a; std::cin >> a; return std::to_string(a); } ); }
lambdaの中が結構冗長な感じになりました
putStrLn関数
-- putStrLn putStrLn :: String -> IO ()
文字列を標準出力する関数です
std::cout
をラップしただけでいけますね
// String -> IO () auto putStrLn( std::string const& a ) { return IO<void>( [&]{ std::cout << a; } ); } auto putStrLn( std::string && a ) { return IO<void>( [a=std::move(a)]{ std::cout << a; } ); }
一応(無駄に)左辺値参照版と右辺値参照版を作りました
Monad型クラス
これだけでも標準入力HalloWorldできるんですが
ついでにMonad型クラスも作って継承させましょう
Monad型クラスでは(>>=)
演算子とreturn
関数を定義してやる必要があります
どちらも名前だけ作って実装は省略します
(継承先で再実装するので)
class Monad m where return :: a -> m a (>>=) :: m a -> ( a -> m b ) -> m b -- (>>) :: m a -> m b -> m b fail :: String -> m a
またMonadの型クラスになれる型は多相型です
多相型でなかった場合に、型エラーがでるよう、
コンストラクタを=delete
して
多相型用の部分特殊化を用意します
本来は右辺の中身を左辺に移す(>>)
演算子や文字列を受取ってM<A>
を返すfail
関数が必要なのですが
今回は・・・その・・・面倒・・・申し訳なく・・・
template<typename Derived> class Monad { Monad()=delete; }; template<template<typename...>class D,typename A> class Monad<D<A>> { template<typename B,typename C> friend auto operator>>=( Monad<D<A>> const& a, std::function<Monad<D<B>>(C)> const& f ) -> D<B>; template<typename B> friend auto return_( B const& a ) -> D<A>; //template<typename B> //friend auto operator>>( Monad<D<A>> const& a, Monad<D<B>> const& b) -> Monad<D<B>> //{ // return b; //} };
次に継承先での実装(instance)を書きます
template<typename A> struct IO : Monad< IO<A> > { std::function<A()> f_; IO(std::function<A()>const& f):f_(f){} IO(std::function<A()>&& f):f_(f){} ~IO()=default; A operator+( ) { return f_(); } // instance Monad A where template<typename B> friend auto operator>>=( IO&& a, std::function<IO<B>(A)>&& f ) -> IO<B> { return f( a.f_() ); } friend auto return_( A const& a ) -> IO<A> { return IO<A>( [&]{return a;} ); } };
使い方
int main() { Main = getLine >>= putStrLine >> getLine >>= putStrLine }
これで動いてくれたらさぞ面白かったですが 演算子の優先度を見ると 以下のようになっております
int main() { ( Main = getLine ) >>= ( putStrLine >> getLine ) >>= putStrLine }
(>>=)
演算子を()で包んでもまだ以下のようになります
int main() { Main = ( ( getLine >>= putStrLine ) >> ( getLine >>= putStrLine ) ) }
と言うわけで、考え直さないといけません
Mainの再現について
Main
なのですが、私は結局以下のようにしました
{ static void run(std::list<IO_>const& l) { for(auto& a : l) a.f_(); } Main(std::initializer_list<IO_>&& l):IO<void>([]()->void{}){ run(std::list<IO_>(l)); } };
ようはstd::initializer_list
で複数のIO()
を受取れるようになっています
つまり、(>>)
演算を使用したMain()
への再代入を棄てて、
処理したいIO()
型リストを受取とって順に実行するようにもういろいろと妥協しました
と言うわけで、今回のIOアクションは以下のように書きます
int main()
{
Main = {
getLine >>= putStrLine,
getLine >>= putStrLine
};
}
だいぶ良さそうになりました
だいぶ良さそうになったのですが
もちろんまだ失敗します(おい)
constexprとlambda式
私的メモ
clangとgccで挙動が全く違います
しかも私自身規格を読んでいないので、
どちらが正しいのか全くわかっていません
http://melpon.org/wandbox/permlink/lUzXqVVTIf7dglD9
あとで何とかする
追記:どうやらconstexprはリテラルでないといけなくて
リテラルでないものの中にlambdaがあるそうです
ということで、エラーになるclangの挙動の方が正しいようです
うーん
参照:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3597.html
http://cpplover.blogspot.jp/2014/06/lambdaconstexpr.html
HaskellをC++で書いてみる(多相型(Maybe型)とFunctor型クラス)
はじめに
前回、単相型(具体型)とEq型クラスを作ったので
今回は多相型とFunctor型クラスを作成します
多相型(polymorphic type)に関して
例えばHaskellのList型は
[1,2,3,4]でも[1.0,2.0,3.0,4.0]でも['1','2','3','4']でも
どんな型でもListと呼ばれます
これはその無数の型に対するList型を定義しているわけではなくて
特定の型を取って、そのList型をつくる型のテンプレートのようなものが
定義されているからです
これを多相型といいます
多相型は具体型を型引数にとることで具体型になりますが
その振る舞いは多相型に定義されています
例えば、List型は型引数Intを取ることで
Int型の値を複数保持できるInt-List型になります
この振る舞いや型クラスはList型の方に書かれてあります
まんまC++のclass template、もしくはC#のジェネリックですね
List同様にMaybe型も多相型です
Maybe型
「これは結果を返しそこなうかもしれない計算の型を表現しています」
で有名なMaybe型です。
ようは、Int型に対して0でも-2147483648でもなく
「計算が失敗した」と言う状態をもたせることができる型です
他にも、MapでKey対応するValueがなかった場合などを表現したりします
C++だとboostにある(次回のC++17ではstdに入るらしい)optional型、
C#だとOption型が該当しますね
Haskellでは以下のように定義されています
Maybe a = Nothing | Just a --derivingは省略
C++で(あえて)書いてみると以下のようになります
template<typename A> struct Maybe { A a_; bool none_; Maybe(A const& a):a_(a),none_(fales){} // Just a Maybe( ):a_( ),none_(true){} // Nothing };
しかしこれだけでは足りません
HaskellではNothingあるいはJust*でMaybe型を作成するので
C++も同じようにMaybe型を作成する関数を作ってあげないといけません
これはFactoryパターンで実装できそうです
template<typename A> auto Just( A const& a ) -> Maybe<A> { return Maybe(a); } template<typename A=int> auto Nothing( ) -> Maybe<A> { return Maybe( ); }
- 直和型ではない件について
HaskellのMaybeは直和型、つまりは複数の定義(Just aかNothing)
のうちどちらか一方を値として持ちます。
しかし今回C++で作成したMaybeは直積型で表現したメンバ変数がそれぞれ値を持ち、
これらの組み合わせで、2つの状態(Just aなのかNothingなのか)
を再現しているにすぎません
そのため厳密には別物です。
本来なら、Maybe型はNothing型とJust型の両方をとる(型安全な)共用体型(boost.variant)
として定義し、両方を保持できるべきなのです
これをvariant型に置き換えるか否かは非常に考えどころですが
現状はこのまま進めていきます
(この先、困ったときに修正することにします。遅延評価というやつです)
Functor型クラス(というかfmap)に関して
Functorは型クラスで、fmap関数を持っています
というかFunctor型クラスである条件はfmap関数が定義されている事だけです
いわゆるデフォルト実装を持たない型クラスですので
前回同様に関数のインスタンス宣言と実装を追記します
(インスタンスの自動導出はC++では私の能力ではちょっと難しい・・・)
まずはHaskellのMaybeにおけるfmap関数の実装を見てみます
instance Functor Maybe where fmap f (Just x) = Just (f x) fmap f Nothing = Nothing
Just aかNothingでパターンマッチをしていますね
これは現在のMaybeでは扱えません
(JustとNothingを型としてMaybeが保有すればできたかもですが・・・)
べつの方法をとる必要があります。
今回は、普通にMaybe内部の値none_を3項演算子の分岐条件にし
fを適応する(Just(f a))か、しないか(Nothing)分岐して返すようにしました
//Fanctor template<typename B> friend auto fmap( std::function<B(A)> const& f, Maybe<A> const& a ) -> Maybe<B> { return (a) ? (Maybe<B>(f(a.a_))) : (Maybe<B>()); }
完成?
template<typename A> struct Maybe { private: A a_; bool none_; Maybe(A const& a):a_(a),none_(false){} // Just a Maybe( ):a_( ),none_(true){} // Nothing // Functor type class methed (fmap) template<typename B> friend auto fmap( std::function<B(A)> const& f, Maybe<A> const& a ) -> Maybe<B> { return (a.none_) ? (Maybe<B>()) : (Maybe<B>(f(a.a_))); } }; //値コンストラクタ(Factoryパターン) template<typename B> auto Just( B const& a ) -> Maybe<B> { return Maybe<>(a); } template<typename B=int> auto Nothing( ) -> Maybe<B> { return Maybe<>( ); }
http://melpon.org/wandbox/permlink/s23nt3iWCVWeRhKi
http://melpon.org/wandbox/permlink/eMT4ofGS7tAdlpFm
おまけ:遅延評価
値コンストラクタがわりのFactoryパターンを含め
すべてのMaybe型返し値を引数のないstd::function<Maybe<A>()>
で返せば
遅延評価みたいになります
以下はそれを愚直に実装したものです
http://melpon.org/wandbox/permlink/vFna69sy9g4jC0r2
書いてて、IO<T>
の実装をしたくなりましたので、近日いろいろ考察してみたいですね