import std.algorithm;
import std.range;
import std.traits;
import std.functional;
import std.typetuple;

template scan(alias fun)
{
    auto scan(T, Range)(T start, Range r) if (isInputRange!(Unqual!Range))
    {
        alias binaryFun!fun _fun;
        
        struct Result
        {
            alias Unqual!Range R;
            alias typeof(_fun(T.init, .ElementType!R.init)) ElementType;
            R _input;
            ElementType _front;
            
            this(T start, R input)
            {
                _front = start;
                _input = input;
            }

            static if (isInfinite!R)
            {
                // Propagate infinite-ness.
                enum bool empty = false;
            }
            else
            {
                bool _empty = false;
                @property bool empty()
                {
                    return _empty;
                }
            }

            void popFront()
            {
                static if (!isInfinite!R) {
                    if (_input.empty) {
                        _empty = true;
                    }
                }
                if (!empty) {
                    _front = _fun(_front, _input.front);
                    _input.popFront();
                }
            }
            
            @property auto ref front()
            {
                return _front;
            }
            
            static if (hasLength!R || isSomeString!R)
            {
                @property auto length()
                {
                    return _input.length;
                }

                alias length opDollar;
            }

            static if (isForwardRange!R)
                @property auto save()
                {
                    auto result = this;
                    result._input = result._input.save;
                    return result;
                }
        }

        return Result(start, r);
    }
}

unittest {
    auto arr = scan!((a,b)=>a+b)(0, [1,2,3,4]);
    
    assert(equal(arr, [0,1,3,6,10]));
    
    import std.stdio;
    
    writeln( scan!"a+b"(0, cast(int[])[]) );
}

void main( ) {

}