|
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} |
37 | 27 | # typejoin Either & Either |
38 | 28 | Base.typejoin(::Type{<:Either{L, R}}, ::Type{<:Either{L, R}}) where {L, R} = Either{L, R} |
39 | 29 | Base.typejoin(::Type{<:Either{L}}, ::Type{<:Either{L}}) where {L} = Either{L} |
40 | 30 | Base.typejoin(::Type{<:Either{<:Any, R}}, ::Type{<:Either{<:Any, R}}) where {R} = Either{<:Any, R} |
41 | 31 | Base.typejoin(::Type{<:Either}, ::Type{<:Either}) = Either |
42 | 32 |
|
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)) |
50 | 36 |
|
| 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 |
51 | 40 |
|
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}] |
61 | 41 |
|
| 42 | +# Helpers for Either |
| 43 | +# ------------------ |
62 | 44 |
|
63 | 45 | function either(left_false, comparison::Bool, right_true) |
64 | | - comparison ? Right(right_true) : Left(left_false) |
| 46 | + comparison ? Identity(right_true) : Stop(left_false) |
65 | 47 | end |
66 | 48 |
|
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) |
72 | 51 |
|
73 | | -isright(e::Left) = false |
74 | | -isright(e::Right) = true |
| 52 | +isleft(e::Stop) = true |
| 53 | +isleft(e::Identity) = false |
75 | 54 |
|
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 |
94 | 57 |
|
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 |
98 | 60 |
|
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 |
101 | 63 |
|
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 |
104 | 66 |
|
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 |
0 commit comments