Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CU-fb532c - Clean up Selective api #2312

Merged
merged 8 commits into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import arrow.Kind
import arrow.KindDeprecation
import arrow.core.Either.Right
import arrow.typeclasses.Monoid
import arrow.typeclasses.SelectiveDeprecation
import arrow.typeclasses.Semigroup
import arrow.typeclasses.Show

Expand Down Expand Up @@ -974,7 +975,8 @@ inline fun <T> Option<T>.getOrElse(default: () -> T): T = fold({ default() }, ::
*
* @param alternative the default option if this is empty.
*/
inline fun <A> OptionOf<A>.orElse(alternative: () -> Option<A>): Option<A> = if (fix().isEmpty()) alternative() else fix()
inline fun <A> OptionOf<A>.orElse(alternative: () -> Option<A>): Option<A> =
if (fix().isEmpty()) alternative() else fix()

infix fun <T> OptionOf<T>.or(value: Option<T>): Option<T> = if (fix().isEmpty()) {
value
Expand Down Expand Up @@ -1014,32 +1016,15 @@ fun <T> Iterable<T>.lastOrNone(predicate: (T) -> Boolean): Option<T> = this.last

fun <T> Iterable<T>.elementAtOrNone(index: Int): Option<T> = this.elementAtOrNull(index).toOption()

@Deprecated(SelectiveDeprecation)
fun <A, B> Option<Either<A, B>>.select(f: OptionOf<(A) -> B>): Option<B> =
branch(f.fix(), Some(::identity))

fun <A, B, C> Option<Either<A, B>>.branch(fa: Option<(A) -> C>, fb: Option<(B) -> C>): Option<C> =
flatMap {
it.fold(
{ a -> Some(a).ap(fa) },
{ b -> Some(b).ap(fb) }
{ a -> Some(a).ap(f.fix()) },
{ b -> Some(b).ap(Some(::identity)) }
)
}

private fun Option<Boolean>.selector(): Option<Either<Unit, Unit>> =
map { bool -> if (bool) Either.right(Unit) else Either.left(Unit) }

fun <A> Option<Boolean>.whenS(x: Option<() -> Unit>): Option<Unit> =
selector().select(x.map { f -> { _: Unit -> f() } })

fun <A> Option<Boolean>.ifS(fl: Option<A>, fr: Option<A>): Option<A> =
selector().branch(fl.map { { _: Unit -> it } }, fr.map { { _: Unit -> it } })

fun Option<Boolean>.orS(f: Option<Boolean>): Option<Boolean> =
ifS(Some(true), f)

fun Option<Boolean>.andS(f: Option<Boolean>): Option<Boolean> =
ifS(f, Some(false))

fun <A> Option<A>.combineAll(MA: Monoid<A>): A = MA.run {
foldLeft(empty()) { acc, a -> acc.combine(a) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1127,33 +1127,6 @@ operator fun <E : Comparable<E>, A : Comparable<A>> Validated<E, A>.compareTo(ot
{ r1 -> other.fold({ 1 }, { r2 -> r1.compareTo(r2) }) }
)

fun <E, A, B> Validated<E, Either<A, B>>.select(f: Validated<E, (A) -> B>): Validated<E, B> =
fold({ Invalid(it) }, { it.fold({ l -> f.map { ff -> ff(l) } }, { r -> r.valid() }) })

fun <E, A, B, C> Validated<E, Either<A, B>>.branch(fl: Validated<E, (A) -> C>, fr: Validated<E, (B) -> C>): Validated<E, C> =
when (this) {
is Validated.Valid -> when (val either = this.a) {
is Either.Left -> fl.map { f -> f(either.a) }
is Either.Right -> fr.map { f -> f(either.b) }
}
is Validated.Invalid -> this
}

private fun <E> Validated<E, Boolean>.selector(): Validated<E, Either<Unit, Unit>> =
map { bool -> if (bool) Either.leftUnit else Either.unit }

fun <E> Validated<E, Boolean>.whenS(x: Validated<E, () -> Unit>): Validated<E, Unit> =
selector().select(x.map { f -> { f() } })

fun <E, A> Validated<E, Boolean>.ifS(fl: Validated<E, A>, fr: Validated<E, A>): Validated<E, A> =
selector().branch(fl.map { { _: Unit -> it } }, fr.map { { _: Unit -> it } })

fun <E> Validated<E, Boolean>.orS(f: Validated<E, Boolean>): Validated<E, Boolean> =
ifS(Valid(true), f)

fun <E> Validated<E, Boolean>.andS(f: Validated<E, Boolean>): Validated<E, Boolean> =
ifS(f, Valid(false))

/**
* Return the Valid value, or the default if Invalid
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,36 @@ import arrow.core.andThen
import arrow.core.left
import arrow.core.right

const val SelectiveDeprecation =
"""Selective typeclass is deprecated and will be removed in 0.13.0."""

@Deprecated(KindDeprecation)
interface Selective<F> : Applicative<F> {
fun <A, B> Kind<F, Either<A, B>>.select(f: Kind<F, (A) -> B>): Kind<F, B>

private fun Kind<F, Boolean>.selector(): Kind<F, Either<Unit, Unit>> =
map { bool -> if (bool) Unit.left() else Unit.right() }

@Deprecated(SelectiveDeprecation)
fun <A, B, C> Kind<F, Either<A, B>>.branch(fl: Kind<F, (A) -> C>, fr: Kind<F, (B) -> C>): Kind<F, C> {
val nested: Kind<F, Either<A, Either<B, Nothing>>> = map { it.map(::Left) }
val ffl: Kind<F, (A) -> Either<Nothing, C>> = fl.map { it.andThen(::Right) }
return nested.select(ffl).select(fr)
}

@Deprecated(SelectiveDeprecation)
fun <A> Kind<F, Boolean>.whenS(x: Kind<F, () -> Unit>): Kind<F, Unit> =
selector().select(x.map { f -> { _: Unit -> f() } })

@Deprecated(SelectiveDeprecation)
fun <A> Kind<F, Boolean>.ifS(fl: Kind<F, A>, fr: Kind<F, A>): Kind<F, A> =
selector().branch(fl.map { { _: Unit -> it } }, fr.map { { _: Unit -> it } })

@Deprecated(SelectiveDeprecation)
fun <A> Kind<F, Boolean>.orS(f: Kind<F, Boolean>): Kind<F, Boolean> =
ifS(just(true), f)

@Deprecated(SelectiveDeprecation)
fun <A> Kind<F, Boolean>.andS(f: Kind<F, Boolean>): Kind<F, Boolean> =
ifS(f, just(false))
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import arrow.core.ForOption
import arrow.core.Option
import arrow.core.Option.Companion
import arrow.core.extensions.OptionSelective
import arrow.typeclasses.SelectiveDeprecation
import kotlin.Boolean
import kotlin.Deprecated
import kotlin.Function0
Expand Down Expand Up @@ -49,14 +50,7 @@ fun <A, B> Kind<ForOption, Either<A, B>>.select(arg1: Kind<ForOption, Function1<
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated(
"@extension kinded projected functions are deprecated",
ReplaceWith(
"branch(arg1, arg2)",
"arrow.core.branch"
),
DeprecationLevel.WARNING
)
@Deprecated(SelectiveDeprecation)
fun <A, B, C> Kind<ForOption, Either<A, B>>.branch(
arg1: Kind<ForOption, Function1<A, C>>,
arg2: Kind<ForOption, Function1<B, C>>
Expand All @@ -71,14 +65,7 @@ fun <A, B, C> Kind<ForOption, Either<A, B>>.branch(
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated(
"@extension kinded projected functions are deprecated",
ReplaceWith(
"whenS(arg1)",
"arrow.core.whenS"
),
DeprecationLevel.WARNING
)
@Deprecated(SelectiveDeprecation)
fun <A> Kind<ForOption, Boolean>.whenS(arg1: Kind<ForOption, Function0<Unit>>): Option<Unit> =
arrow.core.Option.selective().run {
this@whenS.whenS<A>(arg1) as arrow.core.Option<kotlin.Unit>
Expand All @@ -91,14 +78,7 @@ fun <A> Kind<ForOption, Boolean>.whenS(arg1: Kind<ForOption, Function0<Unit>>):
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated(
"@extension kinded projected functions are deprecated",
ReplaceWith(
"ifS(arg1, arg2)",
"arrow.core.ifS"
),
DeprecationLevel.WARNING
)
@Deprecated(SelectiveDeprecation)
fun <A> Kind<ForOption, Boolean>.ifS(arg1: Kind<ForOption, A>, arg2: Kind<ForOption, A>): Option<A> =
arrow.core.Option.selective().run {
this@ifS.ifS<A>(arg1, arg2) as arrow.core.Option<A>
Expand All @@ -111,14 +91,7 @@ fun <A> Kind<ForOption, Boolean>.ifS(arg1: Kind<ForOption, A>, arg2: Kind<ForOpt
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated(
"@extension kinded projected functions are deprecated",
ReplaceWith(
"orS(arg1)",
"arrow.core.orS"
),
DeprecationLevel.WARNING
)
@Deprecated(SelectiveDeprecation)
fun <A> Kind<ForOption, Boolean>.orS(arg1: Kind<ForOption, Boolean>): Option<Boolean> =
arrow.core.Option.selective().run {
this@orS.orS<A>(arg1) as arrow.core.Option<kotlin.Boolean>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,11 @@ import arrow.Kind
import arrow.core.Either
import arrow.core.ForValidated
import arrow.core.Validated
import arrow.core.select
import arrow.core.branch
import arrow.core.Validated.Companion
import arrow.core.extensions.ValidatedSelective
import arrow.core.fix
import arrow.core.ifS
import arrow.core.andS
import arrow.core.orS
import arrow.core.whenS
import arrow.typeclasses.SelectiveDeprecation
import arrow.typeclasses.Semigroup
import kotlin.Boolean
import kotlin.Function0
import kotlin.Function1
import kotlin.Suppress
import kotlin.Unit
import kotlin.jvm.JvmName

@JvmName("select")
@Suppress(
Expand All @@ -32,8 +21,9 @@ import kotlin.jvm.JvmName
fun <E, A, B> Kind<Kind<ForValidated, E>, Either<A, B>>.select(
SE: Semigroup<E>,
arg1: Kind<Kind<ForValidated, E>, Function1<A, B>>
): Validated<E, B> =
fix().select(arg1.fix())
): Validated<E, B> = arrow.core.Validated.selective(SE).run {
fix().select<A, B>(arg1.fix()) as arrow.core.Validated<E, B>
}

@JvmName("branch")
@Suppress(
Expand All @@ -42,13 +32,14 @@ fun <E, A, B> Kind<Kind<ForValidated, E>, Either<A, B>>.select(
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated("@extension kinded projected functions are deprecated", ReplaceWith("branch(arg1, arg2)", "arrow.core.branch"))
@Deprecated(SelectiveDeprecation)
fun <E, A, B, C> Kind<Kind<ForValidated, E>, Either<A, B>>.branch(
SE: Semigroup<E>,
arg1: Kind<Kind<ForValidated, E>, Function1<A, C>>,
arg2: Kind<Kind<ForValidated, E>, Function1<B, C>>
): Validated<E, C> =
fix().branch(arg1.fix(), arg2.fix())
): Validated<E, C> = arrow.core.Validated.selective(SE).run {
fix().branch<A, B, C>(arg1.fix(), arg2.fix()) as arrow.core.Validated<E, C>
}

@JvmName("whenS")
@Suppress(
Expand All @@ -57,12 +48,13 @@ fun <E, A, B, C> Kind<Kind<ForValidated, E>, Either<A, B>>.branch(
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated("@extension kinded projected functions are deprecated", ReplaceWith("whenS(arg1)", "arrow.core.whenS"))
@Deprecated(SelectiveDeprecation)
fun <E> Kind<Kind<ForValidated, E>, Boolean>.whenS(
SE: Semigroup<E>,
arg1: Kind<Kind<ForValidated, E>, Function0<Unit>>
): Validated<E, Unit> =
fix().whenS(arg1.fix())
): Validated<E, Unit> = arrow.core.Validated.selective(SE).run {
fix().whenS<E>(arg1.fix()) as arrow.core.Validated<E, Unit>
}

@JvmName("ifS")
@Suppress(
Expand All @@ -71,13 +63,14 @@ fun <E> Kind<Kind<ForValidated, E>, Boolean>.whenS(
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated("@extension kinded projected functions are deprecated", ReplaceWith("ifS(arg1, arg2)", "arrow.core.ifS"))
@Deprecated(SelectiveDeprecation)
fun <E, A> Kind<Kind<ForValidated, E>, Boolean>.ifS(
SE: Semigroup<E>,
arg1: Kind<Kind<ForValidated, E>, A>,
arg2: Kind<Kind<ForValidated, E>, A>
): Validated<E, A> =
fix().ifS(arg1.fix(), arg2.fix())
): Validated<E, A> = arrow.core.Validated.selective(SE).run {
fix().ifS(arg1.fix(), arg2.fix()) as arrow.core.Validated<E, A>
}

@JvmName("orS")
@Suppress(
Expand All @@ -86,12 +79,13 @@ fun <E, A> Kind<Kind<ForValidated, E>, Boolean>.ifS(
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated("@extension kinded projected functions are deprecated", ReplaceWith("orS(arg1)", "arrow.core.ifS"))
@Deprecated(SelectiveDeprecation)
fun <E, A> Kind<Kind<ForValidated, E>, Boolean>.orS(
SE: Semigroup<E>,
arg1: Kind<Kind<ForValidated, E>, Boolean>
): Validated<E, Boolean> =
fix().orS(arg1.fix())
): Validated<E, Boolean> = arrow.core.Validated.selective(SE).run {
fix().orS<A>(arg1.fix()) as arrow.core.Validated<E, Boolean>
}

@JvmName("andS")
@Suppress(
Expand All @@ -100,20 +94,22 @@ fun <E, A> Kind<Kind<ForValidated, E>, Boolean>.orS(
"EXTENSION_SHADOWED_BY_MEMBER",
"UNUSED_PARAMETER"
)
@Deprecated(SelectiveDeprecation)
fun <E, A> Kind<Kind<ForValidated, E>, Boolean>.andS(
SE: Semigroup<E>,
arg1: Kind<Kind<ForValidated,
E>, Boolean>
): Validated<E, Boolean> =
fix().andS(arg1.fix())
E>, Boolean>
): Validated<E, Boolean> = arrow.core.Validated.selective(SE).run {
fix().andS<A>(arg1.fix()) as arrow.core.Validated<E, Boolean>
}

@Suppress(
"UNCHECKED_CAST",
"NOTHING_TO_INLINE"
)
@Deprecated("Selective typeclasses is deprecated. Use concrete methods on Validated")
inline fun <E> Companion.selective(SE: Semigroup<E>): ValidatedSelective<E> = object :
arrow.core.extensions.ValidatedSelective<E> {
override fun SE(): arrow.typeclasses.Semigroup<E> =
SE
}
inline fun <E> Companion.selective(SE: Semigroup<E>): ValidatedSelective<E> =
object : arrow.core.extensions.ValidatedSelective<E> {
override fun SE(): arrow.typeclasses.Semigroup<E> =
SE
}
24 changes: 0 additions & 24 deletions arrow-site/docs/docs/arrow/typeclasses/selective/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,6 @@ Some<Either<Int, String>>(Right("2"))
.select(Some({ a: Int -> a.toString() }))
```

#### Kind<F, Either<A, B>>#branch

Applies an effectful computation to either side of the branch.

```kotlin:ank
import arrow.core.extensions.option.selective.branch

Some<Either<Int, String>>(Left(1))
.branch(Some({ a: Int ->
listOf(a.toString())
}), Some({ b: String ->
listOf(b)
}))
```

```kotlin:ank
Some<Either<Int, String>>(Right("0"))
.branch(Some({ a: Int ->
listOf(a.toString())
}), Some({ b: String ->
listOf(b)
}))
```

### Laws

Arrow provides [`SelectiveLaws`][selective_law_source]{:target="_blank"} in the form of test cases for internal verification of lawful instances and third party apps creating their own Selective instances.
Expand Down