ocular/optics
Common optics for Gleam standard library types.
This module provides pre-built optics for working with:
- Dict (by key)
- List (by index)
- Option (unwrapping)
- Tuple (first, second, etc.)
- Records (field lenses)
Values
pub fn dict_key(
key: k,
) -> types.Optional(dict.Dict(k, v), dict.Dict(k, v), v, v)
An optional that focuses on a specific key in a dictionary.
Returns Ok(value) if the key exists, Error(Nil) otherwise.
Example
let d = dict.from_list([#("name", "Alice"), #("age", "30")])
let name_opt = dict_key("name")
ocular.get_opt(d, name_opt) // Ok("Alice")
ocular.set_opt(d, name_opt, "Bob") // dict with "name" -> "Bob"
pub fn dict_key_with_default(
key: k,
default: v,
) -> types.Lens(dict.Dict(k, v), dict.Dict(k, v), v, v)
An optional that focuses on a key, with a default value if missing.
Unlike dict_key, this always “succeeds” for gets (returns the value or default).
Example
let d = dict.from_list([#("name", "Alice")])
let name_lens = dict_key_with_default("name", "Unknown")
let age_lens = dict_key_with_default("age", "0")
ocular.get(d, name_lens) // "Alice"
ocular.get(d, age_lens) // "0"
ocular.set(d, age_lens, "30") // dict with "name" -> "Alice", "age" -> "30"
pub fn error() -> types.Prism(Result(a, e), Result(a, f), e, f)
A prism that focuses on the Error variant of a Result.
Example
let x: Result(Nil, String) = Error("failure")
ocular.preview(x, error()) // Ok("failure") // Notice how the focus shifts to the error value!
ocular.review(error(), "failure") // Error("failure")
pub fn first() -> types.Lens(#(a, b), #(c, b), a, c)
A lens that focuses on the first element of a 2-tuple.
Example
let pair = #("hello", 42)
ocular.get(pair, first()) // "hello"
ocular.set(pair, first(), "world") // #("world", 42)
pub fn first3() -> types.Lens(#(a, b, c), #(d, b, c), a, d)
A lens that focuses on the first element of a 3-tuple.
pub fn id() -> types.Lens(a, b, a, b)
The identity lens. Focuses on the whole structure.
This is the neutral element for lens composition:
id |> compose.lens(other)=otherother |> compose.lens(id)=other
Example
let x = "hello"
ocular.get(x, id()) // "hello"
ocular.set(x, id(), "world") // "world"
ocular.modify(x, id(), string.uppercase) // "HELLO"
pub fn list_head(
default: a,
) -> types.Lens(List(a), List(a), a, a)
A lens that focuses on the first element of a list. Returns the default value if the list is empty.
Example
let items = ["a", "b", "c"]
let head = list_head("default")
ocular.get(items, head) // "a"
ocular.get([], head) // "default"
ocular.set(items, head, "A") // ["A", "b", "c"]
pub fn list_index(
index: Int,
) -> types.Optional(List(a), List(a), a, a)
An optional that focuses on a specific index in a list.
Returns Ok(value) if the index is valid, Error(Nil) otherwise.
Example
let items = ["a", "b", "c"]
let second = list_index(1)
ocular.get_opt(items, second) // Ok("b")
ocular.set_opt(items, second, "B") // ["a", "B", "c"]
pub fn list_tail() -> types.Lens(
List(a),
List(a),
List(a),
List(a),
)
A lens that focuses on the tail of a list (everything after the first element).
Example
let items = ["a", "b", "c"]
let tail = list_tail()
ocular.get(items, tail) // ["b", "c"]
ocular.set(items, tail, ["x"]) // ["a", "x"]
pub fn list_traversal() -> types.Traversal(List(a), List(b), a, b)
A traversal that focuses on all elements of a list.
Example
let items = [1, 2, 3]
let all = list_traversal()
ocular.get_all(items, all) // [1, 2, 3]
ocular.modify_all(items, all, fn(x) { x * 2 }) // [2, 4, 6]
pub fn none() -> types.Prism(
option.Option(a),
option.Option(a),
Nil,
Nil,
)
A prism that focuses on the None variant of an Option.
This is mostly useful for checking if something is None or constructing None.
Example
let x: Maybe(String) = None
ocular.preview(x, none()) // Ok(Nil)
let y: Maybe(String) = Some("hello")
ocular.preview(y, none()) // Error(Nil)
ocular.review(none(), Nil) // None
pub fn ok() -> types.Prism(Result(a, e), Result(b, e), a, b)
A prism that focuses on the Ok variant of a Result.
Example
let x: Result(String, Nil) = Ok("success")
ocular.preview(x, ok()) // Ok("success")
ocular.review(ok(), "success") // Ok("success")
pub fn second() -> types.Lens(#(a, b), #(a, c), b, c)
A lens that focuses on the second element of a 2-tuple.
Example
let pair = #("hello", 42)
ocular.get(pair, second()) // 42
ocular.set(pair, second(), 100) // #("hello", 100)
pub fn second3() -> types.Lens(#(a, b, c), #(a, d, c), b, d)
A lens that focuses on the second element of a 3-tuple.
pub fn some() -> types.Prism(
option.Option(a),
option.Option(b),
a,
b,
)
A prism that focuses on the Some variant of an Option.
Example
let x: Maybe(String) = Some("hello")
ocular.preview(some_prism(), x) // Ok("hello")
let y: Maybe(String) = None
ocular.preview(some_prism(), y) // Error(Nil)
ocular.review(some_prism(), "world") // Some("world")
pub fn some_with_default(
default: a,
) -> types.Lens(option.Option(a), option.Option(a), a, a)
An optional that unwraps an Option, with a default for the “get” operation.
Unlike some_prism, this returns the default when getting from None.
Example
let opt_str = some_with_default("default")
ocular.get(Some("hello"), opt_str) // "hello"
ocular.get(None, opt_str) // "default"
ocular.set(None, opt_str, "new") // Some("new")
pub fn third3() -> types.Lens(#(a, b, c), #(a, b, d), c, d)
A lens that focuses on the third element of a 3-tuple.