Julia 中的透镜
Lenses in Julia

原始链接: https://juliaobjects.github.io/Accessors.jl/stable/lenses/

## Accessors.jl: 处理嵌套数据 Accessors.jl 引入了 **透镜** —— 一种强大的机制,用于访问和修改复杂对象中深度嵌套的数据,而无需直接改变原始数据。透镜允许你“聚焦”到对象的特定部分进行读取或更新。 你可以使用 `@optic` 宏定义透镜,或使用 `opcompose` 等函数直接构造它们。透镜应用于对象以检索值,或使用 `set` 函数创建具有指定修改的 *新* 对象。`modify` 函数在更新之前将函数应用于焦点值。 至关重要的是,透镜遵循三个 **透镜定律**,确保可预测的行为:设置值然后获取它会返回该值,设置现有值不会改变对象,并且最后的设置操作优先。实现透镜需要定义 `Accessors.set` 和透镜应用函数,两者都必须是纯函数。 这种方法促进了函数式编程原则,并简化了对复杂数据结构的处理。

相关文章

原文

Accessors.jl is build around so called lenses. A Lens allows to access or replace deeply nested parts of complicated objects.

julia> using Accessors

julia> struct T;a;b; end

julia> obj = T("AA", "BB");

julia> lens = @optic _.a
(@o _.a)

julia> lens(obj)
"AA"

julia> set(obj, lens, 2)
T(2, "BB")

julia> obj # the object was not mutated, instead an updated copy was created
T("AA", "BB")

julia> modify(lowercase, obj, lens)
T("aa", "BB")

Lenses can also be constructed directly and composed with opcompose, , or (note reverse order).

julia> using Accessors

julia> v = (a = 1:3, )
(a = 1:3,)

julia> l = opcompose(PropertyLens(:a), IndexLens(1))
(@o _.a[1])

julia> l ≡ @optic _.a[1]   # equivalent to macro form
true

julia> l(v)
1

julia> set(v, l, 3)
(a = [3, 2, 3],)

Implementing lenses is straight forward. They can be of any type and just need to implement the following interface:

  • Accessors.set(obj, lens, val)
  • lens(obj)

These must be pure functions, that satisfy the three lens laws:

@assert lens(set(obj, lens, val)) ≅ val
        # You get what you set.
@assert set(obj, lens, lens(obj)) ≅ obj
        # Setting what was already there changes nothing.
@assert set(set(obj, lens, val1), lens, val2) ≅ set(obj, lens, val2)
        # The last set wins.

Here is an appropriate notion of equality or an approximation of it. In most contexts this is simply ==. But in some contexts it might be ===, , isequal or something else instead. For instance == does not work in Float64 context, because get(set(obj, lens, NaN), lens) == NaN can never hold. Instead isequal or ≅(x::Float64, y::Float64) = isequal(x,y) | x ≈ y are possible alternatives.

See also @optic, set, modify.

联系我们 contact @ memedata.com