Should Elixir functions be curry-able?

Erlang:

This adheres to our general principle that we do not provide built-in mechanisms; we provide primitives with which mechanisms can be built.

Erlang/Elixir: Beyond Functional Programming with Elixir and Erlang

i.e. The BEAM is primarily a Concurrent Programming platform - Functional Programming was adopted for pragmatic reasons - not as an end in itself.

also:

I tend to think of it not so much as a language with concurrency but more of an operating system with a language.


iex(1)> defmodule Demo do
...(1)>  
...(1)>   def make_foldl(acc, fun) do
...(1)>     fn (list) when is_list(list) ->
...(1)>       List.foldl(list, acc, fun)
...(1)>     end
...(1)>   end
...(1)> 
...(1)> end
{:module, Demo,
 <<70, 79, 82, 49, 0, 0, 5, 48, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 190,
   0, 0, 0, 18, 11, 69, 108, 105, 120, 105, 114, 46, 68, 101, 109, 111, 8, 95,
   95, 105, 110, 102, 111, 95, 95, 7, 99, ...>>, {:make_foldl, 2}}
iex(2)> data = Enum.to_list(1..10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
iex(3)> add_list = Demo.make_foldl(0, &Kernel.+/2)
#Function<0.107962701/1 in Demo.make_foldl/2>
iex(4)> result = data |> add_list.()
55
iex(5)> IO.puts("#{inspect(result)}")
55
:ok
iex(6)> 

Partial application can be accomplished with closures and it is partial application that is the workhorse (though it seems that currying had a more effective PR-agent).

Currying is an aesthetic nicety - lack of it may make things a bit more verbose but it is hardly a showstopper.

Also concision is often used as an excuse to forego proper naming. Lambdas/Anonymous functions leave the reader to parse the code to determine what is being done in order to divine why it is being done - when a simple (variable/function) name could effectively and painlessly inform the reader about the why.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. (Martin Fowler, Refactoring)

1 Like