Skip to content
This repository has been archived by the owner on Feb 24, 2021. It is now read-only.

Convert typeclasses into fun interfaces #77

Merged
merged 3 commits into from Jan 7, 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
9 changes: 1 addition & 8 deletions arrow-optics/src/main/kotlin/arrow/optics/Getter.kt
Expand Up @@ -31,7 +31,7 @@ inline fun <S, A> GetterOf<S, A>.fix(): Getter<S, A> = this as Getter<S, A>
* @param S the source of a [Getter]
* @param A the focus of a [Getter]
*/
interface Getter<S, A> : GetterOf<S, A> {
fun interface Getter<S, A> : GetterOf<S, A> {

/**
* Get the focus of a [Getter]
Expand All @@ -46,13 +46,6 @@ interface Getter<S, A> : GetterOf<S, A> {
* [Getter] that takes either [S] or [S] and strips the choice of [S].
*/
fun <S> codiagonal(): Getter<Either<S, S>, S> = Getter { aa -> aa.fold(::identity, ::identity) }

/**
* Invoke operator overload to create a [Getter] of type `S` with focus `A`.
*/
operator fun <S, A> invoke(get: (S) -> A) = object : Getter<S, A> {
override fun get(s: S): A = get(s)
}
}

/**
Expand Down
14 changes: 2 additions & 12 deletions arrow-optics/src/main/kotlin/arrow/optics/Setter.kt
Expand Up @@ -43,7 +43,7 @@ typealias SetterKindedJ<S, A> = PSetterKindedJ<S, S, A, A>
* @param A the focus of a [PSetter]
* @param B the modified focus of a [PSetter]
*/
interface PSetter<S, T, A, B> : PSetterOf<S, T, A, B> {
fun interface PSetter<S, T, A, B> : PSetterOf<S, T, A, B> {

/**
* Modify polymorphically the focus of a [PSetter] with a function [f].
Expand All @@ -53,7 +53,7 @@ interface PSetter<S, T, A, B> : PSetterOf<S, T, A, B> {
/**
* Set polymorphically the focus of a [PSetter] with a value [b].
*/
fun set(s: S, b: B): T
fun set(s: S, b: B): T = modify(s) { b }

companion object {

Expand All @@ -64,16 +64,6 @@ interface PSetter<S, T, A, B> : PSetterOf<S, T, A, B> {
*/
fun <S> codiagonal(): Setter<Either<S, S>, S> = Setter { aa, f -> aa.bimap(f, f) }

/**
* Invoke operator overload to create a [PSetter] of type `S` with target `A`.
* Can also be used to construct [Setter]
*/
operator fun <S, T, A, B> invoke(modify: (S, ((A) -> B)) -> T): PSetter<S, T, A, B> = object : PSetter<S, T, A, B> {
override fun modify(s: S, f: (A) -> B): T = modify(s, f)

override fun set(s: S, b: B): T = modify(s) { b }
}

/**
* Create a [PSetter] from a [arrow.Functor]
*/
Expand Down
14 changes: 2 additions & 12 deletions arrow-optics/src/main/kotlin/arrow/optics/extensions/SetAt.kt
@@ -1,24 +1,14 @@
package arrow.optics.extensions

import arrow.optics.Lens
import arrow.optics.PLens
import arrow.optics.typeclasses.At

/**
* [At] instance definition for [Set].
*/
interface SetAt<A> : At<Set<A>, A, Boolean> {
override fun at(i: A): Lens<Set<A>, Boolean> = PLens(
fun <A> setAt(): At<Set<A>, A, Boolean> = At { i ->
PLens(
get = { it.contains(i) },
set = { s, b -> (if (b) s + i else s - i) }
)

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <A> invoke() = object : SetAt<A> {}
}
}
65 changes: 14 additions & 51 deletions arrow-optics/src/main/kotlin/arrow/optics/extensions/list.kt
Expand Up @@ -13,7 +13,6 @@ import arrow.core.toT
import arrow.core.extensions.option.applicative.applicative
import arrow.core.k
import arrow.core.fix
import arrow.optics.Optional
import arrow.optics.POptional
import arrow.optics.PPrism
import arrow.optics.Prism
Expand Down Expand Up @@ -45,89 +44,58 @@ interface ListTraversal<A> : Traversal<List<A>, A> {
}
}

fun <A> ListExtensions.each(): Each<List<A>, A> = ListEach()
fun <A> ListExtensions.each(): Each<List<A>, A> = listEach()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem


/**
* [Each] instance definition for [List] that summons a [Traversal] to focus in each [A] of the source [List].
*/
interface ListEach<A> : Each<List<A>, A> {
override fun each() = ListTraversal<A>()
fun <A> listEach(): Each<List<A>, A> = Each { ListTraversal() }

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <A> invoke() = object : ListEach<A> {}
}
}

fun <A> ListExtensions.filterIndex(): FilterIndex<List<A>, Int, A> = ListFilterIndex()
fun <A> ListExtensions.filterIndex(): FilterIndex<List<A>, Int, A> = listFilterIndex()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem


/**
* [FilterIndex] instance definition for [List].
*/
interface ListFilterIndex<A> : FilterIndex<List<A>, Int, A> {
override fun filter(p: (Int) -> Boolean): Traversal<List<A>, A> = object : Traversal<List<A>, A> {
fun <A> listFilterIndex(): FilterIndex<List<A>, Int, A> = FilterIndex { p ->
object : Traversal<List<A>, A> {
override fun <F> modifyF(FA: Applicative<F>, s: List<A>, f: (A) -> Kind<F, A>): Kind<F, List<A>> =
s.mapIndexed { index, a -> a toT index }.k().traverse(FA) { (a, j) ->
if (p(j)) f(a) else FA.just(a)
}
}

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <A> invoke() = object : ListFilterIndex<A> {}
}
}

fun <A> ListExtensions.index(): Index<List<A>, Int, A> = ListIndex()
fun <A> ListExtensions.index(): Index<List<A>, Int, A> = listIndex()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem


/**
* [Index] instance definition for [List].
*/
interface ListIndex<A> : Index<List<A>, Int, A> {
override fun index(i: Int): Optional<List<A>, A> = POptional(
fun <A> listIndex(): Index<List<A>, Int, A> = Index { i ->
POptional(
getOrModify = { it.getOrNull(i)?.right() ?: it.left() },
set = { l, a -> l.mapIndexed { index: Int, aa: A -> if (index == i) a else aa } }
)

companion object {

operator fun <A> invoke() = object : ListIndex<A> {}
}
}

fun <A> ListExtensions.cons(): Cons<List<A>, A> = ListCons()
fun <A> ListExtensions.cons(): Cons<List<A>, A> = listCons()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem


/**
* [Cons] instance definition for [List].
*/
interface ListCons<A> : Cons<List<A>, A> {
override fun cons(): Prism<List<A>, Tuple2<A, List<A>>> = PPrism(
fun <A> listCons(): Cons<List<A>, A> = Cons {
PPrism(
getOrModify = { list -> list.firstOrNull()?.let { Tuple2(it, list.drop(1)) }?.right() ?: list.left() },
reverseGet = { (a, aas) -> listOf(a) + aas }
)

companion object {

operator fun <A> invoke() = object : ListCons<A> {}
}
}

fun <A> ListExtensions.snoc(): Snoc<List<A>, A> = ListSnoc()
fun <A> ListExtensions.snoc(): Snoc<List<A>, A> = listSnoc()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fun <A> ListExtensions.snoc(): Snoc<List<A>, A> = listSnoc()
@Deprecated("Use listSnoc() instead", @ReplaceWith("listSnoc()", "arrow.optics.extensions.listSnoc")
fun <A> ListExtensions.snoc(): Snoc<List<A>, A> = listSnoc()

Should this be defined under arrow.optics. instead of arrow.optics.extensions like we're doing in Arrow Core?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I'll do that in a different PR


/**
* [Snoc] instance definition for [List].
*/
interface ListSnoc<A> : Snoc<List<A>, A> {

override fun snoc() = object : Prism<List<A>, Tuple2<List<A>, A>> {
fun <A> listSnoc(): Snoc<List<A>, A> = Snoc {
object : Prism<List<A>, Tuple2<List<A>, A>> {
override fun getOrModify(s: List<A>): Either<List<A>, Tuple2<List<A>, A>> =
Option.applicative().mapN(Option.just(s.dropLast(1)), s.lastOrNull().toOption(), ::identity)
.fix()
Expand All @@ -136,9 +104,4 @@ interface ListSnoc<A> : Snoc<List<A>, A> {
override fun reverseGet(b: Tuple2<List<A>, A>): List<A> =
b.a + b.b
}

companion object {

operator fun <A> invoke() = object : ListSnoc<A> {}
}
}
61 changes: 10 additions & 51 deletions arrow-optics/src/main/kotlin/arrow/optics/extensions/map.kt
Expand Up @@ -3,13 +3,10 @@ package arrow.optics.extensions
import arrow.Kind
import arrow.core.MapInstances
import arrow.core.Option
import arrow.core.Predicate
import arrow.core.left
import arrow.core.right
import arrow.core.getOption
import arrow.core.k
import arrow.optics.Lens
import arrow.optics.Optional
import arrow.optics.PLens
import arrow.optics.POptional
import arrow.optics.Traversal
Expand All @@ -19,13 +16,13 @@ import arrow.optics.typeclasses.FilterIndex
import arrow.optics.typeclasses.Index
import arrow.typeclasses.Applicative

fun <K, V> MapInstances.at(): At<Map<K, V>, K, Option<V>> = MapAt()
fun <K, V> MapInstances.at(): At<Map<K, V>, K, Option<V>> = mapAt()

/**
* [At] instance definition for [Map].
*/
interface MapAt<K, V> : At<Map<K, V>, K, Option<V>> {
override fun at(i: K): Lens<Map<K, V>, Option<V>> = PLens(
fun <K, V> mapAt(): At<Map<K, V>, K, Option<V>> = At { i ->
PLens(
get = { it.getOption(i) },
set = { map, optV ->
optV.fold({
Expand All @@ -35,15 +32,6 @@ interface MapAt<K, V> : At<Map<K, V>, K, Option<V>> {
})
}
)

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <K, V> invoke() = object : MapAt<K, V> {}
}
}

fun <K, V> MapInstances.traversal(): Traversal<Map<K, V>, V> = MapTraversal()
Expand All @@ -66,31 +54,20 @@ interface MapTraversal<K, V> : Traversal<Map<K, V>, V> {
}
}

fun <K, V> MapInstances.each(): Each<Map<K, V>, V> = MapEach()
fun <K, V> MapInstances.each(): Each<Map<K, V>, V> = mapEach()

/**
* [Each] instance definition for [Map].
*/
interface MapEach<K, V> : Each<Map<K, V>, V> {
override fun each() = MapTraversal<K, V>()

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <K, V> invoke() = object : MapEach<K, V> {}
}
}
fun <K, V> mapEach(): Each<Map<K, V>, V> = Each { MapTraversal() }

fun <K, V> MapInstances.filterIndex(): FilterIndex<Map<K, V>, K, V> = filterMapIndex()

/**
* [FilterIndex] instance definition for [Map].
*/
interface filterMapIndex<K, V> : FilterIndex<Map<K, V>, K, V> {
override fun filter(p: Predicate<K>) = object : Traversal<Map<K, V>, V> {
fun <K, V> filterMapIndex(): FilterIndex<Map<K, V>, K, V> = FilterIndex { p ->
object : Traversal<Map<K, V>, V> {
override fun <F> modifyF(FA: Applicative<F>, s: Map<K, V>, f: (V) -> Kind<F, V>): Kind<F, Map<K, V>> = FA.run {
s.toList().k().traverse(FA) { (k, v) ->
(if (p(k)) f(v) else just(v)).map {
Expand All @@ -99,34 +76,16 @@ interface filterMapIndex<K, V> : FilterIndex<Map<K, V>, K, V> {
}.map { it.toMap() }
}
}

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <K, V> invoke() = object : filterMapIndex<K, V> {}
}
}

fun <K, V> MapInstances.index(): Index<Map<K, V>, K, V> = MapIndex()
fun <K, V> MapInstances.index(): Index<Map<K, V>, K, V> = mapIndex()

/**
* [Index] instance definition for [Map].
*/
interface MapIndex<K, V> : Index<Map<K, V>, K, V> {
override fun index(i: K): Optional<Map<K, V>, V> = POptional(
fun <K, V> mapIndex(): Index<Map<K, V>, K, V> = Index { i ->
POptional(
getOrModify = { it[i]?.right() ?: it.left() },
set = { m, v -> m.mapValues { (k, vv) -> if (k == i) v else vv } }
)

companion object {
/**
* Operator overload to instantiate typeclass instance.
*
* @return [Index] instance for [String]
*/
operator fun <K, V> invoke() = object : MapIndex<K, V> {}
}
}