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不支持这种形式。泛型也是多态性的另一种形式,称为参数多态性,甚至连继承也称为子类型多态性。多态性是一个非常宽泛的术语,所以请小心不要混淆它。