Generics in elixir

Hi, I’m trying to understand how far can elixir typespecs go.
I’ve been programming in typescript for a while, and for now I have an example I want to replicate in Elixir:
So I have a collection and I want to write a utility to group items in the collection using some sort of logic (that is user-defined)
So in typescript it would actually look like:

function groupBy<T, GroupKey>(collection: T[], by: (item: T) => GroupKey): Record<GroupKey, T[]> {
  // implementation...
}

Usage:

const myCollection: number[] = [1, 2, 3, 4]
groupBy(myCollection, (item) => item)

Here the parameter “item” is correctly typed to number and the result type would be an object that has for key a number and for value a list of number.

Can elixir handle generics like this (even with macro maybe?)
Or are there some other approaches?

AFAIK Dialyzer do not do any deductions about types. You can write:

@spec group_by(collection :: [t], by :: ((t) -> key)) :: %{required(key) => t} when t: term(), key: term()

But Dialyzer will not be able to deduce that key or t needs to be the same, this will be only visible to the user. Of course you do not need to use Dialyzer and instead use other tools (like Gradualizer) or even write your own that will make deductions about code, but AFAIK there is no such tool right now.

1 Like

Yeah I just realized that neither Enum.map infers types.
For now I can explicitly define the structure of the lambda parameter.
But it would be a nice to have feature tbh.

Thanks it would have taken a lot of time to search for this by myself

Being more strict in the function parameter lists via pattern-matching and guards can get you very far. It can become tedious to write them but the added peace of mind is very much worth it.

1 Like