@nospecialize
export TagfulPattern, And, Or,
       Literal, Wildcard,
       Deconstrucution, Guard, Effect,
       untagless, TagfulPattern,
       PatternInfo

abstract type TagfulPattern end


struct PatternInfo
    pattern ::TagfulPattern
    typetag :: TypeObject
end

struct And <: TagfulPattern
    ps :: Vector{PatternInfo}
end

struct Or <: TagfulPattern
    ps :: Vector{PatternInfo}
end

struct Literal{T} <: TagfulPattern
    val :: T
end

struct Wildcard <: TagfulPattern
end

struct Deconstrucution <: TagfulPattern
    comp :: PComp
    extract :: Function
    params :: Vector{PatternInfo}
end

struct Guard <: TagfulPattern
    predicate :: Any
end

struct Effect <: TagfulPattern
    perform :: Any
end

@specialize
function _uncurry_call_argtail(f)
    function (_, args...)
        f(args...)
    end
end
@nospecialize

function untagless(points_of_view::Dict{Function, Int})
    myviewpoint = points_of_view[untagless]
    typetag_viewpoint::Int = points_of_view[tag_extract]
    mk_info(all_info)::PatternInfo = PatternInfo(
        all_info[myviewpoint], all_info[typetag_viewpoint]
    )
    ! = mk_info
    function decons(comp::PComp, extract::Function, ps)
        Deconstrucution(comp, extract, PatternInfo[!p for p in ps])
    end
    and(ps::Vector{Vector{Any}}) = And(PatternInfo[!e for e in ps])
    or(ps::Vector{Vector{Any}}) = Or(PatternInfo[!e for e in ps])

    (
        and = and,
        or = or,
        literal = Literal,
        wildcard = Wildcard(),
        decons = decons,
        guard = Guard,
        effect = Effect
    )
end
@specialize    