SecretX
11/20/2021, 8:54 PMOption<Pair<A, Option<B>>>
to Option<Pair<A, B>>
using arrow? This is the code were I want to apply that
fun playerDisconnect(player: Player) {
activeDungeons.remove(player.uniqueId) // returns a String?
?.let { dungeonRepo.getDungeon(it) } // returns an Option<Dungeon>
?.tap {
dungeonRepo.getLastLevel(it) // I need to somehow zip the "Dungeon" with this Option<Level> (returned by the getLastLevel), and use both, or none of the two, if there's no last level
// filter the result using levelSpawnsManager#isLevelComplete, passing the Level I just got as argument
// then run these methods after
levelSpawnsManager.cancelDungeonSpawns(dungeon)
levelSpawnsManager.resetCompletedLevels(dungeon)
player.runLogoffCommands(dungeon)
}
}
SecretX
11/20/2021, 9:36 PMOption<String>
, but it doesn't look very idiomatic
fun playerDisconnect(player: Player) {
activeDungeons.remove(player.uniqueId).toOption()
.flatMap { dungeonRepo.getDungeon(it) }
.flatMap { dungeonRepo.getLastLevel(it).map { level -> it to level } }
.filterNot { (dungeon, level) -> isLevelComplete(dungeon, level) }
.tap { (dungeon, _) ->
levelSpawnsManager.cancelDungeonSpawns(dungeon)
levelSpawnsManager.resetCompletedLevels(dungeon)
player.runLogoffCommands(dungeon)
}
}
Stewart Stewart
11/21/2021, 8:28 AM(F<G<A>>) -> G<F<A>>
ie, OptionPair to PairOption is called sequence
Where types F
and G
are functors (define map).
Option is a “traversable functor”, and Pair is an “applicative bifunctor” (which is to say you can just ignore the left side).
Here we can sequence then inner PO -> OP, then flatten the outer options (OOP -> OP).
x: Option<Pair<A, Option<B>>>
x.flatMap { it.sequencePair() }
I’m not sure if the recent refactor removing kinds and typeclasses has methods for Pair/Tuple2,
but it’s easy enough to sequence
manually using plain Kotlin:
x.flatMap { (a, ob) -> ob.map { Pair(a, it)} }
Which is essentially what you wrote above.
That said, all you really want to do is get a dungeon, check the dungeon, then do cleanup work on the dungeon.
The level isn’t needed, so you can skip the pairing/unpairing portions and just use the level directly in your filter:
getLastLevel(it).exists { isLevelComplete(dungeon, level) }
So your code would look like:
fun playerDisconnect(player: Player) {
activeDungeons.remove(player.uniqueId).toOption()
.flatMap { dungeonRepo.getDungeon(it) }
.filterNot { d -> dungeonRepo.getLastLevel(d).exists { isLevelComplete(d, it) } }
.tap { dungeon ->
levelSpawnsManager.cancelDungeonSpawns(dungeon)
levelSpawnsManager.resetCompletedLevels(dungeon)
player.runLogoffCommands(dungeon)
}
However, Option is deprecated, so you might want to something like this:
fun playerDisconnect(player: Player) {
activeDungeons.remove(player.uniqueId)
?.let { dungeonRepo.getDungeon(it) }
?.takeUnless { d -> dungeonRepo.getLastLevel(d)?.let { isLevelComplete(d, it) } ?: false }
?.also { dungeon ->
levelSpawnsManager.cancelDungeonSpawns(dungeon)
levelSpawnsManager.resetCompletedLevels(dungeon)
player.runLogoffCommands(dungeon)
}
}
Peter
11/22/2021, 4:06 PM