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

Re-organize Optics docs #2583

Merged
merged 5 commits into from Dec 23, 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
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