Share
Embed
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
Transcript
24 slides
-
ߴΧΠϯυଟ૬ʢͷ༧උࣝʣ • ܕίϯετϥΫλ ʹ ʮܕʯΛҾʹऔΓɺʮܕʯΛฦ͢ • ྫɿ Optional<X> = 1
+ X ʹ͓͚Δ "Optional" ɺ ʮܕ → ܕʯʹม͢Δʮܕؔʯ • ΧΠϯυ ʹ ʮܕͷܕʯ • ྫɿ Optional<Int> : *ɹʢܕʣ • ྫɿ Optional : * -> *ɹʢܕ → ܕʣ -
ߴΧΠϯυଟ૬ • ߴΧΠϯυ ʹ ʮΧΠϯυʯΛҾʹऔΓɺʮΧΠϯυʯΛ ฦ͢ • ྫɿ Functor :
(* -> *) -> *ɹʢܕؔ → ܕʣ • Functor<Optional> ͷΑ͏ͳॻ͖ํ͕Մೳ • ʮܕίϯετϥΫλʯΛҾʹऔΔʮܕʯΛ࡞Δ͜ͱ ͕Ͱ͖Δ ❗❗ -
ߴΧΠϯυଟ૬ͷྫ 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] ... } -
Swift 4.2 ݱࡏɺ ߴΧΠϯυଟ૬ະαϙʔτ ʢSwift 5 Ͱαϙʔτ༧ఆ͓ͦΒ͘ͳ͍1ʣ 1 WWDC 2018ͷSwiftϥϘʹͯԹײΛ֬ೝɻ·ͨɺGenerics
Manifesto Ͱ "Unlikely" ͷهड़ɻ -
arrow-kt/arrow • https://github.com/arrow-kt/arrow • Functor, Applicative, Monad ͳͲͷ جຊతͳtypeclassΛαϙʔτ •
෦Ͱ KindedJ ʢJavaͰlightweight HKTʣΛ༻ • Annotation processing ͱ generic interface ͕ڧྗ (Swiftʹͳ͍) -
SwiftͰHKTΛ࣮ݱ͢Δʹʁ • SwiftͰHigher Kinded PolymorphismΛ࣮ݱ͢Δ - Qiita • Emulating HKT
in Swift • ͲͷΞϓϩʔνɺ Lightweight higher-kinded polymorphism ʢจʣ͕ݩʹͳ͍ͬͯΔ -
Lightweight HKT • ʮܕίϯετϥΫλΛɺܕύϥϝʔλʹద༻͢ΔʯͨΊͷ ͱͯ͠ɺ ༻ͷܕʢλάʣΛ༻ҙ͢Δ • MyClass<Array> ͱॻ͚ͳ͍ΘΓʹ enum
ForArray {} Λ༻ҙ͠ɺMyClass<ForArray> ͱॻ͘ • ͨͩ͠ɺ ForArray ࣗମܕมΛ࣋ͨͳ͍ͨΊɺ ܕద༻Λ දݱ͢ΔͨΊͷܕ struct Kind<F, A> Λಋೖͯ͠ɺ Kind<ForArray, Int> 㱻 Array<Int> ૬ޓมՄೳʹ͢Δ -
/// `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>) } -
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> } } -
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 ʹద߹ͯ͠ΈΔɻ -
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!"] -
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ͳΒղܾͯ͘͠ΕΔʣ -
/// 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 */ } -
ྫɿϞφυ 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)))))) ܕ͕ҟͳ͍ͬͯͯɺฦΓલճͷίϯςφܕΛҡ࣋ -
ྫɿࣗવม // `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))) -
Future TODO (?) • Monad Transformer • Free / Cofree
• Yoneda / Coyoneda • Adjunction • Lan / Ran (Kan Extension) • iOSDC 2018 CfP ʮݍͱSwiftͷԠ༻ʯ -
·ͱΊ • ܕίϯετϥΫλɺΧΠϯυɺߴΧΠϯυ • Lightweight HKT • Arrow (Kotlin) ྑͦ͞͏
• Swiftʹཉ͍͠ػೳ (HKTҎલ) • Generic protocol (e.g. protocol Functor<F>) • Parameterized extensions (e.g. where T: Optional)