Update: Improved ChainLink
pretty-printing, to give a better idea what it does:
julia> demo" --(f; it[1]+it[2]; g(_,1)) "
--(f; #=expr_of_it=#; g(#==#))
Although a ChainLink
object stores and runs a lambda (this minimizes compile time, compared with composition), I set a tuple in its type parameterization to give a basic description of the sequence of methods it calls.
julia> demo" --(f; it[1]+it[2]; g(_,1)) " |> typeof
ChainLink{var"#135#136", (:f, Symbol("#=expr_of_it=#"), Symbol("g(#==#)"))}
Of course, expressions of it
can take more arbitrary behavior than simple method calls. Best practice would dictate calling named methods whenever possible (i.e., keeping expressions of it
as simple and sparse as possible, trying to use them only for minor adjustments to prepare an object for the next method in the chain), so that the ChainLink
’s descriptor would be most informative.
Using the baby example from comment #3:
julia> demo" --(pick_up; @assert(it.head > it.legs); put(_.butt, arm); rock) "
--(pick_up; #=expr_of_it=#; put(#==#); rock)
Creating a ChainLink
out of the Chain.jl readme example:
julia> demo"""
--begin
dropmissing
filter(:id => >(6), _)
groupby(_, :group)
combine(_, :age => sum)
end"""
--(dropmissing; filter(#==#); groupby(#==#); combine(#==#))
EDIT:
I made it so now the pretty-print shows exactly how the ChainLink
is constructed. (Is this a good idea or no? ):
julia> demo" --(f; it[1]+it[2]; g(_,1)) "
--(f; it[1] + it[2]; g(_, 1))
julia> demo" --(f; it[1]+it[2]; g(_,1)) " |> typeof
ChainLink{var"#175#176", (:f, Symbol("it[1] + it[2]"), Symbol("g(_, 1)"))}
julia> demo" --(pick_up; (@assert it.head > it.legs; it); put(_.butt, arm); rock(_, 2)) "
--(pick_up; begin
#= none:1 =# @assert it.head > it.legs
#= none:1 =#
it
end; put(Fix2(getproperty, :butt), arm); rock(_, 2))
julia> demo"""--begin
dropmissing
filter(:id => >(6), _)
groupby(_, :group)
combine(_, :age => sum)
end"""
--(dropmissing; filter(:id => (>)(6), _); groupby(_, :group); combine(_, :age => sum))