Reputation: 9859
Is there a way to make the function "type" implement a protocol in Elixir? I am playing around with a custom Functor
protocol and was wondering if I could make functions implement it (ignoring all the limitations of Elixir's type system).
The implementation (if function
where a type) would be
defimpl Category.Functor, for: function do
def fmap(f, g), do: &(g.(f.(x))
end
Given that you could do
f_2x_plus_1 = &(&1 * 2) |> Functor.fmap(&(&1 + 1))
f_2x_plus_1.(1) == 3
Not that I'd use this for anything serious, just wondering.
Upvotes: 1
Views: 289
Reputation: 9859
It turns out you can. Here is the implementation I am working on for what might result in a library called excategory
defmodule Category.Function do
def compose(f, g) do
arity_f = :erlang.fun_info(f)[:arity]
arity_g = :erlang.fun_info(g)[:arity]
case {arity_f, arity_g} do
{1, 1} ->
&(g.(f.(&1)))
arities ->
raise "Function are not of arity 1, got #{arities}"
end
end
end
defimpl Category.Functor.P, for: Function do
defdelegate map(f, g), to: Category.Function, as: :compose
end
It was on the Protocol section of Getting Started
http://elixir-lang.org/getting-started/protocols.html
Upvotes: 1
Reputation: 9109
Your example doesn't make a whole lot of sense to me because there is only a single type of function in elixir, but Function is a type that you can implement protocols for.
defimpl Category.Functor, for: Function do
def fmap(f, g), do: &(g.(f.(&1))
end
The problem that I see is that arity is very important in Elixir/Erlang and I don't see how to account for that in a straightforward way.
Upvotes: 1
Reputation: 1611
I'm not sure why you need a Protocol
for this... sorry if I've missed something important in your question. You can implement a function with guards that does this though:
defmodule Functor do
def fmap(f, g) where is_function(f) and is_function(g) do
&(g.(f.(&1)))
end
end
and then you can write:
iex> f_2x_plus_1 = Functor.fmap(&(&1 * 2), &(&1 + 1))
#Function<0.100612233/1 in Functor.fmap/2>
...> f_2x_plus_1.(1)
3
I guess I'm just not sure what the protocol gets you that a function doesn't.
Upvotes: 0
Reputation: 1267
Because Erlang/Elixir are dynamically typed, the strict answer is no. Functions really are only differentiated by arity (or for named functions, module, function name, and arity).
You can specify more specific types via Typespecs, and dialyzer (usable in a mix task via dialyxer) will do some assertions on that, but this is not part of the compile toolchain or runtime and provides no guarantees. Not all the violations will be caught by dialyzer (it's based on success typing), but it's a good start.
Upvotes: 0