I want to develop a recursive Either type as a Swift enum (at least a partially working version (;), and so have been playing around with generics (trying to work with the type system).
Here is what I have so far:
enum NumericEitherEnum<Left, Right> {
case left(Left)
case right(Right)
var left: Left? {
switch self {
case .left(let leftie) where leftie is NumericEitherEnum<Int, Float>:
return (leftie as? NumericEitherEnum<Int, Float>)?.left // This won't work (obviously)
case .left(let left):
return left
case .right(_):
return nil
}
}
var right: Right? {
switch self {
case .left(_):
return nil
case .right(let right) where right is NumericEitherEnum:
return (right as? NumericEitherEnum)?.right // This assumes the generic parameters of Left, Right in the current enum so won't work.
case .right(let right):
return right
}
}
}
I get cryptic diagnostic error messages in Xcode, which I haven't been able to get around:
- 'Replace
(leftie as? NumericEitherEnum<Int, Float>)?withNumericEitherEnum<Int, Float>' - 'Enum case 'left' cannot be used as an instance member'
What I am trying to achieve:
print(NumericEitherEnum<NumericEitherEnum<Int, Float>, NumericEitherEnum<Int, Float>>.left(.left(3)).left ?? "failed :(") // Parses the innermost value 3
The fix-it doesn't fix the error or advise how to actually address the underlying cause. I think this is probably an edge case for the compiler to parse (maybe even bug) ;). I also realise that in fact it doesn't make sense logically to return an Int for a Left? type but is there any way I can express this within the type system (I tried associated types but I still don't know how to make this dynamic). There's also a problem to handle nested enums that have a different generic type signature (not sure how to express this).
How can I resolve this issue in a better way? Ideally, I want to have a clean call site without too much indirection and extra data structures but would be open to trying out a different data structure if this isn't practically achievable.