Is partial function application in Erlang a good idea?

:woman_shrugging:

Guess I’ll leave that to @Gwaeron, if he likes :sweat_smile:

1 Like

I love this idea! It reminds me of scala’s usage of _ for ignored params.
It working well with a future pipe operator alone in my opinion justifies its existence.

Here’s a random scala snippet I tried to translate to idiomatic erlang, with my understanding of this proposal implemented:

val items = Seq(("candy", 2, true), ("cola", 7, false), ("apple", 3, false), ("milk", 4, true))
val itemsToBuy = items
  .filter(_._3)     // filter in only available items (true)
  .filter(_._2 > 3) // filter in only items with price greater than 3
  .map(_._1)        // return only the first element of the tuple; the item name
assertEquals(itemsToBuy, Seq("milk"))
Items      = [{candy, 2, true}, {cola, 7, false}, {apple, 3, false}, {milk, 4, true}],
ItemsToBuy = lists:filter(element(3, _)    , Items)
          |> lists:filter(element(2, _) > 3, _    )
          |> lists:   map(element(1, _)    , _    ).

This probably begs the question that if Items were a list of lists, should lists:filter(_._3, Items) be valid with _._N being an alias for lists:nth(N, _)
Though I’m not particularly interested in answering that question.

2 Likes

Yeah, that usage is pretty much what I had in mind, except the second filter which compares a fun element(2, _) to an integer 3 and would crash since there’s no function clause matching lists:filter(bool(), [any()]).
Though I think each of those filter functions could be replaced by a list comprehension for easier reading, this demonstrates how the fun-ifying with missing elements can be useful for piping.

I haven’t responded here in a while due to being busy, but I intend to try to rewrite some non-toy examples in OTP modules that I think will demonstrate, as requested, how this could be used to generate cleaner code, and then maybe send it to the mailing list if there is some interest.

3 Likes

except the second filter which compares a fun element(2, _) to an integer 3 and would crash since there’s no function clause matching lists:filter(bool(), [any()]).

Oh right… would surrounding the expression in parentheses like (element(2, _) > 3) signify to be interpreted as fun(Elem) -> element(2, Elem) > 3 or would that not be possible at this point?

1 Like

In a prototype I made using parse transforms, operators were supported _ > 3, but I didn’t add any way to change the scope of the placeholder _ to a surrounding expression.

With the suggestion made above to keep the fun keyword I guess it could be possible to control the scope of the placeholder, something like fun (element(2, _) > 3) but I don’t think that looks like Erlang any more, a normal fun would be better. I wouldn’t be surprised if there are also other implications I didn’t consider yet that would make this use inconsistent.

3 Likes

It has been quite fun to read this thread as Gleam has precisely this syntax for partial function application :grin:

4 Likes

What became of this project? @Gwaeron?

2 Likes

Sorry for the delay, I’ve been in the middle of a move and didn’t have time to do a write-up yet, but it’s definitely still on the to-do list! Look forward to it Soon™.

4 Likes

Will do :slight_smile:

2 Likes