Skip to content

Commit

Permalink
Re-organize Optics docs (#2583)
Browse files Browse the repository at this point in the history
  • Loading branch information
serras committed Dec 23, 2021
1 parent a08a8dc commit bea8b51
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 118 deletions.
15 changes: 11 additions & 4 deletions arrow-site/docs/_data/sidebar-optics.yml
Expand Up @@ -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/

Expand All @@ -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/

Expand Down
96 changes: 96 additions & 0 deletions 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<Employee>) {
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<Employee>()).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<Employee>().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<Int, String>) {
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<Int, String>().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<Employee>` by its index position or a `Map<K, V>` 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<Employee>().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<Employee>().run {
Employees.employees[2].company.address.street.name.getOrNull(employees)
}
```
93 changes: 3 additions & 90 deletions arrow-site/docs/docs/dsl/README.md
Expand Up @@ -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.*
Expand All @@ -40,7 +40,7 @@ val optional: Optional<Employee, String> = 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
Expand Down Expand Up @@ -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<Employee>) {
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<Employee>()).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<Employee>().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<Int, String>) {
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<Int, String>().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<Employee>` by its index position or a `Map<K, V>` 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<Employee>().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<Employee>().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 }}).
69 changes: 45 additions & 24 deletions arrow-site/docs/docs/optics/README.md
Expand Up @@ -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, String> = 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)!
</div>

<div class="quickstart-intro" markdown="1">
Expand All @@ -33,37 +43,48 @@ traversing deep values in sealed and data classes models.s

<div class="quickstart-coroutines-item" markdown="1">
#### 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 }})
</div>

<div class="quickstart-coroutines-item" markdown="1">
#### 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)
</div>

<div class="quickstart-coroutines-item" markdown="1">
#### 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

</div>

<div class="quickstart-coroutines-item" markdown="1">
#### 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 }})
</div>
</div>
</div>
Expand Down

0 comments on commit bea8b51

Please sign in to comment.