Skip to content

Commit 3c70797

Browse files
S. SahmS. Sahm
authored andcommitted
rewrote everything to use Identity, Nothing and Stop
1 parent b38eb6d commit 3c70797

10 files changed

Lines changed: 233 additions & 239 deletions

File tree

src/DataTypesBasic.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,17 @@ functions, we go with Approach 2. That applies to Option, Try and Either.
3030
module DataTypesBasic
3131

3232
export Const,
33-
Identity,
33+
Identity, Stop,
3434
Option, issomething, iftrue, iffalse, getOption, # isnothing, Nothing, Some comes from Base
35-
Either, Left, Right, either, isleft, isright, getleft, getright, getleftOption, getrightOption, getEither, flip_left_right,
36-
Try, Success, Failure, @Try, @TryCatch, issuccess, isfailure, MultipleExceptions,
35+
Either, either, isleft, isright, getleft, getright, getleftOption, getrightOption, flip_left_right,
36+
Try, Failure, @Try, @TryCatch, issuccess, isfailure, MultipleExceptions,
3737
ContextManager, @ContextManager
3838

3939
using IsDef
4040

4141
include("Const.jl")
4242
include("Identity.jl")
43+
include("Stop.jl")
4344
include("Option.jl")
4445
include("Try.jl")
4546
include("Either.jl")

src/Either.jl

Lines changed: 49 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,68 @@
1-
struct Left{L}
2-
value::L
3-
end
4-
5-
struct Right{R}
6-
value::R
7-
end
8-
9-
const Either{L, R} = Union{Left{L}, Right{R}}
10-
Either{L, R}(x::L) where {L, R} = Left(x)
11-
Either{L, R}(x::R) where {L, R} = Right(x)
12-
Either{L}(x::R) where {L, R} = Right(x)
13-
Either{L}(x::L) where {L} = Left(x)
14-
15-
16-
# conversions/ promotions
17-
18-
# typejoin Left & Left
19-
Base.typejoin(::Type{Left{L}}, ::Type{Left{L}}) where L = Left{L}
20-
Base.typejoin(::Type{<:Left}, ::Type{<:Left}) = Left
21-
# typejoin Right & Right
22-
Base.typejoin(::Type{Right{R}}, ::Type{Right{R}}) where R = Right{R}
23-
Base.typejoin(::Type{<:Right}, ::Type{<:Right}) = Right
24-
# typejoin Left & Right
25-
Base.typejoin(::Type{Left{L}}, ::Type{Right{R}}) where {L, R} = Either{L, R}
26-
Base.typejoin(::Type{Right{R}}, ::Type{Left{L}}) where {L, R} = Either{L, R}
27-
# typejoin Left & Either
28-
Base.typejoin(::Type{Left{L}}, ::Type{<:Either{L, R}}) where {L, R} = Either{L, R}
29-
Base.typejoin(::Type{<:Either{L, R}}, ::Type{Left{L}}) where {L, R} = Either{L, R}
30-
Base.typejoin(::Type{<:Left}, ::Type{<:Either{<:Any, R}}) where {R} = Either{<:Any, R}
31-
Base.typejoin(::Type{<:Either{<:Any, R}}, ::Type{<:Left}) where {R} = Either{<:Any, R}
32-
# typejoin Right & Either
33-
Base.typejoin(::Type{Right{R}}, ::Type{<:Either{L, R}}) where {L, R} = Either{L, R}
34-
Base.typejoin(::Type{<:Either{L, R}}, ::Type{Right{R}}) where {L, R} = Either{L, R}
35-
Base.typejoin(::Type{<:Right}, ::Type{<:Either{L}}) where {L} = Either{L}
36-
Base.typejoin(::Type{<:Either{L}}, ::Type{<:Right}) where {L} = Either{L}
1+
const Either{L, R} = Union{Stop{L}, Identity{R}}
2+
Either{L, R}(x::L) where {L, R} = Stop(x)
3+
Either{L, R}(x::R) where {L, R} = Identity(x)
4+
Either{L}(x::R) where {L, R} = Identity(x)
5+
Either{L}(x::L) where {L} = Stop(x)
6+
7+
# Stop is covariate
8+
Base.convert(::Type{Stop{T}}, x::Stop) where {T} = Stop(Base.convert(T, x.value))
9+
promote_rule(::Type{Stop{T}}, ::Type{Stop{S}}) where {T, S<:T} = Stop{T}
10+
11+
12+
# TypeJoin should work with Identity and Either
13+
14+
# typejoin Stop & Identity
15+
Base.typejoin(::Type{Stop{L}}, ::Type{Identity{R}}) where {L, R} = Either{L, R}
16+
Base.typejoin(::Type{Identity{R}}, ::Type{Stop{L}}) where {L, R} = Either{L, R}
17+
# typejoin Stop & Either
18+
Base.typejoin(::Type{Stop{L}}, ::Type{<:Either{L, R}}) where {L, R} = Either{L, R}
19+
Base.typejoin(::Type{<:Either{L, R}}, ::Type{Stop{L}}) where {L, R} = Either{L, R}
20+
Base.typejoin(::Type{<:Stop}, ::Type{<:Either{<:Any, R}}) where {R} = Either{<:Any, R}
21+
Base.typejoin(::Type{<:Either{<:Any, R}}, ::Type{<:Stop}) where {R} = Either{<:Any, R}
22+
# typejoin Identity & Either
23+
Base.typejoin(::Type{Identity{R}}, ::Type{<:Either{L, R}}) where {L, R} = Either{L, R}
24+
Base.typejoin(::Type{<:Either{L, R}}, ::Type{Identity{R}}) where {L, R} = Either{L, R}
25+
Base.typejoin(::Type{<:Identity}, ::Type{<:Either{L}}) where {L} = Either{L}
26+
Base.typejoin(::Type{<:Either{L}}, ::Type{<:Identity}) where {L} = Either{L}
3727
# typejoin Either & Either
3828
Base.typejoin(::Type{<:Either{L, R}}, ::Type{<:Either{L, R}}) where {L, R} = Either{L, R}
3929
Base.typejoin(::Type{<:Either{L}}, ::Type{<:Either{L}}) where {L} = Either{L}
4030
Base.typejoin(::Type{<:Either{<:Any, R}}, ::Type{<:Either{<:Any, R}}) where {R} = Either{<:Any, R}
4131
Base.typejoin(::Type{<:Either}, ::Type{<:Either}) = Either
4232

43-
# Left/Right are covariate
44-
Base.convert(::Type{Right{T}}, x::Right{S}) where {S, T} = Right(Base.convert(T, x.value))
45-
Base.convert(::Type{Left{T}}, x::Left{S}) where {S, T} = Left(Base.convert(T, x.value))
46-
Base.convert(::Type{Either{L, R2}}, x::Right{R}) where {L, R, R2} = Right(Base.convert(R2, x.value))
47-
Base.convert(::Type{Either{L2, R}}, x::Left{L}) where {L, L2, R} = Left(Base.convert(L2, x.value))
48-
promote_rule(::Type{Left{T}}, ::Type{Left{S}}) where {T, S<:T} = Left{T}
49-
promote_rule(::Type{Right{T}}, ::Type{Right{S}}) where {T, S<:T} = Right{T}
33+
# Conversion should also work with Either
34+
Base.convert(::Type{Either{L, R}}, x::Identity) where {L, R} = Identity(Base.convert(R, x.value))
35+
Base.convert(::Type{Either{L, R}}, x::Stop) where {L, R} = Stop(Base.convert(L, x.value))
5036

37+
Base.eltype(::Type{<:Either{L, R}}) where {L, R} = R
38+
Base.eltype(::Type{<:Either{<:Any, R}}) where {R} = R
39+
Base.eltype(::Type{<:Either}) = Any
5140

52-
# == controversy https://github.com/JuliaLang/julia/issues/4648
53-
Base.:(==)(a::Right, b::Right) = a.value == b.value
54-
Base.:(==)(a::Left, b::Right) = false
55-
Base.:(==)(a::Right, b::Left) = false
56-
Base.:(==)(a::Left, b::Left) = a.value == b.value
57-
58-
# TypeClasses.unionall_implementationdetails(::Type{<:Either{L, R}}) where {L, R} = Either{L, R}
59-
# Traits.leaftypes(::Type{Either}) = [Either{newtype(), newtype(), Left}, Either{newtype(), newtype(), Right}]
60-
# Traits.leaftypes(::Type{Either{T}}) where T = [Either{T, newtype(), Left}, Either{T, newtype(), Right}]
6141

42+
# Helpers for Either
43+
# ------------------
6244

6345
function either(left_false, comparison::Bool, right_true)
64-
comparison ? Right(right_true) : Left(left_false)
46+
comparison ? Identity(right_true) : Stop(left_false)
6547
end
6648

67-
flip_left_right(x::Left) = Right(x.value)
68-
flip_left_right(x::Right) = Left(x.value)
69-
70-
isleft(e::Left) = true
71-
isleft(e::Right) = false
49+
flip_left_right(x::Stop) = Identity(x.value)
50+
flip_left_right(x::Identity) = Stop(x.value)
7251

73-
isright(e::Left) = false
74-
isright(e::Right) = true
52+
isleft(e::Stop) = true
53+
isleft(e::Identity) = false
7554

76-
getleft(e::Left) = e.value
77-
getleft(e::Right) = nothing
78-
79-
getright(e::Left) = nothing
80-
getright(e::Right) = e.value
81-
82-
getleftOption(e::Left{L}) where {L} = Some{L}(e.value)
83-
getleftOption(e::Right) = nothing
84-
85-
getrightOption(e::Left) = nothing
86-
getrightOption(e::Right{R}) where {R} = Some{R}(e.value)
87-
88-
Base.get(e::Either) = getright(e)
89-
getOption(e::Either) = getrightOption(e)
90-
91-
Base.eltype(::Type{<:Either{L, R}}) where {L, R} = R
92-
Base.eltype(::Type{<:Left{L}}) where L = Any # we have to specify this clause as otherwise we get ERROR: UndefVarError: R not defined
93-
Base.eltype(::Type{<:Either}) = Any
55+
isright(e::Stop) = false
56+
isright(e::Identity) = true
9457

95-
Base.iterate(e::Right) = e.value, nothing
96-
Base.iterate(e::Right, state) = state
97-
Base.iterate(e::Left) = nothing
58+
getleft(e::Stop) = e.value
59+
# getleft(e::Identity) = nothing # throw an error if getleft is called on Identity
9860

99-
Base.foreach(f, x::Right) = f(x.value); nothing
100-
Base.foreach(f, x::Left) = nothing
61+
# getright(e::Stop) = nothing # throw an error if getright is called on Stop
62+
getright(e::Identity) = e.value
10163

102-
Base.map(f, x::Right) = Right(f(x.value))
103-
Base.map(f, x::Left) = x
64+
getleftOption(e::Stop{L}) where {L} = Identity{L}(e.value)
65+
getleftOption(e::Identity) = nothing
10466

105-
Iterators.flatten(x::Right) = convert(Either, x.value)
106-
Iterators.flatten(x::Left) = x
67+
getrightOption(e::Stop) = nothing
68+
getrightOption(e::Identity{R}) where {R} = e

src/Identity.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
struct Identity{T}
22
value::T
33
end
4+
# == controversy https://github.com/JuliaLang/julia/issues/4648
5+
Base.:(==)(a::Identity, b::Identity) = a.value == b.value
6+
7+
function Base.show(io::IO, x::Identity)
8+
print(io, "Identity($(repr(x.value)))")
9+
end
410

511
Base.get(a::Identity) = a.value
612
Base.eltype(::Type{<:Identity{T}}) where T = T
@@ -11,3 +17,11 @@ Base.iterate(a::Identity, state) = state
1117
Base.foreach(f, a::Identity) = begin f(a); nothing; end
1218
Base.map(f, a::Identity) = Identity(f(a.value))
1319
Base.Iterators.flatten(a::Identity) = convert(Identity, a.value)
20+
21+
# Identity is covariate
22+
Base.convert(::Type{Identity{T}}, x::Identity) where {T} = Identity(Base.convert(T, x.value))
23+
promote_rule(::Type{Identity{T}}, ::Type{Identity{S}}) where {T, S<:T} = Identity{T}
24+
25+
# we need this for safety, if someone overwrites typejoin for Unions with Identiy
26+
Base.typejoin(::Type{Identity{T}}, ::Type{Identity{T}}) where T = Identity{T}
27+
Base.typejoin(::Type{<:Identity}, ::Type{<:Identity}) = Identity

src/Option.jl

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
const Option{T} = Union{Nothing, Some{T}}
1+
# we don't use Some because it does not behave like a container, but more like `Ref`
2+
# for details/update see https://github.com/JuliaLang/julia/issues/35911
3+
const Option{T} = Union{Nothing, Identity{T}}
24

35
Option{T}(a::Nothing) where T = nothing
4-
Option{T}(a::T) where T = Some{T}(a)
6+
Option{T}(a::T) where T = Identity{T}(a)
57
Option(a::Nothing) = nothing
6-
Option(a::T) where T = Some{T}(a)
8+
Option(a::T) where T = Identity{T}(a)
79
Option{T}() where T = nothing
810
Option() = nothing
911

@@ -34,38 +36,21 @@ Base.convert(::Type{Option}, x::Option) = x
3436
# Option{T} seems to be already covered by normal Union, Some, Nothing conversions, no need to provide them
3537

3638
function iftrue(func::Function, b::Bool)
37-
b ? Some(func()) : nothing
39+
b ? Identity(func()) : nothing
3840
end
3941
function iftrue(b::Bool, t)
40-
b ? Some(t) : nothing
42+
b ? Identity(t) : nothing
4143
end
4244
function iffalse(func::Function, b::Bool)
43-
!b ? Some(func()) : nothing
45+
!b ? Identity(func()) : nothing
4446
end
4547
function iffalse(b::Bool, t)
46-
!b ? Some(t) : nothing
48+
!b ? Identity(t) : nothing
4749
end
4850

4951
issomething(m::Nothing) = false
50-
issomething(m::Some) = true
51-
52-
Base.get(m::Some) = m.value
53-
Base.get(m::Nothing) = nothing
52+
issomething(m::Identity) = true
5453

5554
# Base.eltype is not well defined for Some, and always returns Any
5655
Base.eltype(::Type{<:Option{T}}) where {T} = T
5756
Base.eltype(::Type{Nothing}) = Any # if we don't provide this clause, we get ERROR: UndefVarError: T not defined, as the above clause matches, but no T can be infered from Nothing
58-
59-
60-
Base.iterate(o::Some) = o.value, nothing
61-
Base.iterate(o::Some, state) = state
62-
Base.iterate(o::Nothing) = nothing
63-
64-
Base.foreach(f, o::Some) = f(o.value); nothing
65-
Base.foreach(f, o::Nothing) = nothing
66-
67-
Base.map(f, o::Some) = Some(f(o.value))
68-
Base.map(f, ::Nothing) = nothing
69-
70-
Iterators.flatten(x::Nothing) = x
71-
Iterators.flatten(x::Some) = convert(Option, x.value)

src/Stop.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
wrapper to indicate that a computation should stop, including information about the stop
3+
"""
4+
struct Stop{T}
5+
value::T
6+
end
7+
# Stop with no args is just nothing
8+
Stop() = nothing
9+
10+
# == controversy https://github.com/JuliaLang/julia/issues/4648
11+
Base.:(==)(a::Stop, b::Stop) = a.value == b.value
12+
# Stop is a non-container, hence has always eltype Any
13+
Base.eltype(::Type{<:Stop}) = Any
14+
15+
isstop(::Stop) = true
16+
isstop(other) = false
17+
Base.iterate(e::Stop) = nothing
18+
Base.foreach(f, x::Stop) = nothing
19+
Base.map(f, x::Stop) = x
20+
Iterators.flatten(x::Stop) = x
21+
22+
# Stop is covariate
23+
Base.convert(::Type{Stop{T}}, x::Stop) where {T} = Stop(Base.convert(T, x.value))
24+
promote_rule(::Type{Stop{T}}, ::Type{Stop{S}}) where {T, S<:T} = Stop{T}
25+
26+
# we need this for safety, if someone overwrites typejoin for Unions with Stop
27+
Base.typejoin(::Type{Stop{T}}, ::Type{Stop{T}}) where T = Stop{T}
28+
Base.typejoin(::Type{<:Stop}, ::Type{<:Stop}) = Stop

0 commit comments

Comments
 (0)