JuliaData / DataFramesMeta.jl

Metaprogramming tools for DataFrames
https://juliadata.github.io/DataFramesMeta.jl/stable/
Other
480 stars 55 forks source link

Add function composition #299

Open pdeffebach opened 3 years ago

pdeffebach commented 3 years ago

I think that when we see fun1(fun2(x)) the function passed to transform should be fun1 \circ fun2. That way we can take advantage of more fast paths iirc.

bkamins commented 3 years ago

Yes and the thing is that fun1 \circ fun2 is compiled only once as opposed to x -> fun1(fun2(x)) which has to be compiled every time. but I would label it as a minor improvement.

nalimilan commented 3 years ago

Actually I had implemented something like that back in 2019 before you cleaned up the package. FWIW, here are the functions I had written:

"""Check whether expression is a single-argument call, like f(x)"""
isoneargcall(e::Expr) =
    e.head === :call && length(e.args) == 2 && e.args[1] isa Symbol

function tocomposition(body)
    if body.head == :(=) && length(body.args) == 2 &&
        body.args[2] isa Expr
        funs = Symbol[]
        e = body.args[2]
        while e isa Expr && isoneargcall(e)
            push!(funs, e.args[1])
            e = e.args[2]
        end
        if e isa Symbol || (e isa QuoteNode && e.value isa Symbol)
            # Recursion parsed the full expression
            return mapreduce(eval, ∘, funs)
        else # Expression doesn't consist only in single-argument calls
            return body
        end
    end
    return body
end