结论:
julia> @with C().a.a1 = 3
C(A(3, 2), B(A(1, 2), 2), 3)
julia> c = C()
C(A(1, 2), B(A(1, 2), 2), 3)
julia> c = @with c.a.a1 = 3
C(A(3, 2), B(A(1, 2), 2), 3)
julia> c = @with c.a.a2 = 5
C(A(3, 5), B(A(1, 2), 2), 3)
julia> c = @with c.b.a.a2 = 5
C(A(3, 5), B(A(1, 5), 2), 3)
怎么实现的? 思考例子
# a.b.c.d <- v
let cache = a
# cache.c.d <- v
value =
let cache = cache.b,
# cache.d <- v
value =
let cache = cache.c
value = v
value = update(cache, Val(d), v)
end
update(cache, Val(c), value)
end
update(cache, Val(b), value)
end
得到一个33行代码的实现:
using MLStyle
@generated function field_update(main :: T, field::Val{Field}, value) where {T, Field}
fields = fieldnames(T)
quote
$T($([field !== Field ? :(main.$field) : :value for field in fields]...))
end
end
function lens_compile(ex, cache, value)
@when :($a.$(b::Symbol).$(c::Symbol) = $d) = ex begin
updated =
Expr(:let,
Expr(:block, :($cache = $cache.$b), :($value = $d)),
:($field_update($cache, $(Val(c)), $value)))
lens_compile(:($a.$b = $updated), cache, value)
@when :($a.$(b::Symbol) = $c) = ex
Expr(:let,
Expr(:block, :($cache = $a), :($value=$c)),
:($field_update($cache, $(Val(b)), $value)))
@otherwise
error("Malformed update notation $ex, expect the form like 'a.b = c'.")
end
end
function with(ex)
cache = gensym("cache")
value = gensym("value")
lens_compile(ex, cache, value)
end
macro with(ex)
with(ex) |> esc
end
function with(ex)
cache = gensym("cache")
value = gensym("value")
lens_compile(ex, cache, value)
end
macro with(ex)
with(ex) |> esc
end