前回のunfoldは無限列しか出しません。それをtakewhile止めています。しかし、例えば整数を10進数に分解することを考えます。10で割った余りを出していくと、
shared_ptr<cIterable<int>> digits(int n) { auto f = [] (int n) { return pair<int,int>(n % 10, n / 10); }; return unfold(f, n); } int main() { cout << digits(123) << endl; }
3 2 1 0 0 0 …と延々出力されてしまい、止める方法がありません。
HaskellではMaybeモナドを使うのですが、
import Data.List digits = unfoldr (\n -> if n == 0 then Nothing else Just (mod n 10, div n 10)) main = print (digits 123)
ここでは停止条件を別の引数で与えることにしましょう。状態sの関数を与えて、trueだったらその手前で終わりということにします。その引数を与えなければ止まらないとします。
template<typename T, typename U, typename V, typename W> class cUnfold : public cIterable<T> { T val; U stat; V func; W pred; public: cUnfold(V f, U s, W p) : stat(s), func(f), pred(p) { } bool exists_next() { bool b = !pred(stat); if(b) { pair<T,U> p = func(stat); val = p.first; stat = p.second; } return b; } T value() const { return val; } }; template<typename U, typename V, typename W> auto unfold(V f, U s, W p) -> shared_ptr<cIterable<decltype(f(s).first)>> { typedef decltype(f(s).first) T; return shared_ptr<cIterable<T>>(new cUnfold<T,U,V,W>(f, s, p)); } template<typename U, typename V> auto unfold(V f, U s) -> shared_ptr<cIterable<decltype(f(s).first)>> { typedef decltype(f(s).first) T; auto pred = [] (U s) { return false; }; typedef decltype(pred) W; return shared_ptr<cIterable<T>>(new cUnfold<T,U,V,W>(f, s, pred)); }
これで、3 2 1と出力されるようになります。
shared_ptr<cIterable<int>> digits(int n) { auto f = [] (int n) { return pair<int,int>(n % 10, n / 10); }; auto pred = [] (int s) { return s == 0; }; return unfold(f, n, pred); } int main() { cout << digits(123) << endl; }