Functional version of Base library

Is there a functional version of the Base library?
is it possible to do this?

x = rand(10, 10)
r_x = x |> 
            reshape((1, length(x))) |> # convert x to a 1xlength(x) Matrix 
            r |> # apply r
            reshape(size(x)) # converto to original size 

instead of this:

x = rand(10, 10)
r_x = reshape(reshape(x, (1, length(x))) |> r, size(x))   # convert to a 1xlength(x) Matrix, apply r, convert to original size

Thank you.

With a little bit more typing:

r_x = x |> reshape((1, length(x)))

works with:

x |> x -> reshape(x,(1,length(x)))
1 Like

Thank you.
Does multiple dispatch allow you to do this?

Base.reshape(dim::Tuple) = x -> Base.reshape(x, dim)

Is there a reason why this is not present in the library Base?
It’s a bad practice?

I think it would be useful to have functional versions of the Base library functions.

This is possible, and in several cases (e.g. ==) we already do this. However, in a multi-argument function it’s often not clear what argument you would want to “functionalize” (i.e. “curry”).

If x -> is too verbose, it would be better to have a syntax for this (e.g. RFC: curry underscore arguments to create anonymous functions by stevengj · Pull Request #24990 · JuliaLang/julia · GitHub), but we’ve had a hard time agreeing on the details.

5 Likes

You might like one of several packages implementing ideas like this. Chain.jl has a good summary of the options:

1 Like

BTW, you can make this more simple

reshape(x, 1, :)  # or reshape(x, (1, :))
1 Like

Thanks to everyone.

I think functions like reshape, map, filter, reduce, + operator, etc, can be made functional without ambiguity.

Is this code good or there are bad practices?

Base.reshape(dim::Tuple) = x -> Base.reshape(x, dim)    # if the function takes the dimension
Base.reshape(array) = x -> Base.reshape(array, x)       # if the function takes the array

Thank you, but I don’t like custom solutions with macros and I don’t want that who reads my code must know too many libraries.


Thank you, but I don’t like a reshape inside another reshape. I would like to use a more elegant style with pipe operator.


Sorry for my english.

1 Like

You might think so, but see e.g. Deprecate/remove map(f) and foreach(f) · Issue #35293 · JuliaLang/julia · GitHub. + is also a good example to illustrate the problem, since we do have a unary + already (as in +(42)) in symmetry with unary -, so we can’t add a curried version.

1 Like

This is type piracy and should generally be avoided. The latter also has a meaning already:

julia> reshape([1])
0-dimensional Array{Int64,0}:
1
1 Like

An alternative, if you don’t like the nested reshapes but need to repeat this pattern several times, is to stick it into a function – so that at least your code has it only once. I think this is quite readable:

apply_reshaped(f, x, shape) = reshape(f(reshape(x, shape)), size(x))

apply_reshaped(r, x, (1, :))
1 Like

Thanks for the answers, I found out a lot of new things I didn’t know.
Before asking this question I thought that a more functional style was more elegant and less prone to errors.
Now I find out that there are several problems with this functional approach.
At this point I’m wondering: how popular is the pipe operator?
Does it make sense to have a more functional style?
Sorry for my English, I’m using an automatic translator.

1 Like

No, I’m not trying to convince you to use reshape for this purpose. I’m saying that if you use reshape for anything, you can use : instead of length(x). It is more elegant.

1 Like