Calling elim(hlist)
and elim(tail)
does not provide you any dispatch. Out of 3 overloads of elim()
compiler attempts to pick one at compilation time, and will always use it regardless of value of T
. Looks like compiler attempts to use the last one, which expects HList<End>
.
If I'm not mistaken, what you are trying to achieve is called Generalized abstract data types (GADTs)?, which currently not supported in Swift. But you can emulate them using protocols and visitor pattern:
protocol HList {
func accept<V: HListVisitor>(_ visitor: V) -> V.Result
}
protocol HListVisitor {
associatedtype Result
func visitCons<Head, Tail: HList>(head: Head, tail: Tail) -> Result
func visitEnd() -> Result
}
struct End: HList {
func accept<V: HListVisitor>(_ visitor: V) -> V.Result {
return visitor.visitEnd()
}
}
struct Cons<Head, Tail: HList>: HList {
var head: Head
var tail: Tail
func accept<V: HListVisitor>(_ visitor: V) -> V.Result {
return visitor.visitCons(head: head, tail: tail)
}
}
func elimHList<T: HList>(_ hlist: T) -> Double? {
struct DoubleEliminator: HListVisitor {
func visitCons<Head, Tail: HList>(head: Head, tail: Tail) -> Double? {
if let doubleHead = head as? Double {
return doubleHead
}
return tail.accept(self)
}
func visitEnd() -> Double? {
return nil
}
}
return hlist.accept(DoubleEliminator())
}