[Proposal] identity function

372 views
Skip to first unread message

Alexey Nikitin

unread,
Jul 2, 2019, 5:23:47 AM7/2/19
to elixir-lang-core
Like Haskell's `id` or Clojure's `identity` or Ruby's `itself`

It can be very useful sometimes. Instead of writing ugly `&(&1)` it would much more attractive to write `&identity/1` or `&id\1`
Moreover this function is already used as a default argument for some higher-order function. For example `Enum.group_by(enumerable, key_fun, value_fun \\ fn x -> x end)`

Here are some examples

```
#=> [1, 2, 3, true, 1234]

'abcdaabccc' |> Enum.sort |> Enum.chunk_by(&identity/1)
#=> ['aaa', 'bb', 'cccc', 'd']

[1, 1, 2, 3, 3, 1, 1, 5, 5] |> Enum.chunk_by(&identity/1) |> Enum.map(&hd/1)
#=> [1, 2, 3, 1, 5]

Enum.group_by('abracadabra', &identity/1)
#=> %{97 => 'aaaaa', 98 => 'bb', 99 => 'c', 100 => 'd', 114 => 'rr'}

Enum.map([1, 2, 3, 4], &identity/1)
#=> [1, 2, 3, 4]
[1,2,3,nil, true, false, 1234] |> Enum.filter(&identity/1)
```

Роман Смирнов

unread,
Jul 2, 2019, 5:47:10 AM7/2/19
to elixir-lang-core
+1
Could be very handy sometimes.

вторник, 2 июля 2019 г., 12:23:47 UTC+3 пользователь Alexey Nikitin написал:

Wiebe-Marten Wijnja

unread,
Jul 2, 2019, 5:54:53 AM7/2/19
to elixir-lang-core
I would usually be against introducing concepts to the core's standard library that can be readily and easily expressed in user code.
However, in this case I think there are two strong arguments for including the identity function in the standard library:

1. It is a great tool to help people new to functional programming with their understanding.
2. It is a lot more clear in its purpose than `&(&1)` because it has a name. (c.f. earlier operators vs named functions discussions).

~Marten/Qqwy

Bruce Tate

unread,
Jul 2, 2019, 8:52:37 AM7/2/19
to elixir-l...@googlegroups.com
Strong +1 from me. 

I also think we need default functions for some Enum functions, such as filter. 

-bt

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/b6b3359a-582b-4b42-88d3-10674c6227a5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--

Regards,
Bruce Tate
CEO

Chris Keathley

unread,
Jul 2, 2019, 11:26:18 AM7/2/19
to elixir-l...@googlegroups.com
I'm also in favor of including an `id` function.


For more options, visit https://groups.google.com/d/optout.


--
Chris

Amos King

unread,
Jul 2, 2019, 11:59:38 AM7/2/19
to elixir-l...@googlegroups.com
This is a basic of functional programming and has my vote. 

Amos King
CEO
Binary Noggin

Christopher Keele

unread,
Jul 2, 2019, 12:41:46 PM7/2/19
to elixir-lang-core
I'd cast my vote against this. The proposal seems to be:

1. Create a function named 'id' or some such
2. Put it in the Kernel namespace (so it need not be prefixed)

I've been doing a lot of python lately and they have a lot of things like this, including the same 'filter' global function mentioned in this thread.

Points against:

1. It'd suck to not be able to use 'id' as a variable name, and would conflict with a lot of existing code.
2. Alternative names to 'id' or namespacing it are not shorter than '&(&1)'
3. '&(&1)' is more open to change with requirements
4. Adopting 'id' within Kernel would encourage adding more utility functions to it, exacerbating 1, like the proposed 'filter' function
5. Not adopting it within the Kernel would be hard, as there's no real appropriate place for it elsewhere in standard lib, unlike Enum's 'filter'

Generally it's a nice idea, but I can't think of a great way to make it work, and it'd open the floodgates to more utility functions that I've come to find grating in day-to-day python development.

Just my two cents,
Chris K

Michał Muskała

unread,
Jul 2, 2019, 12:55:10 PM7/2/19
to elixir-lang-core
Because Elixir is a lisp-2 language, variables and functions are in different "namespaces". This means you can have local variables with names of local functions without any issues, but it also means you need different syntax when you want to call a function contained in a variable. Or formulated differently - variables can't shadow functions. For example, consider:
bar = &foo/0
bar.() #=> 1
bar() #=> 2

def foo(), do: 1
def bar(), do: 2
Having a Kernel.id/1 function would not preclude you from using variables called id.

Michał.
--

You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Alexey Nikitin

unread,
Jul 2, 2019, 1:42:51 PM7/2/19
to elixir-lang-core
>    1. It'd suck to not be able to use 'id' as a variable name, and would conflict with a lot of existing code.

Michał Muskała gave brilliant and comprehensive answer

 >   2. Alternative names to 'id' or namespacing it are not shorter than '&(&1)'

length is not the main point. But semantics is

>    3. '&(&1)' is more open to change with requirements

It would be still available ))

>    4. Adopting 'id' within Kernel would encourage adding more utility functions to it, exacerbating 1, like the proposed 'filter' function

The first point is not a problem in sense of variables. And you still can exclude some auto-imported functions

>    5. Not adopting it within the Kernel would be hard, as there's no real appropriate place for it elsewhere in standard lib, unlike Enum's 'filter'

It's true. That's why we should do this :)


вторник, 2 июля 2019 г., 19:41:46 UTC+3 пользователь Christopher Keele написал:

Vadim Safonov

unread,
Jul 2, 2019, 2:20:00 PM7/2/19
to elixir-lang-core
+1 would be very convenient


вторник, 2 июля 2019 г., 12:23:47 UTC+3 пользователь Alexey Nikitin написал:
Like Haskell's `id` or Clojure's `identity` or Ruby's `itself`

Christopher Keele

unread,
Jul 2, 2019, 2:25:09 PM7/2/19
to elixir-l...@googlegroups.com
Derp, I knew that. Good point.

You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/tB61BHYIH1s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/b2149582-b8ba-4759-99ac-a634f73f3243%40Spark.

José Valim

unread,
Jul 2, 2019, 2:40:45 PM7/2/19
to elixir-l...@googlegroups.com
Thanks Chris, it is important that someone being counter arguments, even if they can be disproved. :)

I definitely see how such a small function can be useful but, at the same time, I am not convinced about the name "identity".

I found it curious that Clojure actually have an identity function because the definition of Identity they use when talking about values and change is a more complex one (and one that really stuck with me):

> By identity I mean a stable logical entity associated with a series of different values over time


Of course, my interpretation above is likely uncommon and there are other interpretations of identity that would fit nicely.

Anyway, to move the discussion forward, can someone do a more complete survey on what this function are called in many of the other languages? I just want to make sure we do our due diligence before adding it to the language.

Thank you,

José Valim
Skype: jv.ptec
Founder and Director of R&D


Wiebe-Marten Wijnja

unread,
Jul 2, 2019, 4:00:50 PM7/2/19
to elixir-lang-core
>  Anyway, to move the discussion forward, can someone do a more complete survey on what this function are called in many of the other languages? I just want to make sure we do our due diligence before adding it to the language.

Haskell: id
Clojure: identity
Ruby: Object#itself (although this is a bound method that returns the receiver rather than an unbound function taking one parameter that returns it unchanged. It is the closest thing we have built-in in Ruby, however)
Racket (and some other Lisps): identity
Python: no built-in named identity function.
JS: no built-in named identity function.
PHP: no built-in named identity function.
Kotlin: no built-in named identity function.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/tB61BHYIH1s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-l...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

Ryan Winchester

unread,
Jul 2, 2019, 4:05:57 PM7/2/19
to elixir-l...@googlegroups.com

Allen Madsen

unread,
Jul 2, 2019, 4:47:15 PM7/2/19
to elixir-l...@googlegroups.com

Bruce Tate

unread,
Jul 2, 2019, 5:02:32 PM7/2/19
to elixir-l...@googlegroups.com
I could learn to like &id/1, and also think that &ident/1 fits Elixir's style of abbreviation. My vote is for either one of those. 

-bt


For more options, visit https://groups.google.com/d/optout.


--

Parker Selbert

unread,
Jul 2, 2019, 5:07:53 PM7/2/19
to elixir-l...@googlegroups.com
I’m in favor of the addition overall. The specific function name matters less to me, &identity/1 or &id/1 would be fine.

Greg Vaughn

unread,
Jul 2, 2019, 5:11:21 PM7/2/19
to elixir-l...@googlegroups.com
Can we have some fun with this? Maybe use the unicode "identical to" symbol? ≡
:-) (only half-joking)

-Greg Vaughn
> Groxio, LLC.
> 512.799.9366
> br...@grox.io
> grox.io
>
> --
> You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAFXvW-7%3DfZ2r0a8Urxvg%2B5yHee0gmXZ%3DVVMTuNo05gSOgwkf%2Bg%40mail.gmail.com.

Rich Morin

unread,
Jul 2, 2019, 7:05:25 PM7/2/19
to elixir-lang-core
> On Jul 2, 2019, at 14:11, Greg Vaughn <gva...@gmail.com> wrote:
>
> Can we have some fun with this? Maybe use the unicode "identical to" symbol? ≡
> :-) (only half-joking)

It's great that Elixir supports Unicode (how else could we spell José?), but I
really hope that using Unicode doesn't become any sort of requirement. Among
other reasons is accessibility for the blind: braille displays don't really
play nicely with non-ASCII character sets...

-r

Tyson Buzza

unread,
Jul 2, 2019, 9:31:21 PM7/2/19
to elixir-lang-core
The existing way of doing this might allow beginners to develop a better intuition for the Elixir's capture operator.

For example consider this code for creating a lookup map from a list of maps:

```
lookup = Enum.map(map_list, & {&1.id, &2.name}) |> Enum.into(%{})
```

Knowing about `& &1` allowed me to then intuit that the `& {&1.id, &2.name}` bit of the code above might be possible.

Tyson Buzza

unread,
Jul 2, 2019, 9:38:23 PM7/2/19
to elixir-lang-core
In my post before, the code example I gave should have been `& {&1.id, &1.name}`


On Tuesday, July 2, 2019 at 5:23:47 PM UTC+8, Alexey Nikitin wrote:

Alexey Nikitin

unread,
Jul 3, 2019, 2:41:15 AM7/3/19
to elixir-lang-core
The name may be not the best. It has mathematical roots. But everyone is used to it. It's like "lambda" :) Who could ever imagine that the greek letter is an anonymous function.
But as well as "identity" is the most understandable and familiar name for fp-fans. People look for it by intuition https://stackoverflow.com/questions/35616191/is-there-an-identity-function-in-elixir

Thus I consider the "identity" name the best option

вторник, 2 июля 2019 г., 21:40:45 UTC+3 пользователь José Valim написал:
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/tB61BHYIH1s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-l...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

Виталий Миляков

unread,
Jul 3, 2019, 2:47:37 AM7/3/19
to elixir-lang-core
+1
Great Idea! 

Alexis Brodeur

unread,
Jul 3, 2019, 8:16:22 AM7/3/19
to elixir-lang-core
While this is a great idea, and I am overall in favor of an `Kernel.identity/1`, let me play devil's advocate for a bit...

According to lib/elixir/src/elixir_locals.erl, all `def`s in a module are validated to not clash against an already imported function from other modules.  By introducing `Kernel.identity/1`, modules in the wild already using a `identity/1` function would cease to compile, therefore making this change a breaking one, according to my current understanding of the compiler.

A simple `test.exs` module
```ex
defmodule Test do
  def test do
    inspect("term")
  end

  def inspect(term, opts \\ []) do
    IO.puts("my inspect/2")
  end
end

Test.test
```

against the current `master` of elixir yields:
```
== Compilation error in file /Users/brodeuralexis/test.exs ==
** (CompileError) /Users/brodeuralexis/test.exs:6: imported Kernel.inspect/1 conflicts with local function
    (elixir) src/elixir_locals.erl:94: :elixir_locals."-ensure_no_import_conflict/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:95: anonymous fn/3 in :elixir_locals.ensure_no_import_conflict/3
    /Users/brodeuralexis/test.exs:1: (file)
```

Tyson Buzza

unread,
Jul 3, 2019, 11:19:28 AM7/3/19
to elixir-l...@googlegroups.com
What about calling it the `passthrough` function? That way it does exactly what it says on the tin. This name comes from electronics rather than functional programming or math though.

To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/c42c687b-681f-4863-9628-6819affd8738%40googlegroups.com.

Wiebe-Marten Wijnja

unread,
Jul 3, 2019, 11:32:38 AM7/3/19
to elixir-lang-core
I would be all for changing the way Kernel is imported to allow a name that exists in Kernel to be redefined (potentially generating a warning), because regardless of what name we choose, if this behaviour is not altered then adding any function to Kernel will be a breaking change.

On the other hand: I do not think this is the first time that a new function is added to kernel after 1.0 (or is it)? What approach was taken in those earlier cases?

~Marten/Qqwy

Rich Morin

unread,
Jul 7, 2019, 9:33:17 PM7/7/19
to elixir-l...@googlegroups.com
> On Jul 2, 2019, at 02:23, Alexey Nikitin <tank...@gmail.com> wrote:
>
> Like Haskell's `id` or Clojure's `identity` or Ruby's `itself`

In the spirit of bikeshedding, I'll submit that Clojure's `identity`
takes up too much space for my taste. So, I prefer Haskell's `id` or
perhaps Kotlin's `it`.

-r


Bruce Tate

unread,
Jul 8, 2019, 8:48:52 AM7/8/19
to elixir-l...@googlegroups.com
ooohhhh I really like *it*. 

To compress nils, 

Enum.filter( list, &it/1 )

id is likely to be pretty invasive and might be a more broadly breaking change. 

-bt

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--

Regards,
Bruce Tate
CEO

Alexey Nikitin

unread,
Jul 8, 2019, 11:44:50 AM7/8/19
to elixir-lang-core

Please do not invent new names. It will only get worse

понедельник, 8 июля 2019 г., 4:33:17 UTC+3 пользователь Rich Morin написал:

Paul Schoenfelder

unread,
Jul 8, 2019, 11:58:53 AM7/8/19
to elixir-l...@googlegroups.com
My two cents: use `identity`, or `id` if it absolutely must be ridiculously concise, but keep it simple. In my opinion, functional programmers will almost universally expect one of those two, and everyone else probably won't care because the concept will be new to them. I can't say that I've found myself missing the lack of a standard library `identity` function thus far, but I can see the benefit in readability if we start seeing it replace usages of anonymous functions that just return their argument.

Paul
--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Amos King

unread,
Jul 8, 2019, 12:03:06 PM7/8/19
to elixir-l...@googlegroups.com
I like identity because it is fairly standard and will probably not conflict with as many other libraries that are currently in the ecosystem. 


Amos King
CEO
Binary Noggin

Alexey Nikitin

unread,
Jul 12, 2019, 8:03:39 AM7/12/19
to elixir-lang-core
Any news here? @José Valim, let's do this. Almost everyone reacted to this with enthusiasm. It would be nice. Without this function elixir couldn't be a category :) Let's make elixir Lisp again!


вторник, 2 июля 2019 г., 21:40:45 UTC+3 пользователь José Valim написал:
Thanks Chris, it is important that someone being counter arguments, even if they can be disproved. :)
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/tB61BHYIH1s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-l...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.

Chulki Lee

unread,
Jul 12, 2019, 12:59:49 PM7/12/19
to elixir-lang-core
I'm happy to see Elixir adopting FP concept here ([identity function](https://en.wikipedia.org/wiki/Identity_function)), but I'm not sure it's good to add it to `Kernel` (as it's imported by default!) - or even in Elixir core.

Why should we add this to Elixir core, instead of "extending" with module?

```elixir
defmodule FP do
  def identity(a), do: a
end

def module YourApp do
  import FP

  def hello do
    'abcdaabccc' |> Enum.sort |> Enum.chunk_by(&identity/1)
  end
end
```

For example, that library can be de-facto helper for such FP utility functions.

José Valim

unread,
Jul 12, 2019, 1:15:20 PM7/12/19
to elixir-l...@googlegroups.com
Generally speaking, I agree with Chulki Lee.

I understand the value of the identity function. But the cons of adding it to Kernel is that we partially take the name away from everyone else, unless they unimport it, and ultimately the implementation of identity/1 is not doing much to wararnt this loss.

José Valim
Skype: jv.ptec
Founder and Director of R&D

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/2e98526b-e83c-4b92-8035-26bce95da822%40googlegroups.com.

Bruce Tate

unread,
Jul 12, 2019, 1:18:00 PM7/12/19
to elixir-l...@googlegroups.com
> Why should we add this to Elixir core, instead of "extending" with module?

I have been a big proponent of this for a long time because just about every code base uses the identity function and it's a barrier to those who would learn Elixir. 

Rather than import or call &FP.identity/1, most would just continue to use something like & &1, and that's generally tough on beginners. 

-bt

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/2e98526b-e83c-4b92-8035-26bce95da822%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

José Valim

unread,
Jul 12, 2019, 1:21:49 PM7/12/19
to elixir-l...@googlegroups.com
If the goal is teaching, then I think "fn x -> x end" beats both "&identify/1" and "& &1" in terms of clarity, as identity itself is still a concept that needs to be explained.


José Valim
Skype: jv.ptec
Founder and Director of R&D

Chulki Lee

unread,
Jul 12, 2019, 1:33:45 PM7/12/19
to elixir-lang-core
This is exact reason I'm against adding it to Kernel :) I already have a code using "identity". What would it happen when I upgrade to new Elixir version having this feature?)



Let's look at the list of functions/macros in Kernel  and its description - https://hexdocs.pm/elixir/Kernel.html
 
It mainly consists of:
  • basic language primitives, such as arithmetic operators, spawning of processes, data type handling, etc.
  • macros for control-flow and defining new functionality (modules, functions, and so on)
  • guard checks for augmenting pattern matching

I don't think this new addition (identity/1) does not fit well with Kernel.

Don't get me wrong - I *like* adopting such concepts in Elixir. There are already some functions using such common or mathematical terms (such as List.foldl/3)

However, adding it to Kernel should be more conservative. We cannot more and more such functions into Kernel only because 1) it's convenient and 2) there is not other places to hold it in Elixir core.


 


On Friday, July 12, 2019 at 10:15:20 AM UTC-7, José Valim wrote:
Generally speaking, I agree with Chulki Lee.

I understand the value of the identity function. But the cons of adding it to Kernel is that we partially take the name away from everyone else, unless they unimport it, and ultimately the implementation of identity/1 is not doing much to wararnt this loss.

José Valim
Skype: jv.ptec
Founder and Director of R&D


On Fri, Jul 12, 2019 at 6:59 PM Chulki Lee <chul...@gmail.com> wrote:
I'm happy to see Elixir adopting FP concept here ([identity function](https://en.wikipedia.org/wiki/Identity_function)), but I'm not sure it's good to add it to `Kernel` (as it's imported by default!) - or even in Elixir core.

Why should we add this to Elixir core, instead of "extending" with module?

```elixir
defmodule FP do
  def identity(a), do: a
end

def module YourApp do
  import FP

  def hello do
    'abcdaabccc' |> Enum.sort |> Enum.chunk_by(&identity/1)
  end
end
```

For example, that library can be de-facto helper for such FP utility functions.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-l...@googlegroups.com.