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

Move Optics std to companion objects #888

Merged
merged 34 commits into from
Jun 26, 2018
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7fe7a80
Std as companion
nomisRev Apr 3, 2018
45115fa
Update Option
nomisRev Jun 12, 2018
aa42791
Update String
nomisRev Jun 12, 2018
51d5b28
Update Either
nomisRev Jun 12, 2018
bb3519b
Update List
nomisRev Jun 12, 2018
9649ea2
Update Map
nomisRev Jun 12, 2018
fd1a5f4
Update NonEmptyList
nomisRev Jun 12, 2018
ea00af1
Update Set
nomisRev Jun 12, 2018
e397c33
Update Try
nomisRev Jun 12, 2018
53b3ab1
Update Tuple
nomisRev Jun 12, 2018
b44fa48
Update Validated
nomisRev Jun 12, 2018
96bd72f
Update Id
nomisRev Jun 12, 2018
4c6b8a7
Update SequenceK
nomisRev Jun 12, 2018
7b400bc
Update docs
nomisRev Jun 13, 2018
b50d4a7
Detekt fixes
nomisRev Jun 13, 2018
44b5760
Use correct Eq instance for SequenceKInstanceTest
nomisRev Jun 13, 2018
67334b1
Merge branch 'master' into simon-std-on-companion
nomisRev Jun 13, 2018
bc20b00
Merge branch 'master' into simon-std-on-companion
nomisRev Jun 14, 2018
d9e9baf
Fix optics law links
nomisRev Jun 17, 2018
0faf984
Merge branch 'master' into simon-std-on-companion
pakoito Jun 22, 2018
d9b5fec
Merge branch 'master' into simon-std-on-companion
nomisRev Jun 24, 2018
3c9a69f
Merge branch 'simon-std-on-companion' of github.com:arrow-kt/arrow in…
nomisRev Jun 24, 2018
dcbd3b7
Move List std to ListInstances
nomisRev Jun 24, 2018
de469fa
Move Set std to SetInstances
nomisRev Jun 24, 2018
2d5c0ad
Fix KDoc optics.std.Option
nomisRev Jun 24, 2018
513a6e3
Hygiene - Use method reference where applicable
nomisRev Jun 24, 2018
41dd06b
Add missing test NonEmptyList
nomisRev Jun 24, 2018
6726731
Detekt fix
nomisRev Jun 24, 2018
628a742
Merge branch 'master' into simon-std-on-companion
pakoito Jun 24, 2018
afe1d2f
Merge branch 'master' into simon-std-on-companion
pakoito Jun 24, 2018
369a890
Move Instances objects to arrow-core
nomisRev Jun 25, 2018
60823d7
Add List optics instances to ListInstances
nomisRev Jun 25, 2018
dd0b002
Add Map optics instances to MapInstances
nomisRev Jun 25, 2018
e53b8f2
Merge branch 'master' into simon-std-on-companion
nomisRev Jun 26, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package arrow.instances

object ListInstances
Copy link
Member

Choose a reason for hiding this comment

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

Could you please put this file in arrow-data instead? That way we don't need to depend on the instances package when adding other typeclasses to List.

Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't these go to arrow-core?

Copy link
Member

Choose a reason for hiding this comment

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

It's cheap so why not :D

Original file line number Diff line number Diff line change
@@ -1,73 +1,3 @@
package arrow.instances

import arrow.Kind
import arrow.core.Eval
import arrow.data.*
import arrow.instance
import arrow.typeclasses.*
import arrow.data.combineK as setCombineK
import kotlin.collections.plus as setPlus

@instance(SetK::class)
interface SetKSemigroupInstance<A> : Semigroup<SetK<A>> {
override fun SetK<A>.combine(b: SetK<A>): SetK<A> =
(this.setPlus(b)).k()
}

@instance(SetK::class)
interface SetKMonoidInstance<A> : SetKSemigroupInstance<A>, Monoid<SetK<A>> {
override fun empty(): SetK<A> = emptySet<A>().k()
}

@instance(SetK::class)
interface SetKEqInstance<A> : Eq<SetK<A>> {

fun EQ(): Eq<A>

override fun SetK<A>.eqv(b: SetK<A>): Boolean =
if (size == b.size) set.map { aa ->
b.find { bb -> EQ().run { aa.eqv(bb) } } != null
}.fold(true) { acc, bool ->
acc && bool
}
else false

}

@instance(SetK::class)
interface SetKShowInstance<A> : Show<SetK<A>> {
override fun SetK<A>.show(): String =
toString()
}

@instance(SetK::class)
interface SetKFoldableInstance : Foldable<ForSetK> {
override fun <A, B> Kind<ForSetK, A>.foldLeft(b: B, f: (B, A) -> B): B =
fix().foldLeft(b, f)

override fun <A, B> Kind<ForSetK, A>.foldRight(lb: Eval<B>, f: (A, Eval<B>) -> Eval<B>): Eval<B> =
fix().foldRight(lb, f)

override fun <A> Kind<ForSetK, A>.isEmpty(): kotlin.Boolean =
fix().isEmpty()
}

@instance(SetK::class)
interface SetKSemigroupKInstance : SemigroupK<ForSetK> {
override fun <A> Kind<ForSetK, A>.combineK(y: Kind<ForSetK, A>): SetK<A> =
fix().setCombineK(y)
}

@instance(SetK::class)
interface SetKMonoidKInstance : MonoidK<ForSetK> {
override fun <A> empty(): SetK<A> =
SetK.empty()

override fun <A> Kind<ForSetK, A>.combineK(y: Kind<ForSetK, A>): SetK<A> =
fix().setCombineK(y)
}

object SetKContext : SetKFoldableInstance, SetKMonoidKInstance

infix fun <A> ForSetK.Companion.extensions(f: SetKContext.() -> A): A =
f(SetKContext)
object SetInstances
Copy link
Member

@pakoito pakoito Jun 24, 2018

Choose a reason for hiding this comment

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

Same as ListInstances! We could also add the others: Map, SortedMap, and SortedSet.

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package arrow.instances

import arrow.Kind
import arrow.core.Eval
import arrow.data.*
import arrow.instance
import arrow.typeclasses.*
import arrow.data.combineK as setCombineK
import kotlin.collections.plus as setPlus

@instance(SetK::class)
interface SetKSemigroupInstance<A> : Semigroup<SetK<A>> {
override fun SetK<A>.combine(b: SetK<A>): SetK<A> =
(this.setPlus(b)).k()
}

@instance(SetK::class)
interface SetKMonoidInstance<A> : SetKSemigroupInstance<A>, Monoid<SetK<A>> {
override fun empty(): SetK<A> = emptySet<A>().k()
}

@instance(SetK::class)
interface SetKEqInstance<A> : Eq<SetK<A>> {

fun EQ(): Eq<A>

override fun SetK<A>.eqv(b: SetK<A>): Boolean =
if (size == b.size) set.map { aa ->
b.find { bb -> EQ().run { aa.eqv(bb) } } != null
}.fold(true) { acc, bool ->
acc && bool
}
else false

}

@instance(SetK::class)
interface SetKShowInstance<A> : Show<SetK<A>> {
override fun SetK<A>.show(): String =
toString()
}

@instance(SetK::class)
interface SetKFoldableInstance : Foldable<ForSetK> {
override fun <A, B> Kind<ForSetK, A>.foldLeft(b: B, f: (B, A) -> B): B =
fix().foldLeft(b, f)

override fun <A, B> Kind<ForSetK, A>.foldRight(lb: Eval<B>, f: (A, Eval<B>) -> Eval<B>): Eval<B> =
fix().foldRight(lb, f)

override fun <A> Kind<ForSetK, A>.isEmpty(): kotlin.Boolean =
fix().isEmpty()
}

@instance(SetK::class)
interface SetKSemigroupKInstance : SemigroupK<ForSetK> {
override fun <A> Kind<ForSetK, A>.combineK(y: Kind<ForSetK, A>): SetK<A> =
fix().setCombineK(y)
}

@instance(SetK::class)
interface SetKMonoidKInstance : MonoidK<ForSetK> {
override fun <A> empty(): SetK<A> =
SetK.empty()

override fun <A> Kind<ForSetK, A>.combineK(y: Kind<ForSetK, A>): SetK<A> =
fix().setCombineK(y)
}

object SetKContext : SetKFoldableInstance, SetKMonoidKInstance

infix fun <A> ForSetK.Companion.extensions(f: SetKContext.() -> A): A =
f(SetKContext)
6 changes: 3 additions & 3 deletions modules/docs/arrow-docs/docs/docs/optics/getter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ Or from any of the optics defined in `arrow-optics` that allow to safely getting
import arrow.core.*
import arrow.optics.instances.*

val headGetter: Getter<NonEmptyList<String>, String> = nelHead<String>().asGetter()
val tupleGetter: Getter<Tuple2<String, Int>, String> = firstTuple2<String, Int>().asGetter()
val headGetter: Getter<NonEmptyList<String>, String> = NonEmptyList.head<String>().asGetter()
val tupleGetter: Getter<Tuple2<String, Int>, String> = Tuple2.first<String, Int>().asGetter()
```

## Composition

Unlike a regular `get` function a `Getter` composes. Similar to a `Lens` we can compose `Getter`s to create telescopes and zoom into nested structures.

```kotlin:ank
val firstBar: Getter<NonEmptyList<Foo>, Int> = (nelHead<Foo>() compose barGetter)
val firstBar: Getter<NonEmptyList<Foo>, Int> = NonEmptyList.head<Foo>() compose barGetter
firstBar.get(Foo(5).nel())
```

Expand Down
28 changes: 14 additions & 14 deletions modules/docs/arrow-docs/docs/docs/optics/optional/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,46 +20,46 @@ It combines the properties of a `Lens` (getting, setting and modifying) with the
For a structure `List<Int>` we can create an `Optional` to focus an optional head `Int`.

```kotlin:ank
import arrow.*
import arrow.core.*
import arrow.data.*
import arrow.optics.*

val optionalHead: Optional<List<Int>, Int> = Optional(
val optionalHead: Optional<ListK<Int>, Int> = Optional(
getOrModify = { list -> list.firstOrNull()?.right() ?: list.left() },
set = { int -> { list -> list.mapIndexed { index, value -> if (index == 0) int else value } } }
set = { int -> { list -> list.mapIndexed { index, value -> if (index == 0) int else value }.k() } }
)
```

Our `optionalHead` allows us to operate on the head of `List<Int>` without having to worry if it is available. The `optionalHead` optic is by default available as `listHead<Int>()`
Our `optionalHead` allows us to operate on the head of `List<Int>` without having to worry if it is available. You can find `optionalHead` in the optics library: `ListK.head<Int>()`

```kotlin:ank
import arrow.optics.instances.*

listHead<Int>().set(listOf(1, 3, 6), 5)
ListK.head<Int>().set(listOf(1, 3, 6).k(), 5)
```
```kotlin:ank
listHead<Int>().modify(listOf(1, 3, 6)) { head -> head * 5 }
ListK.head<Int>().modify(listOf(1, 3, 6).k()) { head -> head * 5 }
```

We can also lift such functions.

```kotlin:ank
val lifted = listHead<Int>().lift { head -> head * 5 }
lifted(emptyList())
val lifted = ListK.head<Int>().lift { head -> head * 5 }
lifted(emptyList<Int>().k())
```

Or modify or lift functions using `Applicative`

```kotlin:ank
listHead<Int>().modifyF(Try.applicative(), listOf(1, 3, 6)) { head ->
ListK.head<Int>().modifyF(Try.applicative(), listOf(1, 3, 6).k()) { head ->
Try { head / 2 }
}
```
```kotlin:ank
val liftedF = listHead<Int>().liftF(Try.applicative()) { head ->
val liftedF = ListK.head<Int>().liftF(Try.applicative()) { head ->
Try { head / 0 }
}
liftedF(listOf(1, 3, 6))
liftedF(listOf(1, 3, 6).k())
```

An `Optional` instance can be manually constructed from any default or custom `Iso`, `Lens` or `Prism` instance by calling their `asOptional()` or by creating a custom `Optional` instance as shown above.
Expand All @@ -76,7 +76,7 @@ val participantEmail: Optional<Participant, String> = Optional(
set = { email -> { participant -> participant.copy(email = email) } }
)

val triedEmail: Optional<Try<Participant>, String> = trySuccess<Participant>() compose participantEmail
val triedEmail: Optional<Try<Participant>, String> = Try.success<Participant>() compose participantEmail

triedEmail.getOption(Try.Success(Participant("test", "email")))
```
Expand Down Expand Up @@ -112,8 +112,8 @@ A `POptional` is very similar to [PLens](/docs/optics/lens#Plens) and [PPrism](/
Given a `PPrism` with a focus into `Success` of `Try<Tuple2<Int, String>>` that can polymorphically change its content to `Tuple2<String, String>` and a `PLens` with a focus into the `Tuple2<Int, String>` that can morph the first parameter from `Int` to `String`. We can compose them together build an `Optional` that can look into `Try` and morph the first type of the `Tuple2` within.

```kotlin:ank
val pprism = pTrySuccess<Tuple2<Int, String>, Tuple2<String, String>>()
val plens = pFirstTuple2<Int, String, String>()
val pprism = Try.pSuccess<Tuple2<Int, String>, Tuple2<String, String>>()
val plens = Tuple2.pFirst<Int, String, String>()

val successTuple2: POptional<Try<Tuple2<Int, String>>, Try<Tuple2<String, String>>, Int, String> =
pprism compose plens
Expand Down
10 changes: 4 additions & 6 deletions modules/docs/arrow-docs/docs/docs/optics/traversal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ listTraversal.modifyF(Try.applicative(), listOf(0, 2, 3).k()) {
Or by using any of the constructors of `Traversal`.

```kotlin:ank
import arrow.core.*

fun <A> traversalTuple2Example(): Traversal<Tuple2<A, A>, A> = Traversal(
get1 = { it.a },
get2 = { it.b },
Expand All @@ -54,10 +52,10 @@ Arrow optics also provides a number of predefined `Traversal` optics.
```kotlin:ank
import arrow.instances.*

traversalTuple2<String>().combineAll(String.monoid(), "Hello, " toT "World!")
Tuple2.traversal<String>().combineAll(String.monoid(), "Hello, " toT "World!")
```
```kotlin:ank
traversalTuple10<Int>().getAll(Tuple10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
Tuple10.traversal<Int>().getAll(Tuple10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
```

## Composition
Expand All @@ -66,9 +64,9 @@ Composing `Traversal` can be used for accessing and modifying foci in nested str

```kotlin:ank
val listOfPairTraversal: Traversal<ListKOf<Tuple2<String, String>>, Tuple2<String, String>> = Traversal.fromTraversable(ListK.traverse())
val nestedInts = listOfPairTraversal compose traversalTuple2()
val nestedStrings = listOfPairTraversal compose Tuple2.traversal<String>()

nestedInts.fold(String.monoid(), listOf("Hello, " toT "World ", "from " toT "nested structures!").k())
nestedStrings.fold(String.monoid(), listOf("Hello, " toT "World ", "from " toT "nested structures!").k())
```

`Traversal` can be composed with all optics and results in the following optics.
Expand Down
6 changes: 4 additions & 2 deletions modules/docs/arrow-docs/src/main/kotlin/OpticsHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ data class Employee(val name: String, val company: Company) {
sealed class Shape {
companion object {}

@optics data class Circle(val radius: Double) : Shape() {
@optics
data class Circle(val radius: Double) : Shape() {
companion object
}

@optics data class Rectangle(val width: Double, val height: Double) : Shape() {
@optics
data class Rectangle(val width: Double, val height: Double) : Shape() {
companion object
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,52 @@ import arrow.optics.*
* @receiver [Lens] with a focus in [Option]<[S]>
* @return [Optional] with a focus in [S]
*/
inline val <T, S> Lens<T, Option<S>>.some: Optional<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Lens<T, Option<S>>.some: Optional<T, S> inline get() = this.compose(Option.some())

/**
* DSL to compose a [Prism] with focus [arrow.core.Some] with a [Iso] with a focus of [Option]<[S]>
*
* @receiver [Iso] with a focus in [Option]<[S]>
* @return [Prism] with a focus in [S]
*/
inline val <T, S> Iso<T, Option<S>>.some: Prism<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Iso<T, Option<S>>.some: Prism<T, S> inline get() = this.compose(Option.some())

/**
* DSL to compose a [Prism] with focus [arrow.core.Some] with a [Prism] with a focus of [Option]<[S]>
*
* @receiver [Prism] with a focus in [Option]<[S]>
* @return [Prism] with a focus in [S]
*/
inline val <T, S> Prism<T, Option<S>>.some: Prism<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Prism<T, Option<S>>.some: Prism<T, S> inline get() = this.compose(Option.some())

/**
* DSL to compose a [Prism] with focus [arrow.core.Some] with a [Optional] with a focus of [Option]<[S]>
*
* @receiver [Optional] with a focus in [Option]<[S]>
* @return [Optional] with a focus in [S]
*/
inline val <T, S> Optional<T, Option<S>>.some: Optional<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Optional<T, Option<S>>.some: Optional<T, S> inline get() = this.compose(Option.some())

/**
* DSL to compose a [Prism] with focus [arrow.core.Some] with a [Setter] with a focus of [Option]<[S]>
*
* @receiver [Setter] with a focus in [Option]<[S]>
* @return [Setter] with a focus in [S]
*/
inline val <T, S> Setter<T, Option<S>>.some: Setter<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Setter<T, Option<S>>.some: Setter<T, S> inline get() = this.compose(Option.some())

/**
* DSL to compose a [Prism] with focus [arrow.core.Some] with a [Traversal] with a focus of [Option]<[S]>
*
* @receiver [Traversal] with a focus in [Option]<[S]>
* @return [Traversal] with a focus in [S]
*/
inline val <T, S> Traversal<T, Option<S>>.some: Traversal<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Traversal<T, Option<S>>.some: Traversal<T, S> inline get() = this.compose(Option.some())

/**
* DSL to compose a [Prism] with focus [arrow.core.Some] with a [Fold] with a focus of [Option]<[S]>
*
* @receiver [Fold] with a focus in [Option]<[S]>
* @return [Fold] with a focus in [S]
*/
inline val <T, S> Fold<T, Option<S>>.some: Fold<T, S> inline get() = this.compose(somePrism())
inline val <T, S> Fold<T, Option<S>>.some: Fold<T, S> inline get() = this.compose(Option.some())
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@ import arrow.optics.Traversal
import arrow.optics.typeclasses.Each
import arrow.typeclasses.Applicative

/**
* [Traversal] for [Either] that has focus in each [Either.Right].
*
* @receiver [Either.Companion] to make it statically available.
* @return [Traversal] with source [Either] and focus every [Either.Right] of the source.
*/
fun <L, R> Either.Companion.traversal(): Traversal<Either<L, R>, R> = object : Traversal<Either<L, R>, R> {
override fun <F> modifyF(FA: Applicative<F>, s: Either<L, R>, f: (R) -> Kind<F, R>): Kind<F, Either<L, R>> = with(Either.traverse<L>()) {
FA.run { s.traverse(FA, f).map { it.fix() } }
}
}

/**
* [Each] instance for [Either] that has focus in each [Either.Right].
*/
@instance(Either::class)
interface EitherEachInstance<L, R> : Each<Either<L, R>, R> {
override fun each(): Traversal<Either<L, R>, R> =
Expand Down
Loading