Functional programming 为什么长生不老药没有';不使用多种方法/协议?

Functional programming 为什么长生不老药没有';不使用多种方法/协议?,functional-programming,protocols,elixir,multimethod,Functional Programming,Protocols,Elixir,Multimethod,让我们看看文档中的示例: square = fn(x) -> x * x end list = [1, 2, 3, 4] Enum.map(list, square) 为什么需要显式编写Enum.map?为什么它不使用简洁的符号映射[1,2,3,4],正方形 Elixir有多种调度和协议,但对我来说,它使用起来有点奇怪 如果考虑OOP或多方法/多调度中的多态性,则FP中的协议是使代码简短、简洁和免费的程序员记忆记住方法来自哪里。 因此,在OOP中,它看起来像下面的代码: list.ma

让我们看看文档中的示例:

square = fn(x) -> x * x end
list = [1, 2, 3, 4]
Enum.map(list, square)
为什么需要显式编写
Enum.map
?为什么它不使用简洁的符号
映射[1,2,3,4],正方形

Elixir有多种调度和协议,但对我来说,它使用起来有点奇怪

如果考虑OOP或多方法/多调度中的多态性,则FP中的协议是使代码简短、简洁和免费的程序员记忆记住方法来自哪里。

因此,在OOP中,它看起来像下面的代码:

 list.map(square) 
在FP多重方法中,它看起来像

map(list, square)
在这两种情况下,编译器/解释器都使用参数类型来确定它应该使用的
map
方法

为什么长生不老药不使用相同的方法?为什么它需要编写冗长的代码,并把决定函数从何而来的责任推到程序员的肩上

有时不使用multi-method并显式指定它是有意义的,比如
HttpServer.start(80)
。但是对于像
each
get
set
size
等一般方法,似乎不用明确指定它的来源就可以更容易地使用它

附言


似乎用Elixir中的协议实际上可以做到这一点。我想知道-为什么它没有被使用?我在GitHub上看到的Elixir项目中的所有代码都使用冗长的符号,如
ModuleName.fnName
。不知道为什么会这样。是否不鼓励使用协议,或者协议过于复杂而无法用于日常任务

您可以以可扩展的方式使用带有不同参数的
Enum.map
,因为它是通过协议实现的:

iex> Enum.map [1, 2, 3], fn x -> x * x end
[1, 4, 9]

iex> Enum.map 1..3, fn x -> x * x end
[1, 4, 9]
只要导入
Enum
模块,您也可以将
Enum.map
编写为
map

iex> import Enum
iex> map [1, 2, 3], fn x -> x * x end
[1, 4, 9]
默认情况下,我们不包括
Enum
模块。最好是显式导入它,这样任何阅读您的代码的人都能更好地了解所使用函数的来源

换句话说,多个分派和协议仍然不会改变代码始终存在于模块中的事实,除非导入,否则调用始终是限定的

因此,在OOP中,它看起来像下面的代码:

 list.map(square) 
列表.地图(正方形)

在FP多重方法中,它看起来像

地图(列表,正方形)

在OOP中,您获取一个对象(您的列表)并调用该对象正在实现的方法,在本例中为
map

在Elixir中,使用集合和要应用的函数调用存储在Enum模块中的map函数。 在文档等方面,平面名称空间并不是很好。通过引用Enum下的所有可枚举相关函数,您的文档更有意义(但这不是唯一的原因)。

在Elixir(和Erlang)中,函数始终位于模块中。没有模块就不能有函数。甚至您正在调用的“bare”函数也在一个模块中—它被称为
内核
(在Erlang中,它们位于
:Erlang
模块中)

Erlang/Elixir中的函数是通过模块、名称和算术来标识的——只有这三个元素的组合才能告诉您函数的真实身份,但这三个元素都只涉及函数的命名,而不涉及它所作用的数据


相反,协议与命名函数无关——它们与处理多态数据有关。所有
Enum
函数都有
Enumerable
协议支持-它们可以处理列表、范围、映射、集合等。因此
Enum.map
是一个多态函数,但它被称为
Enum.map
而不仅仅是
map
。如果您对模块名称感到非常困扰,您可以随时导入要使用“裸”的模块。

我对Elixir非常陌生

对我来说,结构和协议只在第一个参数上处理多态性似乎是有局限性的。我发现Julia、CLOS和Clojure中的多方法/多分派功能更强大

但是,看起来您可以非常接近多个方法,而无需在宏中使用多参数保护

一个滑稽简单的例子看起来像

defmodule MyModule do
  defguard both_integers(i, j) when is_integer(i) and is_integer(j)

  def add(i, j) when both_integers(i, j) do
    IO.puts i + j
  end

  def add(i, j) do
    IO.puts "do something completely different"
  end
end

我相信没有人愿意仅仅为了生存而编写协议实现。若你们确切地知道你们的数据是列表,那个么你们就写列表。这是一个相当广泛的问题。投票结束。请注意,这不是OOP。名称空间的工作方式、传递什么是合法的、存在什么数据原语、消息和函数/方法调用之间的明显区别以及所有这些都是完全不同的。感谢回复,但协议不是多方法/多态性。您不能同时从不同的模块导入
map
,比如说
Enum.map
map.map
——所以很明显不存在多态性。Elixir中的协议提供了开放的即席多态性。上面的响应显示了它在第一个参数上的多态性。即使是Elixir中的正则函数子句也提供了一种称为封闭ad-hoc多态性的多态性形式。多方法是多态性的另一种形式,Elixir不支持这种形式。泛型也是多态性的另一种形式,称为参数多态性,甚至连继承也称为子类型多态性。多态性是一个非常宽泛的术语,所以请小心不要混淆它。