Are there idioms in Julia for fast Algebraic Data Types (ADT)?

Also, there is a technique to alter ADTs, called tagless final.

ADT approach is called initial approach in some context, and tagless final is called the final approach in this scope.

For your code, we can use tagless final, to achieve stably typed Julia program:

struct SYM{F1, F2}
    constant :: F1
    add :: F2
end

function constant(v)
    function (sym::SYM)
        sym.constant(v)
    end
end

function add(term1, term2)
    function (sym::SYM)
        sym.add(term1(sym), term2(sym))
    end
end

# self algebra
self = SYM(constant, add)

evaluate =
    let constant(v::Int) = v,
        add(l::Int, r::Int) = l + r
        SYM(constant, add)
    end


println(add(constant(2), constant(3))(evaluate))
@code_warntype add(constant(2), constant(3))(evaluate)

There’re no red points, try above codes in your Julia shell

5
Variables
  #self#::var"#17#18"{var"#15#16"{Int64},var"#15#16"{Int64}}
  sym::Core.Compiler.Const(SYM{var"#constant#19",var"#add#20"}(var"#constant#19"(), var"#add#20"()), false)

Body::Int64
1 ─ %1 = Base.getproperty(sym, :add)::Core.Compiler.Const(var"#add#20"(), false)
│   %2 = Core.getfield(#self#, :term1)::var"#15#16"{Int64}
│   %3 = (%2)(sym)::Int64
│   %4 = Core.getfield(#self#, :term2)::var"#15#16"{Int64}
│   %5 = (%4)(sym)::Int64
│   %6 = (%1)(%3, %5)::Int64
└──      return %6
6 Likes