diff --git a/arrow-site/docs/_data/sidebar-optics.yml b/arrow-site/docs/_data/sidebar-optics.yml index c7238299347..a7a0b0d2b44 100644 --- a/arrow-site/docs/_data/sidebar-optics.yml +++ b/arrow-site/docs/_data/sidebar-optics.yml @@ -2,13 +2,13 @@ options: - title: Quick Start url: /optics/ - - title: DSL - url: /optics/dsl/ - - - title: Types + - title: Values DSL nested_options: + - title: Overview + url: /optics/dsl/ + - title: Iso url: /optics/iso/ @@ -27,6 +27,13 @@ options: - title: Setter url: /optics/setter/ + - title: Collections DSL + + nested_options: + + - title: Overview + url: /optics/collections_dsl/ + - title: Fold url: /optics/fold/ diff --git a/arrow-site/docs/docs/collections_dsl/README.md b/arrow-site/docs/docs/collections_dsl/README.md new file mode 100644 index 00000000000..12bcccdedd4 --- /dev/null +++ b/arrow-site/docs/docs/collections_dsl/README.md @@ -0,0 +1,96 @@ +--- +layout: docs-optics +title: Syntax DSL +permalink: /optics/collections_dsl/ +--- + +## Optics DSL for Collections + +The Optics DSL has special support for optics that refer to elements in a collection. + +### [Every]({{ '/optics/every' | relative_url }}) + +`Every` can be used to focus into a structure `S` and see all its foci `A`. Here, we focus into all `Employee`s in the `Employees`. + +```kotlin +@optics data class Employees(val employees: List) { + companion object +} +``` + +```kotlin:ank +import arrow.optics.Every + +val jane = Employee("Jane Doe", Company("Kategory", Address("Functional city", Street(42, "lambda street")))) +val employees = Employees(listOf(john, jane)) + +Employees.employees.every(Every.list()).company.address.street.name.modify(employees, String::capitalize) +``` + +If you are in the scope of `Each`, you don't need to specify the instance. + +```kotlin:ank +Every.list().run { + Employees.employees.every.company.address.street.name.modify(employees, String::capitalize) +} +``` + +### [At]({{ '/optics/at' | relative_url }}) + +`At` can be used to focus in `A` at a given index `I` for a given structure `S`. + +```kotlin +@optics data class Db(val content: Map) { + companion object +} +``` + +Here we focus into the value of a given key in `MapK`. + +```kotlin:ank +import arrow.optics.typeclasses.At + +val db = Db(mapOf( + 1 to "one", + 2 to "two", + 3 to "three" +)) + +Db.content.at(At.map(), 2).some.modify(db, String::reversed) +``` + +If you are in the scope of `At`, you don't need to specify the instance. + +```kotlin:ank +At.map().run { + Db.content.at(2).some.modify(db, String::reversed) +} +``` + +### [Index]({{ '/optics/index' | relative_url }}) + +`Index` can be used to operate on a structure `S` that can index `A` by an index `I` (i.e., a `List` by its index position or a `Map` by its keys `K`). + + +```kotlin:ank +import arrow.optics.typeclasses.Index + +val updatedJohn = Employees.employees.index(Index.list(), 0).company.address.street.name.modify(employees, String::capitalize) +updatedJohn +``` + +In the scope of `Index`, you don't need to specify the instance, so we can enable `operator fun get` syntax. + +```kotlin:ank +Index.list().run { + Employees.employees[0].company.address.street.name.getOrNull(updatedJohn) +} +``` + +Since [Index]({{ '/optics/index' | relative_url }}) returns an [Optional]({{ '/optics/optional' | relative_url }}), `index` and `[]` are safe operations. + +```kotlin:ank +Index.list().run { + Employees.employees[2].company.address.street.name.getOrNull(employees) +} +``` diff --git a/arrow-site/docs/docs/dsl/README.md b/arrow-site/docs/docs/dsl/README.md index 7b1b7cd93e4..e6684c40599 100644 --- a/arrow-site/docs/docs/dsl/README.md +++ b/arrow-site/docs/docs/dsl/README.md @@ -27,7 +27,7 @@ package com.example.domain } ``` -The DSL will be generated in the same package as your `data class`, and can be used on the `Companion` of your class. +The DSL will be generated in the same package as your `data class`, and can be used on the `Companion` of your class. In most cases those optics will be [lenses]({{ '/optics/lens' | relative_url }}), which allow both focus and modification, as shown in the next snippet. ```kotlin import arrow.optics.dsl.* @@ -40,7 +40,7 @@ val optional: Optional = Employee.company.address.street.name optional.modify(john, String::toUpperCase) ``` -Arrow can also generate DSL for a `sealed class`, which can help reduce boilerplate code, or improve readability. +Arrow can also generate DSL for a `sealed class`, which can help reduce boilerplate code, or improve readability. In that case we speak of [optionals]({{ '/optics/optional' | relative_url }}), which allow dealing with possibly-missing data, and [prisms]({{ '/optics/prism' | relative_url }}), which provide construction. ```kotlin package com.example.domain @@ -78,91 +78,4 @@ We can rewrite this code with our generated DSL. NetworkResult.networkError.httpError.message.modify(networkResult, f) ``` -The DSL also has special support for [Every]({{ '/optics/every' | relative_url }}), [At]({{ '/optics/at' | relative_url }}), [Index]({{ '/optics/index' | relative_url }}), etc. - -### Every - -`Every` can be used to focus into a structure `S` and see all its foci `A`. Here, we focus into all `Employee`s in the `Employees`. - -```kotlin -@optics data class Employees(val employees: List) { - companion object -} -``` - -```kotlin -import arrow.optics.Every - -val jane = Employee("Jane Doe", Company("Kategory", Address("Functional city", Street(42, "lambda street")))) -val employees = Employees(listOf(john, jane)) - -Employees.employees.every(Every.list()).company.address.street.name.modify(employees, String::capitalize) -``` - -If you are in the scope of `Each`, you don't need to specify the instance. - -```kotlin -Every.list().run { - Employees.employees.every.company.address.street.name.modify(employees, String::capitalize) -} -``` - -### At - -`At` can be used to focus in `A` at a given index `I` for a given structure `S`. - -```kotlin -@optics data class Db(val content: Map) { - companion object -} -``` - -Here we focus into the value of a given key in `MapK`. - -```kotlin -import arrow.optics.typeclasses.At - -val db = Db(mapOf( - 1 to "one", - 2 to "two", - 3 to "three" -)) - -Db.content.at(At.map(), 2).some.modify(db, String::reversed) -``` - -If you are in the scope of `At`, you don't need to specify the instance. - -```kotlin -At.map().run { - Db.content.at(2).some.modify(db, String::reversed) -} -``` - -### Index - -`Index` can be used to operate on a structure `S` that can index `A` by an index `I` (i.e., a `List` by its index position or a `Map` by its keys `K`). - - -```kotlin -import arrow.optics.typeclasses.Index - -val updatedJohn = Employees.employees.index(Index.list(), 0).company.address.street.name.modify(employees, String::capitalize) -updatedJohn -``` - -In the scope of `Index`, you don't need to specify the instance, so we can enable `operator fun get` syntax. - -```kotlin -Index.list().run { - Employees.employees[0].company.address.street.name.getOrNull(updatedJohn) -} -``` - -Since [Index]({{ '/optics/index' | relative_url }}) returns an [Optional]({{ '/optics/optional' | relative_url }}), `index` and `[]` are safe operations. - -```kotlin -Index.list().run { - Employees.employees[2].company.address.street.name.getOrNull(employees) -} -``` +There are more kinds of optics, you can read about them in the sidebar to the left. In particular, handling containers of data (lists, collections) becomes easier when using the [optics for collections]({{ '/optics/collections_dsl/' | relative_url }}). \ No newline at end of file diff --git a/arrow-site/docs/docs/optics/README.md b/arrow-site/docs/docs/optics/README.md index d20dc745048..77fdd294ff1 100644 --- a/arrow-site/docs/docs/optics/README.md +++ b/arrow-site/docs/docs/optics/README.md @@ -20,10 +20,20 @@ permalink: /optics/ Arrow Optics provides an automatic DSL that allows users to use `.` notation when accessing, composing, and transforming deeply nested immutable data structures. - Optics also offers all the base types such as [Lens]({{ "/optics/lens/" | relative_url }}), [Prism]( {{ '/optics/prism/' | relative_url }}), and others from which we can generalize accessing and -traversing deep values in sealed and data classes models.s +traversing deep values in sealed and data classes models. + +```kotlin +// an immutable value with very nested components +val john = Employee("John Doe", Company("Kategory", Address("Functional city", Street(42, "lambda street")))) +// an Optional points to one place in the value +val optional: Optional = Employee.company.address.street.name +// and now you can modify into a new copy without nested 'copy's! +optional.modify(john, String::toUpperCase) +``` + +Scroll down and learn what Arrow Optics can do for you(r code)!
@@ -33,37 +43,48 @@ traversing deep values in sealed and data classes models.s
#### Quick Start - - [Gradle Setup]({{ '/optics/#Gradle-kotlin' | relative_url }}) - - [Maven Setup]({{ '/optics/#Maven' | relative_url }}) + - [Gradle Setup]({{ '/optics/#setup' | relative_url }}) + - [Optics DSL]({{ '/optics/dsl/' | relative_url }}) + - [Optics DSL for Collections]({{ '/optics/collections_dsl/' | relative_url }})
-#### DSL - - [Optics DSL]({{ '/optics/dsl/' | relative_url }}) +#### Additional information +- [Kotlin Data classes](https://kotlinlang.org/docs/data-classes.html) +- [Kotlin Sealed classes](https://kotlinlang.org/docs/sealed-classes.html)
-#### Extensions and data types - - [Iso]({{ '/optics/iso/' | relative_url }}) - - [Lens]({{ '/optics/lens/' | relative_url }}) - - [Optional]({{ '/optics/optional/' | relative_url }}) - - [Prism]({{ '/optics/prims/' | relative_url }}) - - [Getter]({{ '/optics/getter/' | relative_url }}) - - [Setter]({{ '/optics/setter/' | relative_url }}) - - [Fold]({{ '/optics/fold/' | relative_url }}) - - [Traversal]({{ '/optics/traversal/' | relative_url }}) - - [Every]({{ '/optics/every/' | relative_url }}) - - [Cons]({{ '/optics/cons/' | relative_url }}) - - [Snoc]({{ '/optics/snoc/' | relative_url }}) - - [At]({{ '/optics/at/' | relative_url }}) - - [Index]({{ '/optics/index/' | relative_url }}) - - [FilterIndex]({{ '/optics/filterindex/' | relative_url }}) +#### [Optics DSL for Values]({{ '/optics/dsl/' | relative_url }}) + +###### Focus and modification + + - [Iso]({{ '/optics/iso/' | relative_url }}): 1-to-1 relations + - [Lens]({{ '/optics/lens/' | relative_url }}): focus and modify one value + - [Optional]({{ '/optics/optional/' | relative_url }}): optional value + +###### Single behavior + + - [Getter]({{ '/optics/getter/' | relative_url }}): focus on one value + - [Prism]({{ '/optics/prism/' | relative_url }}): focus on optional value + - [Setter]({{ '/optics/setter/' | relative_url }}): modify one value +
-#### Additional information - - [Kotlin Data classes](https://kotlinlang.org/docs/data-classes.html) - - [Kotlin Sealed classes](https://kotlinlang.org/docs/sealed-classes.html) +#### [Optics DSL for Collections]({{ '/optics/collections_dsl/' | relative_url }}) + +- [Every]({{ '/optics/every/' | relative_url }}): focus and modification +- [Fold]({{ '/optics/fold/' | relative_url }}): only focus +- [Traversal]({{ '/optics/traversal/' | relative_url }}): only modification + +###### Point to elements + +- [Cons]({{ '/optics/cons/' | relative_url }}) +- [Snoc]({{ '/optics/snoc/' | relative_url }}) +- [At]({{ '/optics/at/' | relative_url }}) +- [Index]({{ '/optics/index/' | relative_url }}) +- [FilterIndex]({{ '/optics/filterindex/' | relative_url }})