Generify mapFirst/Second on Tuples

This commit is contained in:
kageru 2019-11-13 22:06:30 +01:00
parent a05f2e558b
commit 07c45d84d0
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
2 changed files with 16 additions and 13 deletions

View File

@ -1,11 +1,10 @@
package moe.kageru.kagebot.extensions
import arrow.Kind
import arrow.core.Either
import arrow.core.Option
import arrow.core.Tuple3
import arrow.core.getOrElse
import arrow.optics.pFirst
import arrow.optics.pSecond
import arrow.typeclasses.Functor
fun <L, R> Either<L, R>.on(op: (R) -> Unit): Either<L, R> {
this.map { op(it) }
@ -14,10 +13,10 @@ fun <L, R> Either<L, R>.on(op: (R) -> Unit): Either<L, R> {
fun <T> Either<*, T>.unwrap(): T = getOrElse { error("Attempted to unwrap Either.left") }
fun <A, B, C, R> Tuple3<A, B, C>.mapSecond(op: (B) -> Option<R>): Option<Tuple3<A, R, C>> {
return op(this.b).map { Tuple3.pSecond<A, B, C, R>().set(this, it) }
fun <A, B, C, A2, F> Tuple3<A, B, C>.mapFirst(AP: Functor<F>, op: (A) -> Kind<F, A2>) = let { (a, b, c) ->
AP.run { op(a).map { Tuple3(it, b, c) } }
}
fun <A, B, C, R> Tuple3<A, B, C>.mapFirst(op: (A) -> Option<R>): Option<Tuple3<R, B, C>> {
return op(this.a).map { Tuple3.pFirst<A, B, C, R>().set(this, it) }
fun <A, B, C, B2, F> Tuple3<A, B, C>.mapSecond(AP: Functor<F>, op: (B) -> Kind<F, B2>) = let { (a, b, c) ->
AP.run { op(b).map { Tuple3(a, it, c) } }
}

View File

@ -1,11 +1,12 @@
package moe.kageru.kagebot.features
import arrow.core.Either
import arrow.core.Tuple3
import arrow.Kind
import arrow.core.*
import arrow.core.extensions.either.applicative.applicative
import arrow.core.extensions.either.monad.flatMap
import arrow.core.extensions.list.monad.map
import arrow.core.extensions.listk.functorFilter.filter
import arrow.core.toOption
import arrow.core.extensions.option.applicative.applicative
import arrow.syntax.collections.destructured
import com.fasterxml.jackson.annotation.JsonProperty
import moe.kageru.kagebot.Log
@ -32,13 +33,16 @@ class TimeoutFeature(@JsonProperty("role") role: String) : MessageFeature {
{ Tuple3(args[1], args[2], args.getOrNull(3)) },
{ "Error: expected “<command> <user> <time> [<reason>]”. If the name contains spaces, please use the user ID instead." }
).flatMap {
it.mapFirst(::findUser).toEither { "Error: User ${it.a} not found, consider using the user ID" }
it.mapFirst(Option.applicative(), ::findUser).fix()
.toEither { "Error: User ${it.a} not found, consider using the user ID" }
}.flatMap {
it.mapSecond { time -> time.toLongOrNull().toOption() }.toEither { "Error: malformed time “${it.b}" }
it.mapSecond(Either.applicative()) { time ->
time.toLongOrNull().rightIfNotNull { "Error: malformed time “${it.b}" }
}.fix()
}.on { (user, time, _) ->
applyTimeout(user, time)
}.fold(
{ message.channel.sendMessage(it) },
{ error -> message.channel.sendMessage(error) },
{ (user, time, reason) ->
user.sendEmbed {
addField("Timeout", Config.localization[LocalizationSpec.timeout].replace("@@", "$time"))