$30 off During Our Annual Pro Sale. View Details »

Swiftで高カインド多相

 Swiftで高カインド多相

potatotips #52 iOS/Android開発Tips共有会 (Jun 21, 2018)
https://potatotips.connpass.com/event/88164/

Library: https://github.com/inamiy/HigherKindSwift

Yasuhiro Inami

June 21, 2018
Tweet

More Decks by Yasuhiro Inami

Other Decks in Programming

Transcript

  1. SwiftͰ
    ߴΧΠϯυଟ૬
    (Higher Kinded Types)
    2018/06/21 potatotips #52 (iOS/Android։ൃTipsڞ༗ձ)
    Yasuhiro Inami / @inamiy

    View Slide

  2. View Slide

  3. ߴΧΠϯυଟ૬ʢͷ༧උ஌ࣝʣ
    • ܕίϯετϥΫλ ʹ ʮܕʯΛҾ਺ʹऔΓɺʮܕʯΛฦ͢
    • ྫɿ Optional = 1 + X ʹ͓͚Δ "Optional" ͸ɺ
    ʮܕ → ܕʯʹม׵͢Δʮܕؔ਺ʯ
    • ΧΠϯυ ʹ ʮܕͷܕʯ
    • ྫɿ Optional : *ɹʢܕʣ
    • ྫɿ Optional : * -> *ɹʢܕ → ܕʣ

    View Slide

  4. ߴΧΠϯυଟ૬
    • ߴΧΠϯυ ʹ ʮΧΠϯυʯΛҾ਺ʹऔΓɺʮΧΠϯυʯΛ
    ฦ͢
    • ྫɿ Functor : (* -> *) -> *ɹʢܕؔ਺ → ܕʣ
    • Functor ͷΑ͏ͳॻ͖ํ͕Մೳ
    • ʮܕίϯετϥΫλʯΛҾ਺ʹऔΔʮܕʯΛ࡞Δ͜ͱ
    ͕Ͱ͖Δ
    ❗❗

    View Slide

  5. ߴΧΠϯυଟ૬ͷྫ
    Haskell:
    class Functor f where
    fmap :: (a -> b) -> f a -> f b
    Scala (scalaz):
    trait Functor[F[_]] extends InvariantFunctor[F] { self =>
    def map[A, B](fa: F[A])(f: A => B): F[B]
    ...
    }

    View Slide

  6. Swift 4.2 ݱࡏɺ
    ߴΧΠϯυଟ૬͸ະαϙʔτ
    ʢSwift 5 Ͱ΋αϙʔτ༧ఆ͸͓ͦΒ͘ͳ͍1ʣ
    1 WWDC 2018ͷSwiftϥϘʹͯԹ౓ײΛ֬ೝɻ·ͨɺGenerics Manifesto Ͱ΋ "Unlikely" ͷهड़ɻ

    View Slide

  7. !

    View Slide

  8. View Slide

  9. View Slide

  10. arrow-kt/arrow
    • https://github.com/arrow-kt/arrow
    • Functor, Applicative, Monad ͳͲͷ
    جຊతͳtypeclassΛαϙʔτ
    • ಺෦Ͱ KindedJ ʢJavaͰlightweight
    HKTʣΛ࢖༻
    • Annotation processing ͱ generic
    interface ͕ڧྗ (Swiftʹ͸ͳ͍)

    View Slide

  11. SwiftͰHKTΛ࣮ݱ͢Δʹ͸ʁ
    • SwiftͰHigher Kinded PolymorphismΛ࣮ݱ͢Δ - Qiita
    • Emulating HKT in Swift
    • ͲͷΞϓϩʔν΋ɺ Lightweight higher-kinded
    polymorphism ʢ࿦จʣ͕ݩʹͳ͍ͬͯΔ

    View Slide

  12. Lightweight HKT
    • ʮܕίϯετϥΫλΛɺܕύϥϝʔλʹద༻͢ΔʯͨΊͷ޻
    ෉ͱͯ͠ɺ ୅༻ͷܕʢλάʣΛ༻ҙ͢Δ
    • MyClass ͱॻ͚ͳ͍୅ΘΓʹ enum ForArray {}
    Λ༻ҙ͠ɺMyClass ͱॻ͘
    • ͨͩ͠ɺ ForArray ࣗମ͸ܕม਺Λ࣋ͨͳ͍ͨΊɺ ܕద༻Λ
    දݱ͢ΔͨΊͷܕ struct Kind Λಋೖͯ͠ɺ
    Kind 㱻 Array ૬ޓม׵Մೳʹ͢Δ

    View Slide

  13. /// `F` ʹ `A1` Λద༻ͯ͠ɺ `F` Λදݱʢ࣮ࡍͷܕ͸ `Any` Ͱফڈʣ
    public struct Kind {
    internal let _value: Any
    public init(_ value: Any) {
    self._value = value
    }
    }
    /// `Kind` 㱻 `Array` ͳͲͷ૬ޓม׵ϓϩτίϧ
    public protocol KindConvertible {
    associatedtype F
    associatedtype A1
    var kind: Kind { get }
    init(kind: Kind)
    }

    View Slide

  14. extension Array: KindConvertible {
    public typealias F = ForArray
    public typealias A1 = Element
    public var kind: Kind {
    // `Array` -> `Kind` ʹม׵
    return Kind(self as Any)
    }
    public init(kind: Kind) {
    // ܕফڈͨ͠த਎Λμ΢ϯΩϟετͯ͠औΓग़͢
    //ʢ`ForArray` ͱ 1:1ʹඥ෇͍͍ͯΔͷͰ҆શʣ
    self = kind._value as! Array
    }
    }

    View Slide

  15. Kind Λ࢖ͬͯɺ Functor Λఆٛͯ͠ΈΔɻ
    public protocol Functor {
    associatedtype F
    associatedtype A1
    // Note: `Kind` ͸ `Self` ͷ୅༻
    func fmap(_ f: @escaping (A1) -> B) -> Kind
    }
    ͜͜Ͱɺ Kind 㱻 Array ͕૬ޓม׵͢Δͷ
    ͰɺArray ͷ୅ΘΓʹ Kind Λ Functor
    ʹద߹ͯ͠ΈΔɻ

    View Slide

  16. extension Kind: Functor where F == ForArray {
    func fmap(_ f: (A1) -> B) -> Kind {
    // ͜͜Ͱ͸ `Array.map` Λͦͷ··࠶ར༻ɻ
    // ͨͩ͠ɺ`Kind.fmap`ʹมߋ͢Δʹ͸ɺ
    // `.value` Ͱ unwrap ͔ͭ
    // `.kind` (= `Kind.init()`) Ͱ re-wrap ͢Δඞཁ͋Γɻ
    return self.value.map(f).kind
    }
    }
    let result = [1, 2, 3].kind
    .fmap { "\($0)!" }.value
    result == ["1!", "2!", "3!"]

    View Slide

  17. extension Kind: Functor where F == ForArray { /* ࣮૷1 */ }
    extension Kind: Functor where F == ForOptional { /* ࣮૷2 */ }
    extension Kind: Functor where F == ForTree { /* ࣮૷3 */ }
    // ERROR: Swift Conflicting conformance of
    // 'Kind' to protocol 'Functor';
    // there cannot be more than one conformance,
    // even with different conditional bounds.
    ɹ

    ͨͩ͠ɺҟͳΔ੍໿৚݅ʹର͢Δadhocͳ࣮૷௥Ճ͸Τϥʔ
    ʹͳΔͷͰ஫ҙʢGeneric protocolͳΒղܾͯ͘͠ΕΔʣ

    View Slide

  18. /// Workaround: `ForXXX` ଆʹ `Functor` ࣮૷ΛຒΊࠐΉผͷϓϩτίϧΛ࡞Δ
    public protocol ForFunctor {
    static func fmap( // NOTE: static fmap
    _ kind: Kind,
    _ f: @escaping (A) -> B
    ) -> Kind
    }
    /// ݺͼग़͠ݩΛڞ௨Խ
    extension Kind: Functor where F: ForFunctor {
    public func fmap(_ f: @escaping (A1) -> B) -> Kind {
    return F.fmap(self, f) /* `F` ͷܕ͝ͱʹɺҟͳΔݺͼग़͠ઌ */
    }
    }
    extension ForArray: ForFunctor { /* ࣮૷1 */ }

    View Slide

  19. ྫɿϞφυ
    let arr = [1, 2, 3].kind
    .bind { [$0 * 3, $0 * 5 ].kind }.value
    arr == [3, 5, 6, 10, 9, 15]
    let list = List.cons(1, .cons(2, .cons(3, .nil))).kind
    .bind { List.cons($0 * 3, .cons($0 * 5, .nil)).kind }
    .value
    list == List.cons(3, .cons(5, .cons(6,
    .cons(10, .cons(9, .cons(15, .nil))))))
    ܕ͕ҟͳ͍ͬͯͯ΋ɺฦΓ஋͸લճͷίϯςφܕΛҡ࣋

    View Slide

  20. ྫɿࣗવม׵
    // `Array` ͔Β `List` ΁ͷࣗવม׵
    let list = [1, 2, 3].kind
    .naturalTransform {
    List($0.value).kind
    }
    .value
    list == List.cons(1, .cons(2, .cons(3, .nil)))

    View Slide

  21. HigherKindSwift
    https://github.com/inamiy/HigherKindSwift

    View Slide

  22. Future TODO (?)
    • Monad Transformer
    • Free / Cofree
    • Yoneda / Coyoneda
    • Adjunction
    • Lan / Ran (Kan Extension)
    • iOSDC 2018 CfP ʮݍ࿦ͱSwift΁ͷԠ༻ʯ

    View Slide

  23. ·ͱΊ
    • ܕίϯετϥΫλɺΧΠϯυɺߴΧΠϯυ
    • Lightweight HKT
    • Arrow (Kotlin) ྑͦ͞͏
    • Swiftʹཉ͍͠ػೳ (HKTҎલ)
    • Generic protocol (e.g. protocol Functor)
    • Parameterized extensions (e.g. where T: Optional)

    View Slide

  24. Thanks!
    Yasuhiro Inami
    @inamiy

    View Slide