Skip to content

Instantly share code, notes, and snippets.

@ukitaka
Created February 13, 2017 09:30
Show Gist options
  • Save ukitaka/597041c1ba82e3f0d57f3dbb88d4f907 to your computer and use it in GitHub Desktop.
Save ukitaka/597041c1ba82e3f0d57f3dbb88d4f907 to your computer and use it in GitHub Desktop.
自作の型でもFunctorであれば無理やりCovariantっぽく振舞わせることができる
enum Maybe<A> {
case some(A)
case none
func map<B>(_ f: (A) -> B) -> Maybe<B> {
switch self {
case .some(let a):
return .some(f(a))
case .none:
return .none
}
}
}
protocol Animal { }
struct Dog: Animal { }
let maybeDog: Maybe<Dog> = .some(Dog())
// NG: cannot assign Maybe<Dog> to Maybe<Animal>
// let maybeAnimal: Maybe<Animal> = maybeDog
// NG: cannot convert Maybe<Dog> to Maybe<Animal>
// let maybeAnimal: Maybe<Animal> = maybeDog as! Maybe<Animal>
func id<A>(_ a: A) -> A {
return a
}
// workaround
extension Maybe where A: Animal {
var covariant: Maybe<Animal> {
return map(id)
}
}
// OK
let maybeAnimal: Maybe<Animal> = maybeDog.covariant
func test() -> Maybe<Animal> {
return maybeDog.covariant // OK
}
@ukitaka
Copy link
Author

ukitaka commented Feb 13, 2017

もちろん組み込みの型ならこんなことしなくてもCovariantなので問題ない

// OK
let arrDog: Array<Dog> = [Dog(), Dog(), Dog()]
let arrAnimal: Array<Animal> = arrDog

// OK
let optDog: Optional<Dog> = .some(Dog())
let optAnimal: Optional<Animal> = optDog

@ukitaka
Copy link
Author

ukitaka commented Feb 13, 2017

extension ObservableType where E: Animal {
    var covariant: Observable<Animal> {
        return self.map(id)
    }
}

// NG
//let animal: Observable<Animal> = Observable<Dog>.empty()

// OK
let animal: Observable<Animal> = Observable<Dog>.empty().covariant

@ukitaka
Copy link
Author

ukitaka commented Feb 13, 2017

class Shape {
    var name: String {
        return "Shape"
    }
}

class Rectangle: Shape {
    override var name: String {
        return "Rectangle"
    }
}

class Square: Rectangle {
    override var name: String {
        return "Square"
    }
}

extension Maybe where A: Shape {
    var covariant: Maybe<Shape> {
        return map(id)
    }
}

extension Maybe where A: Rectangle {
    var covariant: Maybe<Rectangle> {
        return map(id)
    }
}

let maybeSquare: Maybe<Square> = .some(Square())
let maybeRectAngle: Maybe<Rectangle> = maybeSquare.covariant
let maybeShape: Maybe<Shape> = maybeSquare.covariant

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment