可以"功能"在Elixir中实施协议?

时间:2016-03-05 20:14:32

标签: elixir

有没有办法让函数"键入"在Elixir中实施协议?我正在使用自定义Functor协议,并且想知道我是否可以使函数实现它(忽略Elixir类型系统的所有限制)。

实施(如果function类型)

defimpl Category.Functor, for: function do
  def fmap(f, g), do: &(g.(f.(x))
end

鉴于你可以做到

f_2x_plus_1 = &(&1 * 2) |> Functor.fmap(&(&1 + 1))
f_2x_plus_1.(1) == 3

并非我将此用于任何严肃的事情,只是想知道。

4 个答案:

答案 0 :(得分:1)

事实证明你可以。以下是我正在处理的可能导致名为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

它出现在“入门”的“协议”部分

http://elixir-lang.org/getting-started/protocols.html

答案 1 :(得分:1)

你的例子对我来说并没有多大意义,因为在elixir中只有一种类型的函数,但是Function是一种类型,你可以 实现协议。

defimpl Category.Functor, for: Function do
  def fmap(f, g), do: &(g.(f.(&1))
end

我看到的问题是,在Elixir / Erlang中,arity非常重要,我不知道如何以直截了当的方式解释它。

答案 2 :(得分:0)

因为Erlang / Elixir是动态类型的,所以严格的答案是否定的。函数实际上仅由arity(或命名函数,模块,函数名称和arity)区分。

您可以通过Typespecs指定更多特定类型,透析器(通过dialyxer在混合任务中使用)将对此进行一些断言,但这不是编译工具链或运行时的一部分,并且不提供任何保证。并非所有违规行为都会被透析器捕获(这取决于成功输入),但这是一个良好的开端。

答案 3 :(得分:0)

我不确定为什么你需要一个Protocol ...抱歉,如果我错过了你问题中的重要内容。你可以实现一个带保护功能的功能:

defmodule Functor do
  def fmap(f, g) where is_function(f) and is_function(g) do
    &(g.(f.(&1)))
  end
end

然后你可以写:

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

我想我只是不确定协议会给你一个函数没有的东西。