marick

marick

Is `Function.constantly` worth adding?

I confess I don’t use Function.identity because &(&1) comes to mind faster. However, there’s another function that seems commonly used in functional languages, which is a function that makes a function that always returns the same value:

  def constantly(value) do
    fn _ -> value end
  end

Given there’s no shorter version than fn _ -> value end (is there?) would it be worth adding Function.constantly?

Most Liked

OvermindDL1

OvermindDL1

“Other languages” have this function also seem to be the same languages where every function is arity 1 (what you’d think of as an arity 3 function is just an arity 1 that returns a function that is arity 1 that returns a function that is arity 1 that return the result), and no language on the BEAM can work quite like that without a huge amount of preprocessing to ‘pack’ arity’s together if you want to work with the rest of the beam.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

I think this proposal is tricky because, unlike identity/1, there isn’t an obvious arity that your return function should have. Should it be:

fn -> value end
or
fn _ -> value end
or
fn _, _ -> value end
... etc

Each of those has real scenarios where they’d be useful.

The other issue is that these two things do not have the same semantics: Function.constantly(code) and fn -> code end will behave differently depending on what code is. If code is DateTime.utc_now() then Function.constantly will return the same date time over and over, but fn -> DateTime.utc_now() end will return a new datetime each time it is invoked.

al2o3cr

al2o3cr

Nitpick: Function.constantly(value) is also not a shorter version, since it’s literally nine characters longer.

marick

marick

Clojure has a constantly, and it has functions that aren’t just syntactic sugar for arity-1 functions.

dorgan

dorgan

If we take maths as our source of truth(since most constructs of this kind come from there), then I’d argue the arity should be 1, based on notions from lambda calculus.

If we consider the expression λx.λy.x, giving it an x will result in an abstraction that, no matter what y we feed it, it will always return x. The resulting abstraction would be λx.y which is the constant function x↦y. The abstraction that produces such constant functions is the constant combinator K = λx.λy.x.

The identity combinator I is already incarnated in Function.identity, if the K combinator is implemented, we would only need to add the S combinator λfgx.fx(gx):

def substitution(f) do
  fn g ->
    fn x ->
      (f.(x)).(g.(x))
    end
  end
end

And this would complete the three combinators needed for SKI combinator calculus.

The other argument for K’s returned function to have an arity of 1, is that a lot of this work involves giving one argument at a time to partially apply those functions, and it just makes no sense to have more arguments. Having zero arguments also goes against the definition of x↦y.

Another observation is that such constant function is the return value, what’s being proposed is the combinator that produces it. Function.constantly(code) and fn -> code end will behave differently because the former is an invocation to the combinator, and the latter is the produced function. Moreover, if you give a function to Function.constantly/1, then expect the constant function to return the same function, not to evaluate it.


I don’t know what was the motivation behind the addition of Function.identity/1, but I’m not sure if it’s worth it to implement these combinators in elixir itself, or it’s best to leave it for userland code. I think that once you add one you’ll be tempted to add the others, and I don’t know if that’s the goal of the Function module.
I also understand that Elixir is a pragmatic language and academic purity is not it’s goal, but if we are going to implement these abstractions then we need to pick something that’s already been generalized and well understood, otherwise we would end up discussing which arity the function should have considering x, y and z practical examples, and for such cases I believe ad-hoc functions are the best.

Where Next?

Popular in Discussions Top

Jayshua
I recently came across the javascript library htmx. It reminded me a lot of liveview so I thought the community here might be interested....
New
praveenperera
How We Replaced React with Phoenix By: Thought Bot
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
AstonJ
I’ve just started the Phoenix part of the utterly brilliant online course by @pragdave. On generating the Phoenix app he uses the --no-ec...
New
crabonature
I’m still quite new to Elixir. As I understand we got in Elixir “multi guards” as convention to simplify one large guard with or’s?: de...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
opsb
We’re considering our architecture from a viewpoint of scaling our traffic heavily over the next 6 months. Our current deployment is runn...
New
Markusxmr
Since Drab has been developed for a while in the open, introducing the Liveview functionality in a way it happend appears to undermine th...
New

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New

We're in Beta

About us Mission Statement