>100 Views
October 03, 17
スライド概要
Protocol-Oriented Integers を目にして感じたことを 15 分の資料に綴ってみました。すごくざっくりとした説明で掴みきれないところもあると思うのですけど、今までとはちょっと違う視点でジェネリクスを見つめ直すきっかけになってくれたら幸いです。
※ Docswell での公開に移行する直前の Slideshare での閲覧数は 3,275 でした。
正統派趣味人プログラマー。プログラミングとは幼馴染です。
1SPUPDPM0SJFOUFE*OUFHFSTʹ͏ δΣωϦοΫϓϩάϥϛϯάͷະདྷ ۽୩༑ !FT@LVNBHBJ Զίϯ7PM%BZ5SBDL$ 4XJGUͰ1SPUPDPM0SJFOUFE*OUFHFST͕ొ͠ɺϓϩάϥϛϯάͷࡏ Γํ͕৽ہ໘Λܴ͑Α͏ͱ͍ͯ͠ΔΑ͏ʹ͢·͡ײɻಛผͩͬͨδΣω ϦοΫͷੈք͕ৗతʹͳΔ͔͠Εͳ͍ɻৼΓฦΕ$PMMFDUJPOͱ ͔'MPBUJOH1PJOUͱ͔ɺͦΕΛ͡ײΔ໘ͬͯલ͔ΒࡏͬͨΜͰ͢ΑͶɻ ͦΜͳ͜ͱʹ͍Λͤͳ͕Βɺ؆୯ʹͰ͋Γ·͚͢ΕͲ1SPUPDPM 0SJFOUFE*OUFHFST͕ඳ͘ੈքΛΈΜͳͱோΊΒΕͨΒ͢Ͱ͍͠خɻ
1SPUPDPM0SJFOUFE *OUFHFSTʹ͏δΣωϦοΫϓϩάϥϛϯάͷະདྷ
۽୩༑ 5PNPIJSP,VNBHBJ ⾣ 4XJGU͕ޠݴେ͖Ͱ͢ʂ ⾣ ΈΜͳͰָ͠Ήษڧձ͕େ͖Ͱ͢ʂ ⾣ ϓϩάϥϛϯάͷָ͠͞Λ͍͖͍͑ͯͨɻ w ωοτϥδΦ w ษڧձͷํ։࠵ w ಉਓࢽଈചձ
4XJGU 1SPUPDPM0SJFOUFE*OUFHFSTొ
1SPUPDPM0SJFOUFE*OUFHFSTొ ܕΛϓϩτίϧͰදݱʢϓϩτίϧࢦʣ ʹܕറΒΕͳ͍ૢ࡞͕Մೳʹͳͬͨ
1SPUPDPM0SJFOUFE*OUFHFSTొ ܕΛϓϩτίϧͰදݱ 4JHOFE*OUFHFS 6OTJHOFE*OUFHFS ූ߸͖ ූ߸ͳ͠ 4JHOFE/VNFSJD #JOBSZ*OUFHFS 'JYFE8JEUI*OUFHFS ݻఆ෯ Ϗοτද͞ݱΕͨ ූ߸͖ $VTUPN4USJOH$POWFSUJCMF ΛςΩετදݱՄೳ /VNFSJD )BTIBCMF &RVBUBCMF ϋογϡΛऔಘՄೳ Ձൺֱ͕Մೳ &YQSFTTJCMF#Z*OUFHFS-JUFSBM 4USJEFBCMF େখൺֱ͕Մೳ $PNQBSBCMF େখൺֱ͕Մೳ ϦςϥϧͰදݱՄೳ
1SPUPDPM0SJFOUFE*OUFHFSTొ
ʹܕറΒΕͳ͍ૢ࡞͕Մೳʹ
⾣
ͨͱ͑lܕͳΜͰ͍͍͚ΕͲɺzͱ͍͏දݱ
⾣
ͱ͍͏֓೦ͰίʔυΛΈཱͯΔ
func sum<T : Numeric>(of values: Array<T>) -> T {
return values.reduce(0) { $0 + $1 }
}
// Int の配列でも、Float の配列でも、使える
let integers = [5, 5, 5, 5]
let floats = [2.5, 2.5, 2.5, 2.5] as [Float]
sum(of: integers)
sum(of: floats)
// 20
// 10
(FOFSJDT
δΣωϦοΫϓϩάϥϛϯά ʹܕറΒΕͳ͍ϓϩάϥϛϯά ܕΛ͑ͨίʔυͷ൚༻Խ͕ՄೳʹͳΔʁ δΣωϦοΫ্͚ऀڃͷߴٕ๏ʁ
δΣωϦοΫϓϩάϥϛϯά
ʹܕറΒΕͳ͍ϓϩάϥϛϯά
⾣
ܕͳΜͰ͍͍ͱ͍͏ߟ͑ํ
⾣
ͱ͍͏֓೦ͰίʔυΛΈཱͯΔ
ܕͳΜͰ͍͍͚ΕͲ
$PMMFDUJPOʹ૬͢ΔͷͶ
ͦΜͳ$PMMFDUJPOΛ
ड͚औͬͯʜ
$PMMFDUJPO͕ѻ͏
ཁૉΛฦ͠·͔͢ΒͶ
func average <C: Collection> (of values: C ) -> C.Element
where C.Element : BinaryInteger {
ͨͩ͠ɺ͜Ε$PMMFDUJPO͕ѻ͏ཁૉ͕
#JOBSZ*OUFHFSʹͯͬݶΓཱͭίʔυͰ͢
͋ͱɺ֓೦ͷൣᙝͰ
ίʔυΛΈཱͯͯߦ͘ʜ
return values.reduce(into: 0, +=) / C.Element(values.count)
}
δΣωϦοΫϓϩάϥϛϯά ܕΛ͑ͨίʔυͷ൚༻Խ͕ՄೳʹͳΔʁ ⾣ ࠓ·ͰΦʔόʔϩʔυͰද͍ͨͯ͠ݱίʔυ͕൚༻తʹॻ͚Δ ⾣ ଘࡏҙٛlίʔυͷ൚༻ԽzͳͷͩΖ͏͔ʁ GVODTVN PGWBMVFT"SSBZ*OU *OU GVODTVN PGWBMVFT"SSBZ*OU *OU GVODTVN PGWBMVFT"SSBZ*OU *OU GVODTVN PGWBMVFT"SSBZ*OU *OU GVODTVN PGWBMVFT"SSBZ*OU *OU GVODTVN PGWBMVFT"SSBZ6*OU 6*OU GVODTVN PGWBMVFT"SSBZ6*OU 6*OU GVODTVN PGWBMVFT"SSBZ6*OU 6*OU GVODTVN PGWBMVFT"SSBZ6*OU 6*OU GVODTVN PGWBMVFT"SSBZ6*OU 6*OU GVODTVN PGWBMVFT"SSBZ%PVCMF %PVCMF GVODTVN PGWBMVFT"SSBZ'MPBU 'MPBU GVODTVN5/VNFSJD PGWBMVFT"SSBZ5 5 ଘࡏҙٛʹlίʔυͷ൚༻Խz͕͋Δͷ ฆΕͳ͘ɺਖ਼͍͜͠ͱͳͷ͚ͩΕͲʜ
δΣωϦοΫϓϩάϥϛϯά
ۙʹࡏΔδΣωϦοΫ
⾣
ඪ४ϥΠϒϥϦʔͰδΣωϦοΫΘΕ͍ͯΔ
⾣
ྻͷมΠχγϟϥΠβʔۙͳଘࡏ
extension Array {
// 変換元は、要素の型が同じならどんな Sequence でも良い
init<S:Sequence>(_ s: S) where Element == S.Element
}
// どんな Sequence も配列型に変換できる
Array ( [1, 5, 8, 3, 7, 3] )
Array ( [1, 5, 8, 3, 7, 3][2 ..< 5] )
Array ( 1 ..< 20)
Array ( zip([1, 3, 5], [2, 4, 6]))
// Array
// ArraySlice
// CountableRange
// Zip2Sequence<Array, Array>
δΣωϦοΫϓϩάϥϛϯά
͜ΕͩͬͯδΣωϦοΫදݱͷͻͱͭ
// この書き方はパッと思いつかなくても、
func sum<T : Numeric>(of values: Array<T>) -> T {
return values.reduce(into: 0, +=)
}
දݱͷຊ࣭
ͲͪΒಉ͡
// こちらなら自然と書ける人も多いはず(上記より Swift らしいと思う)
extension Array where Element : Numeric {
func sum() -> Element {
return reduce(into: 0, +=)
}
}
δΣωϦοΫϓϩάϥϛϯά δΣωϦοΫ্͚ऀڃͷߴٕ๏ʁ ⾣ ֓೦Ͱ֓೦ΛίʔσΟϯά͢Δख๏ w ରΛlΓΜ͝zͰͳ͘l͑ΒΕΔͷ̍ͭzͱଊ͑ͨΑ͏ͳͷ w ͨͱ͑lΓΜ͕̎ͭ͝zͰͳ͘l zͱ͍͏දํݱ๏ ⾣ ͻͱͭͷύϥμΠϜͱଊ͑ͯͲ͏ͩΖ͏ w ΦϒδΣΫτࢦͰlΫϥε͍͔͠Βzͱආ͚Δ͜ͱ͠ͳ͍ w ͘͠ࢥ͑Δͷɺड͚ೖΕΔͱͦͷจԽͰݍҊ֎ී௨ͩͬͨΓ͢Δ ⾣ ͔ͯ͠͠ɺ͜Ε͕lϓϩτίϧࢦzͱ͍͏ύϥμΠϜʁ w Ԡ༻ٕज़ͱͯ͠ొͨ͠ͷؒҧ͍ͳ͍ͱࢥ͏ w ͨͩ͠ࠓɺͦͷৗࣝΛ͑ͨੈքΛඳ͜͏ͱ͍ͯ͠ΔΑ͏ʹࢥ͑Δ w ߴٕ๏Ͱͳ͘ͱૅجଊ͑Δͱ৽͍͠ະདྷ͕͚ͦ͏ͳ༧͕͢ײΔ
ϓϩτίϧࢦͷະདྷ ண࣮ʹาΈΛਐΊΔ4XJGU
ϓϩτίϧࢦϓϩάϥϛϯάͷະདྷ 4XJGU ⾣ ϓϩτίϧͰܕΛઆ໌͢Δͱ͍͏ੈք؍ ⾣ ੑ࣭ΛϓϩτίϧͰنఆ͠ɺͦΕͰܕΛઆ໌͢Δ struct Array : MutableCollectionType, Sliceable, "SSBZܕɺ ArrayLiteralConvertible { ͭ·Γྻʜ ༰ΛมߋՄೳͳ ཁૉͷू߹Ͱ͋Γɺ ෦ཁૉͰ Γग़͠ՄೳͳͷͰɺ ྻϦςϥϧ͔Β มՄೳͳͷɻ ۩ମతʹ࣮Λͯ͘ͳݟ Կ͕Ͱ͖Δ͔૾Ͱ͖Δ }
ϓϩτίϧࢦϓϩάϥϛϯάͷະདྷ
4XJGU
⾣
ϓϩτίϧ֦ுͱ͍͏ੈք؍
⾣
ओମΛ۩ੈք͔ΒநੈքͱҠߦʢύϥμΠϜγϑτͷݪىʁʣ
// Swift 1 は“写像(map)”が主体
func map<C:CollectionType, T>(source: C,
transform: (C.Generator.Element) -> T) -> [T]
lࣸ૾͕ίϨΫγϣϯΛड͚औΔz
ͱ͍͏Ձ؍
// Swift 2 は“コレクション”が主体
extension CollectionType {
lίϨΫγϣϯ͕ࣸ૾ͱ͍͏֓೦Λ࣋ͭz
ͱ͍͏Ձ؍
func map<T>(transform: (Generator.Element) -> T) -> [T]
}
ϓϩτίϧࢦϓϩάϥϛϯάͷະདྷ 4XJGU ුಈখΛ֓೦Ͱදݱ w 'MPBUJOH1PJOUϓϩτίϧ Ͱܕͳ͘ϓϩτίϧ͚ͩͰ ුಈখΛૢΕΔΑ͏ʹͳͬͨ
ϓϩτίϧࢦϓϩάϥϛϯά ුಈখΛ֓೦Ͱදݱ #JOBSZ'MPBUJOH1PJOU &YQSFTTJCMF#Z'MPBU-JUFSBM *&&&ͷ'MPBUJOH1PJOU #JOBSZ5ZQFʹݻ༗ͷఆٛ ුಈখϦςϥϧͰ දݱՄೳ 'MPBUJOH1PJOU 4JHOFE/VNFSJD *&&&ͷ࠷جຊ෦ DMBVTF Λఏ͢ڙΔ ූ߸͖ &YQSFTTJCMF#Z*OUFHFS-JUFSBM ϦςϥϧͰදݱՄೳ )BTIBCMF /VNFSJD ϋογϡΛऔಘՄೳ 4USJEFBCMF େখൺֱ͕Մೳ $PNQBSBCMF &RVBUBCMF େখൺֱ͕Մೳ Ձൺֱ͕Մೳ
ුಈখΛ֓೦Ͱදݱ
ුಈখͱ͍͏֓೦ͰίʔυΛඳ͚Δ
⾣
%PVCMF'MPBUlුಈখzͱׅͯͬѻ͑Δ
⾣
ͨͩ͠ීஈɺුಈখͷܕΛҙࣝ͢Δ໘ۃΊͯك
func areaOfCircle<T:FloatingPoint>(withRadius radius: T) -> T {
return radius * radius * T.pi
}
areaOfCircle(withRadius: 2 as Double)
areaOfCircle(withRadius: 2 as Float)
areaOfCircle(withRadius: 2 as Float80)
// 12.566370614359172
// 12.56637
// 12.566370614359172464
ϓϩτίϧࢦϓϩάϥϛϯά 4XJGU Λ֓೦Ͱදݱ w #JOBSZ*OUFHFSϓϩτίϧ w /VNFSJDϓϩτίϧ ʢ͓ͦΒ͘ະʣ ͱ͍͏ɺ ݱϓϩάϥϛϯάͷ͕֓װج೦Ͱද͞ݱΕͨ
4XJGU
͕֓೦Ͱද͞ݱΕͨ
⾣
ͲͪΒ͕దͳද͑ݴͱݱΔͩΖ͏ɻ
⾣
ΈΜͳͷݟղ͕Ұக͢Δͷ4XJGU͘Β͍ʁʢ૾ʣ
extension String {
// 現在主流の API දݱ
func repeated(_ count: Int) -> String
// Protocol-Oriented Integers を用いた API දݱ
func repeated<T:BinaryInteger>(_ count: T) -> String
}
"*".repeated(5)
// "*****"
4XJGU
ͦΕͰූ߸ͱ͍͏֓೦ͷ֞ࠜେ͖͍
⾣
܁Γฦ͢Ҏ্͕ී௨
⾣
͔ͩΒͱ6OTJHOFE*OUFHFSʹറΔͱܕม͕ඞཁʹͳΔ
extension String {
func repeated<T:UnsignedInteger>(_ count: T) -> String
}
FSSPSBSHVNFOUUZQF*OUEPFTOPUDPOGPSNUPFYQFDUFEUZQF6OTJHOFE*OUFHFS
"*".repeated(5)
4XJGU δΣωϦοΫΛجຊͱ͡ײΔͱࢹ͕มΘΔ ϓϩτίϧࢦͷຊ֨తͳນ։͚ͳͷ͔͠Εͳ͍
2"
NPPLNPPLSBEJP NPPL ۽୩ͱ៸໘͕ϓϩάϥϛϯάίʔυͷ͔Β ௌ͑ͯ͘͜ΔʹࣖΛָ͚ͯ͠ΉϥδΦ ͖Ε͍ͳϓϩάϥϜίʔυʹɺॻ͍ͨਓͷ͍͕ͨ͘͞ΜࠐΊΒΕ͍ͯ·͢ɻͦΜͳίʔυ ʹ·͙ͬ͢ҙࣝΛ͚ͨͱ͖ɺͦͷ͍ͷ͕ௌ͖͑ͯ͜·͢ɻͦΕͱͯඒͯ͘͠ɺௌ͘ ΄ͲʹࠍΕࠍΕͱͯ͠͠·͏΄ͲɻϓϩάϥϜ͕ͰΔૉఢͳΛɺҰॹʹָ͠Έ·͠ΐ͏ɻ ຖ݄ୈ̎ɾୈ̐ ݄༵ ʹ৴ IUUQLFQDNPPLNPPLSBEJPDPN ⾣ ୈ 1SPQFSUZͷੈք؍Λ௫ΜͰΈͨͯ͘ ⾣ ୈ ޠݴͷັྗΛޠΒ͏ձ ⾣ ୈ JOUFSGBDFͱQSPUPDPM ⾣ ୈ ͋ͷΈͨ"OZͱ!PCKDΛɺ͏͍ͪͲɻ ⾣ ୈ !PCKD ⾣ ୈ "OZ ⾣ ୈ δΣωϦοΫϓϩάϥϛϯά
&OKPZ4XJGU 5IBOLZPV ۽୩༑ !FT@LVNBHBJ