Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swiftで高カインド多相

 Swiftで高カインド多相

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

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

Eac0bf787b5279aca5e699ece096956e?s=128

Yasuhiro Inami

June 21, 2018
Tweet

Transcript

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

    Inami / @inamiy
  2. None
  3. ߴΧΠϯυଟ૬ʢͷ༧උ஌ࣝʣ • ܕίϯετϥΫλ ʹ ʮܕʯΛҾ਺ʹऔΓɺʮܕʯΛฦ͢ • ྫɿ Optional<X> = 1

    + X ʹ͓͚Δ "Optional" ͸ɺ ʮܕ → ܕʯʹม׵͢Δʮܕؔ਺ʯ • ΧΠϯυ ʹ ʮܕͷܕʯ • ྫɿ Optional<Int> : *ɹʢܕʣ • ྫɿ Optional : * -> *ɹʢܕ → ܕʣ
  4. ߴΧΠϯυଟ૬ • ߴΧΠϯυ ʹ ʮΧΠϯυʯΛҾ਺ʹऔΓɺʮΧΠϯυʯΛ ฦ͢ • ྫɿ Functor :

    (* -> *) -> *ɹʢܕؔ਺ → ܕʣ • Functor<Optional> ͷΑ͏ͳॻ͖ํ͕Մೳ • ʮܕίϯετϥΫλʯΛҾ਺ʹऔΔʮܕʯΛ࡞Δ͜ͱ ͕Ͱ͖Δ ❗❗
  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] ... }
  6. Swift 4.2 ݱࡏɺ ߴΧΠϯυଟ૬͸ະαϙʔτ ʢSwift 5 Ͱ΋αϙʔτ༧ఆ͸͓ͦΒ͘ͳ͍1ʣ 1 WWDC 2018ͷSwiftϥϘʹͯԹ౓ײΛ֬ೝɻ·ͨɺGenerics

    Manifesto Ͱ΋ "Unlikely" ͷهड़ɻ
  7. !

  8. None
  9. None
  10. arrow-kt/arrow • https://github.com/arrow-kt/arrow • Functor, Applicative, Monad ͳͲͷ جຊతͳtypeclassΛαϙʔτ •

    ಺෦Ͱ KindedJ ʢJavaͰlightweight HKTʣΛ࢖༻ • Annotation processing ͱ generic interface ͕ڧྗ (Swiftʹ͸ͳ͍)
  11. SwiftͰHKTΛ࣮ݱ͢Δʹ͸ʁ • SwiftͰHigher Kinded PolymorphismΛ࣮ݱ͢Δ - Qiita • Emulating HKT

    in Swift • ͲͷΞϓϩʔν΋ɺ Lightweight higher-kinded polymorphism ʢ࿦จʣ͕ݩʹͳ͍ͬͯΔ
  12. Lightweight HKT • ʮܕίϯετϥΫλΛɺܕύϥϝʔλʹద༻͢ΔʯͨΊͷ޻ ෉ͱͯ͠ɺ ୅༻ͷܕʢλάʣΛ༻ҙ͢Δ • MyClass<Array> ͱॻ͚ͳ͍୅ΘΓʹ enum

    ForArray {} Λ༻ҙ͠ɺMyClass<ForArray> ͱॻ͘ • ͨͩ͠ɺ ForArray ࣗମ͸ܕม਺Λ࣋ͨͳ͍ͨΊɺ ܕద༻Λ දݱ͢ΔͨΊͷܕ struct Kind<F, A> Λಋೖͯ͠ɺ Kind<ForArray, Int> 㱻 Array<Int> ૬ޓม׵Մೳʹ͢Δ
  13. /// `F` ʹ `A1` Λద༻ͯ͠ɺ `F<A1>` Λදݱʢ࣮ࡍͷܕ͸ `Any` Ͱফڈʣ public

    struct Kind<F, A1> { internal let _value: Any public init(_ value: Any) { self._value = value } } /// `Kind<ForArray, Int>` 㱻 `Array<Int>` ͳͲͷ૬ޓม׵ϓϩτίϧ public protocol KindConvertible { associatedtype F associatedtype A1 var kind: Kind<F, A1> { get } init(kind: Kind<F, A1>) }
  14. extension Array: KindConvertible { public typealias F = ForArray public

    typealias A1 = Element public var kind: Kind<F, A1> { // `Array<A1>` -> `Kind<ForArray, A1>` ʹม׵ return Kind(self as Any) } public init(kind: Kind<F, A1>) { // ܕফڈͨ͠த਎Λμ΢ϯΩϟετͯ͠औΓग़͢ //ʢ`ForArray` ͱ 1:1ʹඥ෇͍͍ͯΔͷͰ҆શʣ self = kind._value as! Array<A1> } }
  15. Kind<F, A> Λ࢖ͬͯɺ Functor Λఆٛͯ͠ΈΔɻ public protocol Functor { associatedtype

    F associatedtype A1 // Note: `Kind<F, B>` ͸ `Self<B>` ͷ୅༻ func fmap<B>(_ f: @escaping (A1) -> B) -> Kind<F, B> } ͜͜Ͱɺ Kind<ForArray, A1> 㱻 Array<A1> ͕૬ޓม׵͢Δͷ ͰɺArray<A1> ͷ୅ΘΓʹ Kind<ForArray, A1> Λ Functor ʹద߹ͯ͠ΈΔɻ
  16. extension Kind: Functor where F == ForArray { func fmap<B>(_

    f: (A1) -> B) -> Kind<F, B> { // ͜͜Ͱ͸ `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!"]
  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ͳΒղܾͯ͘͠ΕΔʣ
  18. /// Workaround: `ForXXX` ଆʹ `Functor` ࣮૷ΛຒΊࠐΉผͷϓϩτίϧΛ࡞Δ public protocol ForFunctor {

    static func fmap<A, B>( // NOTE: static fmap _ kind: Kind<Self, A>, _ f: @escaping (A) -> B ) -> Kind<Self, B> } /// ݺͼग़͠ݩΛڞ௨Խ extension Kind: Functor where F: ForFunctor { public func fmap<B>(_ f: @escaping (A1) -> B) -> Kind<F, B> { return F.fmap(self, f) /* `F` ͷܕ͝ͱʹɺҟͳΔݺͼग़͠ઌ */ } } extension ForArray: ForFunctor { /* ࣮૷1 */ }
  19. ྫɿϞφυ let arr = [1, 2, 3].kind .bind { [$0

    * 3, $0 * 5 ].kind }.value arr == [3, 5, 6, 10, 9, 15] let list = List<Int>.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)))))) ܕ͕ҟͳ͍ͬͯͯ΋ɺฦΓ஋͸લճͷίϯςφܕΛҡ࣋
  20. ྫɿࣗવม׵ // `Array<T>` ͔Β `List<T>` ΁ͷࣗવม׵ let list = [1,

    2, 3].kind .naturalTransform { List($0.value).kind } .value list == List.cons(1, .cons(2, .cons(3, .nil)))
  21. HigherKindSwift https://github.com/inamiy/HigherKindSwift

  22. Future TODO (?) • Monad Transformer • Free / Cofree

    • Yoneda / Coyoneda • Adjunction • Lan / Ran (Kan Extension) • iOSDC 2018 CfP ʮݍ࿦ͱSwift΁ͷԠ༻ʯ
  23. ·ͱΊ • ܕίϯετϥΫλɺΧΠϯυɺߴΧΠϯυ • Lightweight HKT • Arrow (Kotlin) ྑͦ͞͏

    • Swiftʹཉ͍͠ػೳ (HKTҎલ) • Generic protocol (e.g. protocol Functor<F>) • Parameterized extensions (e.g. where T: Optional)
  24. Thanks! Yasuhiro Inami @inamiy