Skip to content

Commit

Permalink
Add INIT that works with arbitrary operators (#29)
Browse files Browse the repository at this point in the history
* Add `INIT` that works with arbitrary operators

* Test INIT
  • Loading branch information
tkf committed May 23, 2020
1 parent f0eb049 commit b5b0777
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/src/index.md
Expand Up @@ -6,6 +6,7 @@
```@docs
InitialValues
InitialValues.Init
InitialValues.INIT
InitialValues.@def
InitialValues.@def_monoid
InitialValues.@disambiguate
Expand Down
40 changes: 37 additions & 3 deletions src/InitialValues.jl
Expand Up @@ -6,7 +6,7 @@ module InitialValues
replace(read(path, String), r"^```julia"m => "```jldoctest README")
end InitialValues

export Init, asmonoid
export INIT, Init, asmonoid

"""
Init(op) :: InitialValue
Expand Down Expand Up @@ -55,10 +55,44 @@ An abstract super type of all generic initial value types.
"""
abstract type InitialValue end
abstract type SpecificInitialValue{OP} <: InitialValue end
# abstract type GenericIdentity <: AbstractIdentity end
abstract type NonspecificInitialValue <: InitialValue end

struct TypeOfINIT <: NonspecificInitialValue end

"""
INIT :: InitialValue
A generic initial value. Unlike [`Init`](@ref), this does not detect
an error when `INIT` is used with unintended operations.
# Examples
```jldoctest
julia> using InitialValues
julia> Init(+) * 0 # `Init(op)` must be used with `op`
ERROR: MethodError: no method matching *(::InitialValues.InitialValueOf{typeof(+)}, ::Int64)
[...]
julia> INIT * 123
123
julia> foldl(+, 1:3, init=INIT)
6
"""
const INIT = TypeOfINIT()

function Base.show(io::IO, ::TypeOfINIT) where {OP}
if !get(io, :limit, false)
# Don't show full name in REPL etc.:
print(io, "InitialValues.")
end
print(io, "INIT")
end

struct InitialValueOf{OP} <: SpecificInitialValue{OP} end

const GenericInitialValue{OP} = Union{SpecificInitialValue{OP},NonspecificInitialValue}

function Base.show(io::IO, ::InitialValueOf{OP}) where {OP}
if !get(io, :limit, false)
# Don't show full name in REPL etc.:
Expand All @@ -72,7 +106,7 @@ function Base.show(io::IO, ::InitialValueOf{OP}) where {OP}
end
end

itypeof_impl(op) = :(SpecificInitialValue{typeof($op)})
itypeof_impl(op) = :(GenericInitialValue{typeof($op)})
@eval itypeof(op) = $(itypeof_impl(:op))

"""
Expand Down
8 changes: 8 additions & 0 deletions test/test_basics.jl
Expand Up @@ -8,6 +8,9 @@ OPS = [*, +, |, &, min, max, Base.add_sum, Base.mul_prod]

@testset for op in OPS
@test op(Init(op), :anything) === :anything
@test op(:anything, Init(op)) === :anything
@test op(INIT, :anything) === :anything
@test op(:anything, INIT) === :anything
@test hasinitialvalue(op)
@test hasinitialvalue(typeof(op))
@test isknown(Init(op))
Expand All @@ -26,6 +29,11 @@ end
@test repr(Init(op)) == "InitialValues.$desired"
@test string(Init(op)) == "InitialValues.$desired"
end
@testset "INIT" begin
@test repr(INIT; context=:limit => true) == "INIT"
@test repr(INIT) == "InitialValues.INIT"
@test string(INIT) == "InitialValues.INIT"
end
end

@testset "hasinitialvalue" begin
Expand Down

0 comments on commit b5b0777

Please sign in to comment.