Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

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. ߴΧΠϯυଟ૬ʢͷ༧උ஌ࣝʣ • ܕίϯετϥΫλ ʹ ʮܕʯΛҾ਺ʹऔΓɺʮܕʯΛฦ͢ • ྫɿ Optional<X> = 1

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

    (* -> *) -> *ɹʢܕؔ਺ → ܕʣ • Functor<Optional> ͷΑ͏ͳॻ͖ํ͕Մೳ • ʮܕίϯετϥΫλʯΛҾ਺ʹऔΔʮܕʯΛ࡞Δ͜ͱ ͕Ͱ͖Δ ❗❗
  3. ߴΧΠϯυଟ૬ͷྫ 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] ... }
  4. !

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

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

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

    ForArray {} Λ༻ҙ͠ɺMyClass<ForArray> ͱॻ͘ • ͨͩ͠ɺ ForArray ࣗମ͸ܕม਺Λ࣋ͨͳ͍ͨΊɺ ܕద༻Λ දݱ͢ΔͨΊͷܕ struct Kind<F, A> Λಋೖͯ͠ɺ Kind<ForArray, Int> 㱻 Array<Int> ૬ޓม׵Մೳʹ͢Δ
  8. /// `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>) }
  9. 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> } }
  10. 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 ʹద߹ͯ͠ΈΔɻ
  11. 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!"]
  12. 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ͳΒղܾͯ͘͠ΕΔʣ
  13. /// 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 */ }
  14. ྫɿϞφυ 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)))))) ܕ͕ҟͳ͍ͬͯͯ΋ɺฦΓ஋͸લճͷίϯςφܕΛҡ࣋
  15. ྫɿࣗવม׵ // `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)))
  16. Future TODO (?) • Monad Transformer • Free / Cofree

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

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