# Is there a package to that can make partial functions automatically?

**URL:** <https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292>\
**Category:** General Usage\
**Created:** [November 20, 2019, 2:18am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292 "2019-11-20T02:18:08Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 20, 2019, 2:18am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/1 "2019-11-20T02:18:08Z")

</div>

I have a function say `savejdf`

```julia
savejdf(df::AbstractDataFrame, path::AbstractString)

```

and I would like to create all possible partial functions e.g.

```julia
savejdf(df::AbstractDataFrame) = path -> savejdf(df, path)
savejdf(path::AbstractString) = df -> savejdf(df, path)

```

and obviously would be nice if this generalises to `n`-argument functions.

Is there a macro a package that does that? I like how Haskell does it for you automatically.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 20, 2019, 2:21am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/2 "2019-11-20T02:21:22Z")

</div>

Here’s a solution I worked out a while ago:

```julia
struct FullyCurried end

macro curried(fdef)
    f = fdef.args[1].args[1]
    fargs = fdef.args[1].args[2:end]
    arity = length(fargs)
    body = fdef.args[2]
    err_str = "Too many arguments. Function $f only takes $arity arguments"
    quote 
        begin 
            function $f(args...)
                if length(args) < $arity
                    x -> $f((args..., x)...)
                elseif length(args) == $arity
                    $f(FullyCurried(), args...)
                else
                    throw($err_str)
                end
            end
            $f(::FullyCurried, $(fargs...)) = $body
        end
    end |> esc
end

```

```julia
julia> @curried foo(x, y, z) = (x^2 + y^2)/(x^2 + y^2 +z^2)
foo (generic function with 2 methods)

julia> foo(1)(2)(3)
0.35714285714285715

julia> foo(1, 2, 3)
0.35714285714285715

```

The main thing I like is that instead of a call-site macroinvocation like `@curry f(1)(2)(3)`, the macro instead lives at the function definition site.

I suppose this could go in a tiny package.

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 20, 2019, 2:40am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/3 "2019-11-20T02:40:36Z")

</div>

Yeah. Can we call it PartialCurry.jl?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 20, 2019, 2:40am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/4 "2019-11-20T02:40:54Z")

</div>

I was thinking Currier.jl 😃

[https://github.com/MasonProtter/Currier.jl](https://github.com/MasonProtter/Currier.jl)

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 20, 2019, 2:49am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/6 "2019-11-20T02:49:45Z")

</div>

But partial functions are not the same as currying?

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 20, 2019, 2:50am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/7 "2019-11-20T02:50:38Z")

</div>

Is Currier.jl by position only?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 20, 2019, 2:57am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/8 "2019-11-20T02:57:52Z")

</div>

Oh, my mistake, I thought you just wanted currying. I beleive what you want requires a callsite annotation in general (unless this PR somehow gets merged [https://github.com/JuliaLang/julia/pull/24990](https://github.com/JuliaLang/julia/pull/24990)). Here’s a package that does it somewhat nicely:

[https://github.com/c42f/MagicUnderscores.jl](https://github.com/c42f/MagicUnderscores.jl)

```julia
julia> using MagicUnderscores

julia> @_ [1,2,3,4] |> filter(_>2, _)
2-element Array{Int64,1}:
 3
 4

julia> @_ [1,2,3,4] |> filter(_>2, _) |> length
2

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [November 20, 2019, 3:25am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/9 "2019-11-20T03:25:24Z")

</div>

Neat!

I often want to curry in this direction though, maybe `@rcurried` or something 😛

```julia
foo(1)(2)(3) == foo(3, 2, 1)

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 20, 2019, 3:38am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/10 "2019-11-20T03:38:56Z")

</div>

Done!

```julia
julia> @reverse_curried bar(x, y, z) = (x, y, z)
bar (generic function with 2 methods)

julia> bar(1)(2)(3)
(3, 2, 1)

julia> bar(3, 2, 1)
(3, 2, 1)

```

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [November 20, 2019, 3:40am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/11 "2019-11-20T03:40:50Z")

</div>

Sweet!

---

<div class="post-metadata">

**Author:** ![Orbots](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/orbots/32/3392_2.png) [@Orbots](https://discourse.julialang.org/u/Orbots)\
**Post date:** [November 22, 2019, 1:18am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/12 "2019-11-22T01:18:21Z")

</div>

I also made a Curry.jl using generated functions.

[https://github.com/Orbots/Curry.jl](https://github.com/Orbots/Curry.jl)

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 22, 2019, 1:30am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/13 "2019-11-22T01:30:00Z")

</div>

Love that 🍛 is an export function!

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 22, 2019, 1:35am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/14 "2019-11-22T01:35:12Z")

</div>

Thanks. But all libraries seem to work with positions only. I want an auto-partial function creator that drops Typed arguments that it can match. See the original example.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [November 22, 2019, 2:22am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/15 "2019-11-22T02:22:34Z")

</div>

I didn’t know I wanted that but I do now. Sound you want a macro that defines `@generated` functions.

```julia
@partials function f(a::String, b::Int, c::Dict) 

```

And the `partials` macro outputs something like:

```julia
@generated f(a::Type{A}) where A = begin
    pos = if A <: String
        1
    else if A <: Int
        2
    else if A <: Dict
        3
    end
     ... # write the expression for the anonymous func with `pos` argument filled in with `a`
end
@generated f(a::Type{A}, b::Type{B}) where {A, B} = begin
    # as above for both A and B parameters
end
# and so on...

```

In the macro you could loop over the arguments to `f` and define @generated function for 1 argument, 2 arguments, 3 arguments etc partial functions. The `@generated` function would deal with the arbitrary argument types.

Edit: or just define all the method permutations in the macro manually without `@generated`

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [November 22, 2019, 3:05am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/16 "2019-11-22T03:05:37Z")

</div>

Are you able to make that into a pacakge? I am noob at meta-programming but I would have a crack later on.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [November 22, 2019, 3:29am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/17 "2019-11-22T03:29:45Z")

</div>

Capable or able!?? A few of my packages do worse things… but the 10 or so currently unfinished ones say I am not “able” to, lol.

You will be surprised how easy it is, that could be a third of the code already. It should be a sub 100 lines package. You probably can just use `for` loops to push the right expressions to the right positions in vectors of expressions for the function arguments. It will take you a while to get used to code as data, but once you do it’s fairly simple - except correctly escaping user inputs, that’s always confusing.

Edit: seriously just jump in, Mixers.jl, FieldMetadata.jl and Flatten.jl are all from my first year of julia, for better or worse! but they definitely have a lot of “clever” metaprogramming, like nested macros and recursive `@generated` functions…

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [November 22, 2019, 4:53am UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/18 "2019-11-22T04:53:26Z")

</div>

i have some (horrible) lines of code that can do this:

```julia
_getsig(f::Function) = map(b -> b.sig, methods(f).ms)
function _argTypes(f::Function)
    filtered = filter(x -> !(x isa UnionAll) && !(Any in x.parameters), getsig(f))
    return map(x -> x.parameters[2:end], filtered)
end

function _select_args(args,other_args,pos,n)
other_arg_count = 1
pos_count = 1
max_pos = length(pos)
max_other = length(other_args)
counter = 1
final_args = Any[]
    while counter<=n
        if (pos[pos_count] == counter) 
            push!(final_args,args[pos_count])
            pos_count < max_pos && (pos_count+=1)        
        else
            push!(final_args,other_args[other_arg_count])
            other_arg_count < max_other && (other_arg_count+=1)
        end
        counter +=1
    end
    return final_args
end

#just works with unique types
function partial_application(f,args...)
    f_typelist = _argTypes(f)[1]
    
    f_name = Symbol(f)
    total_args_length = length(f_typelist)
    arg_typelist = (typeof(i) for i in args)
    if !allunique(f_typelist)
        throw("the arguments of $f_name are not of unique types!")
    elseif !allunique(arg_typelist)
        throw("the input arguments are not of unique types!")
    end
    total_args_length
    if length(args) < total_args_length
        pos = findall(i-> any(j -> <:(i,j),arg_typelist),f_typelist)
        function partial_f(other_args...) 
            return f(_select_args(args,other_args,pos,total_args_length)...)
        end  
        return partial_f
    else 
        return f(args...)
    end
end

macro partials(arg)
    fname = arg.args[1]
    arguments = arg.args[2:end]
    quote
        partial_application($fname,$arguments...)
    end
end

```

the usage is the following:

```julia
fn(a::Float64,b::Vector{Float64},c::Int) = c*a*b
f = @partials fn(b)
f(a,c) # fn(a,b,c)

f = @partials fn(c,a)
f(b) 

```

is the worst way possible, but is flexible, accepts n arguments in any order, but you have to define all types in your function

---

<div class="post-metadata">

**Author:** ![overshiki](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/overshiki/32/43161_2.png) [@overshiki](https://discourse.julialang.org/u/overshiki)\
**Post date:** [October 17, 2022, 1:45pm UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/19 "2022-10-17T13:45:12Z")

</div>

Just found this excellent package: [GitHub - archermarx/PartialFunctions.jl: A small package to simplify partial function application](https://github.com/archermarx/PartialFunctions.jl)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 17, 2022, 8:58pm UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/21 "2022-10-17T20:58:39Z")

</div>

> [@longemen3000](#):
>
> `f = @partials fn(b)`

Why not `(a,c) -> f(a,b,c)`?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 17, 2022, 8:59pm UTC](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292/22 "2022-10-17T20:59:28Z")

</div>

There is also [Underscores.jl](https://github.com/c42f/Underscores.jl), where you can do `@_ f(_1,b,_2)`.

[Next page](https://discourse.julialang.org/t/is-there-a-package-to-that-can-make-partial-functions-automatically/31292.md?page=2)
