Slide 1

Slide 1 text

,PUMJO'FTU:VUB5BLBOBTIJ ωετͨ͠EBUBDMBTTͷ໘౗ͳߋ৽ʹ͞Α͏ͳΒʂ -FOTΛ࡞ͬͯཧղ͢Δ"SSPXͷ0QUJDTͷੈք

Slide 2

Slide 2 text

ࣗݾ঺հ w:VUB5BLBOBTIJ w 9!TIJJUB@ w-*/&Ϡϑʔגࣜձࣾ-*/&ͷ"OESPJEΞϓϦ։ൃ w޷͖ͳ,PUMJOͷݴޠػೳ͸εϚʔτΩϟετͱ$POUSBDU

Slide 3

Slide 3 text

ൃද಺༰ wෳࡶͳEBUBDMBTTมߋͷਏ͞ͱ-FOTʹΑΔղܾ w-FOTΛࣗ࡞ͯ͠࢓૊ΈΛཧղ w-FOTΛศརʹѻ͏ϥΠϒϥϦ w-FOTͷݶքͱ0QUJDT

Slide 4

Slide 4 text

ෳࡶͳEBUBDMBTTมߋͷਏ͞ data class User(val id: Int, val profile: Profile) data class Profile(val name: String, val statusMessage: StatusMessage) data class StatusMessage(val text: String, val updatedTime: Long) fun capitalizeStatusMessage(user: User): User = user.copy( profile = user.profile.copy( statusMessage = user.profile.statusMessage.copy( text = user.profile.statusMessage.text.uppercase() ) ) )

Slide 5

Slide 5 text

-FOTʹΑΔਏ͞ͷܰݮ fun capitalizeStatusMessage(user: User): User = user.copy( profile = user.profile.copy( statusMessage = user.profile.statusMessage.copy( text = user.profile.statusMessage.text.uppercase() ) ) ) fun capitalizeStatusMessageWithLens(user: User): User = User.profile.statusMessage.text.modify(user) { it.uppercase() }

Slide 6

Slide 6 text

-FOTͱ͸ʁ wؔ਺ܕϓϩάϥϛϯάͰɺෆมσʔλͷૢ࡞ʹ༻͍ΒΕΔ w,PUMJOͰ͸"SSPXLUϥΠϒϥϦͰར༻Մೳ w(FUUFSͱ4FUUFSͷϖΞͰߏ੒͞Ε͍ͯΔ

Slide 7

Slide 7 text

-FOTΛ࢖͏ // Get fun getStatusMessage(user: User): String = User.profile.statusMessage.text.get(user) // Set fun updateStatusMessage(user: User, newMessage: String): User = User.profile.statusMessage.text.set(user, newMessage) // Modify(Getter + Setter) fun capitalizeStatusMessage(user: User): User = User.profile.statusMessage.text.modify(user) { it.uppercase() }

Slide 8

Slide 8 text

-FOTͷ࢓૊ΈΛཧղ͢Δ

Slide 9

Slide 9 text

-FOTͷ࢓૊ΈΛཧղ͢Δ interface PLens : POptional { fun get(source: S): A override fun set(source: S, focus: B): T . . . } w"SSPXLUͰͷ-FOTͷ࣮૷

Slide 10

Slide 10 text

-FOTͷ࢓૊ΈΛ࡞ͬͯཧղ͢Δ  (FUUFSͷ࡞੒  4FUUFSͷ࡞੒  (FUUFSͱ4FUUFSΛ૊Έ߹Θͤͯ-FOTΛ࡞Δ

Slide 11

Slide 11 text

(FUUFSͷ࣮૷ํ਑ wHFU ؔ਺Λ༻ҙ w൚༻తʹ࢖͑Δ༷ʹδΣωϦΫεΛར༻ wEBUBDMBTTਂ͍৔ॴʹର͢ΔHFUUFS΋؆୯ʹऔಘՄೳʹ͢Δ

Slide 12

Slide 12 text

(FUUFSͷ࡞੒ fun interface Getter { fun get(source: S): A } data class User(val id: Int, val profile: Profile) fun getProfile(user: User): Profile { val profileGetter = Getter { source -> source.profile } return profileGetter.get(user) } w4(FUUFSͷιʔεͷܕ 6TFS  w"(FUUFSͷϑΥʔΧεͷܕ 1SP fi MF

Slide 13

Slide 13 text

(FUUFSͷ߹੒ fun interface Getter { fun get(source: S): A operator fun plus(other: Getter): Getter = TODO() } data class User(val id: Int, val profile: Profile) data class Profile(val name: String, val statusMessage: StatusMessage) fun getStatusMessage(user: User): StatusMessage { val profileGetter = Getter { source -> source.profile } val statusMessageGetter = Getter { source - > source.statusMessage } val composedGetter: Getter = profileGetter + statusMessageGetter return composedGetter.get(user) }

Slide 14

Slide 14 text

(FUUFSͷ߹੒ fun interface Getter { fun get(source: S): A operator fun plus(other: Getter): Getter = Getter { source: S -> val a: A = get(source) other.get(a) } }

Slide 15

Slide 15 text

4FUUFSͷ࡞੒ fun interface Setter { fun modify(source: S, map: (A) -> A): S fun set(source: S, focus: A): S = modify(source) { _: A -> focus } } data class User(val id: Int, val profile: Profile) fun setProfile(user: User, newProfile: Profile): User { val profileSetter = Setter { source, map -> val modifiedProfile = map(source.profile) source.copy(profile = modifiedProfile) } return profileSetter.set(user, newProfile) }

Slide 16

Slide 16 text

4FUUFSͷ߹੒ fun interface Setter { fun modify(source: S, map: (A) -> A): S fun set(source: S, focus: A): S = modify(source) { _: A -> focus } operator fun plus(other: Setter): Setter = Setter { source: S, map: (B) -> B -> modify(source) { focus: A - > other.modify(focus, map) } } }

Slide 17

Slide 17 text

4FUUFSͷ߹੒ data class User(val id: Int, val profile: Profile) data class Profile(val name: String, val statusMessage: StatusMessage) fun setStatusMessage(user: User, newStatusMessage: StatusMessage): User { val profileSetter = Setter { source, map -> val modifiedProfile = map(source.profile) source.copy(profile = modifiedProfile) } val statusMessageSetter = Setter { source, map -> val modifiedStatusMessage = map(source.statusMessage) source.copy(statusMessage = modifiedStatusMessage) } val composedSetter: Setter = profileSetter + statusMessageSetter return composedSetter.set(user, newStatusMessage) }

Slide 18

Slide 18 text

-FOTͷ࡞੒ class Lens( private val getter: Getter, private val setter: Setter ) : Getter by getter, Setter by setter { operator fun plus(other: Lens): Lens = Lens( getter = this.getter + other.getter, setter = this.setter + other.setter ) }

Slide 19

Slide 19 text

࡞੒ͨ͠-FOTͷར༻ data class User(val id: Int, val profile: Profile) data class Profile(val name: String, val statusMessage: StatusMessage) data class StatusMessage(val text: String, val updatedTime: Long) fun createStatusMessageTextLens(): Lens { val profileLens = Lens( getter = { source -> source.profile }, setter = { source, map -> source.copy(profile = map(source.profile)) } ) val statusMessageLens = Lens( getter = { source -> source.statusMessage }, setter = { source, map -> source.copy(statusMessage = map(source.statusMessage)) } ) val textLens = Lens( getter = { source -> source.text }, setter = { source, map -> source.copy(text = map(source.text)) } ) return profileLens + statusMessageLens + textLens }

Slide 20

Slide 20 text

࡞੒ͨ͠-FOTͷར༻ data class User(val id: Int, val profile: Profile) data class Profile(val name: String, val statusMessage: StatusMessage) data class StatusMessage(val text: String, val updatedTime: Long) fun createStatusMessageTextLens(): Lens { … } fun myLens(user: User, newMessage: String) { val lens = createStatusMessageTextLens() val text: String = lens.get(user) val newUser1: User = lens.set(user, newMessage) val newUser2: User = lens.modify(user) { it.uppercase() } }

Slide 21

Slide 21 text

࡞੒ͨ͠-FOTͷܽ఺ fun createStatusMessageTextLens(): Lens { val profileLens = Lens( getter = { source -> source.profile }, setter = { source, map -> source.copy(profile = map(source.profile)) } ) val statusMessageLens = Lens( getter = { source -> source.statusMessage }, setter = { source, map -> source.copy(statusMessage = map(source.statusMessage)) } ) val textLens = Lens( getter = { source -> source.text }, setter = { source, map -> source.copy(text = map(source.text)) } ) return profileLens + statusMessageLens + textLens }

Slide 22

Slide 22 text

࡞੒ͨ͠-FOTͷܽ఺ fun createStatusMessageTextLens(): Lens { val profileLens = Lens( getter = { source -> source.profile }, setter = { source, map -> source.copy(profile = map(source.profile)) } ) val statusMessageLens = Lens( getter = { source -> source.statusMessage }, setter = { source, map -> source.copy(statusMessage = map(source.statusMessage)) } ) val textLens = Lens( getter = { source -> source.text }, setter = { source, map -> source.copy(text = map(source.text)) } ) return profileLens + statusMessageLens + textLens } fun createStatusMessageTextLensByArrow(): Lens = User.profile.statusMessage.text

Slide 23

Slide 23 text

"SSPXLUͷ-FOTͷར༻ํ๏

Slide 24

Slide 24 text

"SSPXLUͷ-FOTͷར༻ํ๏ w-FOTͷͨΊͷίʔυੜ੒ํ๏ w-FOTΛΑΓศརʹ׆༻ w ϢʔςΟϦςΟؔ਺ w ଞϥΠϒϥϦͱͷ࿈ܞ

Slide 25

Slide 25 text

-FOTͷͨΊͷίʔυੜ੒ @optics data class Profile(val name: String, val statusMessage: StatusMessage) { companion object } w!PQUJDTΛEBUBDMBTTʹ͚ͭΔ wۭͷDPNQBOJPOPCKFDUΛఆٛ͢Δ

Slide 26

Slide 26 text

-FOTͷͨΊͷίʔυੜ੒ @optics data class Profile(val name: String, val statusMessage: StatusMessage) { companion object } / / Generated code val Profile.Companion.name: Lens get() = Lens( get = { profile: Profile -> profile.name }, set = { profile: Profile, value: String -> profile.copy(name = value) } ) val Profile.Companion.statusMessage: Lens get() = Lens( get = { profile: Profile -> profile.statusMessage }, set = { profile: Profile, value: StatusMessage - > profile.copy(statusMessage = value) } ) wDPNQBOJPOPCKFDUͷ֦ுϓϩύςΟܦ༝Ͱɺੜ੒͞Εͨ -FOT͕ར༻Մೳ

Slide 27

Slide 27 text

-FOTͷͨΊͷίʔυੜ੒ val composedLens: Lens = User.profile.statusMessage // Generated code val Lens.statusMessage: Lens inline get() = this + Profile.statusMessage val User.Companion.profile: Lens inline get() = Lens( get = { user: User -> user.profile }, set = { user: User, value: Profile -> user.copy(profile = value) } ) val Profile.Companion.statusMessage: Lens inline get() = Lens( get = { profile: Profile -> profile.statusMessage }, set = { profile: Profile, value: StatusMessage - > profile.copy(statusMessage = value) } )

Slide 28

Slide 28 text

-FOTͷͨΊͷϢʔςΟϦςΟؔ਺ val modifiedUser1 = User.profile.name.modify(user) { it.uppercase() } val modifiedUser2 = User.profile.statusMessage.text .modify(modifiedUser1) { it.uppercase() } val result = User.profile.statusMessage.updatedTime .modify(modifiedUser2) { System.currentTimeMillis() } wෳ਺ͷϓϩύςΟͷҰׅมߋ͸ۤख

Slide 29

Slide 29 text

-FOTͷͨΊͷϢʔςΟϦςΟؔ਺ val result = user.copy { User.profile.name transform { it.uppercase() } inside(User.profile.statusMessage) { StatusMessage.text transform { it.uppercase() } StatusMessage.updatedTime set System.currentTimeMillis() } } wDPQZ Ͱ-FOTΛΑΓศརʹ࢖͑Δ wJOTJEF ͸ಛఆͷϑΥʔΧε΁ͷγϣʔτΧοτ

Slide 30

Slide 30 text

-FOTͷͨΊͷϢʔςΟϦςΟؔ਺ val modifiedUser1 = User.profile.name.modify(user) { it.uppercase() } val modifiedUser2 = User.profile.statusMessage.text .modify(modifiedUser1) { it.uppercase() } val result = User.profile.statusMessage.updatedTime .modify(modifiedUser2) { System.currentTimeMillis() } val result = user.copy { User.profile.name transform { it.uppercase() } inside(User.profile.statusMessage) { StatusMessage.text transform { it.uppercase() } StatusMessage.updatedTime set System.currentTimeMillis() } }

Slide 31

Slide 31 text

ଞϥΠϒϥϦͱͷ࿈ܞ val messageState = remember { mutableStateOf(message) } val messageStateFlow = MutableStateFlow(message) messageState.updateCopy { StatusMessage.text transform { it.uppercase() } } messageStateFlow.updateCopy { StatusMessage.text set "newText" } wDPQZ ͸.VUBCMF4UBUF΍.VTUBCMF4UBUF'MPXͰ΋ར༻Մೳ

Slide 32

Slide 32 text

ଞϥΠϒϥϦͱͷ࿈ܞ val messageState = remember { mutableStateOf(message) } val messageStateFlow = MutableStateFlow(message) val messageSharedFlow = MutableSharedFlow() val textState: State = messageState.optic(StatusMessage.text) val textStateFlow: StateFlow = messageStateFlow.optic(StatusMessage.text) val textSharedFlow: SharedFlow = messageSharedFlow.optic(StatusMessage.text) wPQUJD ͸-FOTΛ࢖ͬͯ৽͍͠4UBUF΍'MPXΛੜ੒

Slide 33

Slide 33 text

-FOTͷݶք

Slide 34

Slide 34 text

-FOTͷݶք data class User( val id: Int, val profile: Profile, val friends: Map ) fun getUserFriendProfile(user: User, friendUserId: Int): Profile? = User.friends. ??? .get(user) w-FOT͸EBUBDMBTTΛѻ͏ۜͷ஄ؙͰ͸ͳ͍

Slide 35

Slide 35 text

-FOTͷݶք data class User(val id: Int, val profile: Profile) sealed class Profile { abstract val name: String abstract val statusMessage: StatusMessage data class BasicProfile( override val name: String, override val statusMessage: StatusMessage) : Profile() data class PremiumProfile( override val name: String, override val statusMessage: StatusMessage, val nameDecorationMetadata: String) : Profile() } fun maybeSetNameDecorationMetadata(user: User, newMetadata: String): User = User.profile. ??? .set(user, newMetadata) w-FOT͸EBUBDMBTTΛѻ͏ۜͷ஄ؙͰ͸ͳ͍

Slide 36

Slide 36 text

0QUJDT w"SSPXLUͷ0QUJDT͸ҎԼͷͭͰߏ੒͞Ε͍ͯΔ w 5SBWFSTBM w 0QUJPOBM w -FOT w 1SJTN w *TP wԼʹߦ͘΄Ͳೳྗ͕૿͑Δ͕ ద༻Մೳൣғ͸ڱ·Δ IUUQTBSSPXLUJPMFBSOJNNVUBCMFEBUBJOUSPNBOZPQUJDTUPSVMFUIFNBMM

Slide 37

Slide 37 text

5SBWFSTBM interface Traversal { fun modify(source: S, map: (focus: A) -> A): S } w-JTUͳͲɺෳ਺ݸͷ஋ͷߋ৽͕Ͱ͖Δ wLPUMJODPMMFDUJPOTNBQΛҰൠԽͨ͠ɺNPEJGZ ͕ར༻Մೳ

Slide 38

Slide 38 text

5SBWFSTBM data class UserGroup(val name: String, val users: List) data class Profile(val name: String, val statusMessage: StatusMessage) data class StatusMessage(val text: String, val updatedTime: Long) fun updateAllUpdatedTime(group: UserGroup): UserGroup = UserGroup.users.modify(group) { user - > user.map { User.profile.statusMessage.updatedTime.set(it, System.currentTimeMillis()) } } fun updateAllUpdatedTimeWithTraversal(group: UserGroup): UserGroup = UserGroup.users.every.profile.statusMessage.updatedTime .set(group, System.currentTimeMillis()) wNBQ Λ5SBWFSTBMͰஔ͖׵͑Δ

Slide 39

Slide 39 text

0QUJPOBM interface Optional : Traversal { override fun modify(source: S, map: (focus: A) -> A): S fun getOrNull(source: S): A? } w-JTU΍.BQͳͲͷίϨΫγϣϯ͔ΒҰͭͷ஋ΛऔΓग़ͤΔ wHFU0S/VMM Ͱࣦഊ͢ΔՄೳੑͷ͋ΔॲཧΛදݱՄೳ

Slide 40

Slide 40 text

0QUJPOBM data class User( val id: Int, val profile: Profile, val friends: Map ) fun getUserFriendProfile(user: User, friendUserId: Int): Profile? { val friendOptional: Optional = User.friends.index(friendUserId) return friendOptional.profile.getOrNull(user) } w.BQ, 7Λ0QUJPOBMͰѻ͏

Slide 41

Slide 41 text

1SJTN interface Prism : Optional { override fun modify(source: S, map: (focus: A) -> A): S override fun getOrNull(source: S): A? fun reverseGet(focus: A): S } wTFBMFEDMBTTͷΫϥε֊૚ͷදݱʹ࢖ΘΕΔ wSFWFSTF(FU ͰϑΥʔΧε͔Βιʔε͕ߏஙՄೳ

Slide 42

Slide 42 text

1SJTN sealed class Profile { data class BasicProfile() : Profile() data class PremiumProfile() : Profile() } val basicProfilePrism: Prism = Profile.basicProfile val premiumProfilePrism: Prism = Profile.premiumProfile wαϒΫϥεͷΫϥε໊ͷ1SJTN͕ੜ੒͞ΕΔ

Slide 43

Slide 43 text

1SJTN data class User(val id: Int, val profile: Profile) sealed class Profile { abstract val name: String abstract val statusMessage: StatusMessage data class BasicProfile( override val name: String, override val statusMessage: StatusMessage) : Profile() data class PremiumProfile( override val name: String, override val statusMessage: StatusMessage, val nameDecorationMetadata: String) : Profile() } fun maybeSetNameDecorationMetadata(user: User, newMetadata: String): User = User.profile.premiumProfile.nameDecorationMetadata.set(user, newMetadata) wTFBMFEDMBTTΛ1SJTNͰѻ͏

Slide 44

Slide 44 text

-FOT interface Lens : Optional { override fun modify(source: S, map: (focus: A) -> A): S fun get(source: S): A } w(FUUFSͱ4FUUFS͕ར༻Ͱ͖Δ wHFU ͰϑΥʔΧεΛ࣮֬ʹऔಘՄೳ

Slide 45

Slide 45 text

*TP interface Iso : Prism, Lens { override fun modify(source: S, map: (focus: A) -> A): S override fun reverseGet(focus: A): S override fun get(source: S): A } wͭͷܕͷؒͰɺ৘ใͷଛࣦແ͠ͷ૬ޓม׵͕Մೳ w-FOTͱ1SJTNͷ྆ํͷೳྗΛ࣋ͭ

Slide 46

Slide 46 text

*TP data class StatusMessage(val text: String, val updatedTime: Long) val statusMessageToPairIso: Iso> = Iso( get = { it.text to it.updatedTime }, reverseGet = { StatusMessage(it.first, it.second) } ) @JvmInline value class UserId(val id: Int) fun UserId.getValue(): Int = UserId.id.get(this) fun Int.toUserId(): UserId = UserId.id.reverseGet(this) w*TPʹΑΔܕม׵

Slide 47

Slide 47 text

0QUJDT·ͱΊ 0QUJDTaؔ਺ NPEJGZ HFU0S/VMM SFWFSTF(FU HFU 5SBWFSTBM ̋ ✕ ✕ ✕ 0QUJPOBM ̋ ̋ ✕ ✕ 1SJTN ̋ ̋ ̋ ✕ -FOT ̋ ̋ ✕ ̋ *TP ̋ ̋ ̋ ̋

Slide 48

Slide 48 text

0QUJDT·ͱΊ w5SBWFSTBMෳ਺ݸͷ஋શͯͷߋ৽ w0QUJPOBMίϨΫγϣϯͷҰ෦ͷऔಘ w1SJTNTFBMFEDMBTTͷΫϥε֊૚ͷදݱ w-FOT(FUUFS 4FUUFS w*TPͭͷܕؒͷ૬ޓม׵

Slide 49

Slide 49 text

·ͱΊ w-FOTΛ࢖ͬͯEBUBDMBTTͷૢ࡞Λ؆୯ʹهड़Մೳ w-FOT͸(FUUFSͱ4FUUFSͷ૊ɻࣗ࡞ͯ͠࢓૊ΈΛཧղ w"SSPXLUͷίʔυੜ੒Ͱɺ-FOTΛຖճఆٛͤͣʹར༻Մೳ wίϨΫγϣϯɺTFBMFEDMBTTɺWBMVFDMBTTͷૢ࡞ʹ͸0QUJDT Λར༻͢Δ