Julia: non-destructive update of an immutable type variable

Let's say there is a type

immutable Foo
    x :: Int64
    y :: Float64
end

and there is a variable foo = Foo(1,2.0). I want to build a new variable barusing fooas a prototype a field y = 3.0(or, alternatively, without breaking update foo, creating a new object foo). In the languages ​​ML (Haskell, OCaml, F #) and some others (for example, Clojure) there is an idiom that in the pseudo-code will look like

bar = {foo with y = 3.0}

Is there something similar in Julia?

+4
source share
2 answers

. Clojure , , / . , . , Haskell ML, Julia , {foo with y = 1} , .

Clojure - ; , . fieldnames "" (, [:x, :y]), getfield(foo, :x) :

immutable Foo
  x
  y
  z
end

x = Foo(1,2,3)

with_slow(x, p) =
  typeof(x)(((f == p.first ? p.second : getfield(x, f)) for f in fieldnames(x))...)

with_slow(x, ps...) = reduce(with_slow, x, ps)

with_slow(x, :y => 4, :z => 6) == Foo(1,4,6)

, with_slow. - , , withy(foo::Foo, y) = Foo(foo.x, y, foo.z). Foo (, Foo{T} y::T), , withy(foo, 1.) a Foo{Float64}, with_slow. , crab.

, ML co, - , . , !

# Fields

type Field{K} end

Base.convert{K}(::Type{Symbol}, ::Field{K}) = K
Base.convert(::Type{Field}, s::Symbol) = Field{s}()

macro f_str(s)
  :(Field{$(Expr(:quote, symbol(s)))}())
end

typealias FieldPair{F<:Field, T} Pair{F, T}

# Immutable `with`

for nargs = 1:5
  args = [symbol("p$i") for i = 1:nargs]
  @eval with(x, $([:($p::FieldPair) for p = args]...), p::FieldPair) =
      with(with(x, $(args...)), p)
end

@generated function with{F, T}(x, p::Pair{Field{F}, T})
  :($(x.name.primary)($([name == F ? :(p.second) : :(x.$name)
                         for name in fieldnames(x)]...)))
end

- , f"foo", . , , ; Foo , . , Julia , Foo:

@code_typed with(x, f"y" => 4., f"z" => "hello") # => ...::Foo{Int,Float64,String}

( for nargs - , .)

, , , , . , , () , ; API. , , , .

+4

setindex ( ! ), FixedSizeArrays.jl, .

0

Source: https://habr.com/ru/post/1649611/


All Articles