struct SesMap{O}
    operator::O
end



@forward SesMap.operator alpha
@forward SesMap.operator theta
@forward SesMap.operator nb_loss



function Base.getproperty(obj::SesMap, sym::Symbol)
    if sym == :operator
        return getfield(obj, sym);
    else
        if isa(obj.operator, AbstractVector)
            return [getproperty(op, sym) for op in obj.operator]
        else
            return getproperty(obj.operator, sym);
        end
    end
end


Base.setproperty!(obj::SesSSM, sym::Symbol) = setproperty!(obj.operator, sym);



function Base.show(io::IO, c::SesMap)
    print(io, "Mapping(\n");
    print(io, c.operator);
    print(io, ")");
end



(map::SesMap{O})(zip::Base.Iterators.Zip) where {O} = map(zip.is)
(map::SesMap{O})(xs::Tuple) where {O} = map(xs...)
(map::SesMap{O})(x::AbstractVecOrMat{I}) where {O, I} = [map.operator(xi) for xi in x]
(map::SesMap{O})(y::AbstractVector{I},
                 x::AbstractVector{T}) where {I, O, T} =
    [map.operator((yi, xi)) for (yi, xi) in zip(y, x)]
(map::SesMap{O})(x::AbstractVecOrMat{I}) where {O<:AbstractVector, I} =
    [op(xi) for (op, xi) in zip(map.operator, x)]
(map::SesMap{O})(x::AbstractVecOrMat{I}) where {O<:AbstractVector, I<:AbstractVector} =
    [op(xi) for (op, xi) in zip(map.operator, x)]




function reset!(map::SesMap)
    if isa(map.operator, AbstractVector)
        for op in map.operator
            reset!(op);
        end
    else
        reset!(map.operator);
    end
end



function restart!(map::SesMap; kwargs...)
    if isa(map.operator, AbstractVector)
        for op in map.operator
            restart!(op; kwargs...);
        end
    else
        restart!(map.operator; kwargs...);
    end
end



function testmode!(map::SesMap, args...; kwargs...)
    if isa(map.operator, AbstractVector)
        for op in map.operator
            testmode!(op, args...; kwargs...);
        end
    else
        testmode!(map.operator, args...; kwargs...);
    end
end



@functor SesMap



trainable(map::SesMap) = if isa(map.operator, AbstractVector)
        (map.operator...,)
    else
        (map.operator,)
    end