如何在Erlang中使用方法等定义某些类(或类型)对象(如整数比较)?
我怎样才能这样做:
qsort([Pivot|T]) ->
qsort([X || X <- T, X =< Pivot])
++ [Pivot] ++
qsort([X || X <- T, X > Pivot]).
如果我想对某些对象的列表进行排序,例如人。
答案 0 :(得分:10)
答案很快:你不想去那里。
答案越长:Erlang不是Java等“传统意义”中的面向对象语言。但它有几种机制可以作为对象的替身:首先有闭包,它可以很容易地编码对象的等价物,尽管编码是如此笨拙以至于几乎没有使用过。相反,人们倾向于“挑选”并从OO获得他们需要的具体想法,无论是封装,继承,多态等等。
其次是进程。进程是一个单独的封装实体,您可以向其发送消息并接收答案。它几乎与“一个类是一个单独的封装实体,您可以使用它来操作它的方法”相同。由于产生一个过程很便宜,所以将过程稍微用作OO风格的对象并不是一个问题。
第三,有参数化模块,有些人喜欢使用它们,就好像它们将OO风格的代码带回语言一样。
第四,有一流的功能。由于您可以像数据一样轻松地传递函数,因此您通常可以使用它来概括代码而不是构建对象层次结构。
总之:如果你用惯用语来写Erlang,你很少会发现需要等同于'class'。
答案 1 :(得分:6)
你不能(至少如果你想让Erlang程序员认真对待,而Erlang代码可以正常工作)。
Erlang是一种函数式编程语言,而不是面向对象的编程语言。 “对象”(具有附加功能的状态集合)的整个基本概念是功能方法(尽可能避开可变状态)的诅咒。你可以将功能语言中的类似对象的设置整合在一起 - 尤其是像Erlang这样不纯净的设置 - 但是生成的代码将难以阅读,难以维护,脆弱和丑陋。 (难以阅读和维护,比使用OOP语言编写的OOP代码更加脆弱和丑陋,这似乎很难相信。)
您可以通过以下方式更好地满足您的需求:
用非OOP语言做一半的OOP通常没有结果,也很痛苦。
答案 2 :(得分:3)
Erlang没有这样的抽象数据类型。定义数据类型的标准方法是通过一个模块,该模块将所有访问功能提供给数据,并且期望用户不绕过它们。 OTP中的示例包括sets
,dict
和array
。这通常很有效,但您必须知道数据的类型。有时结构是定义的,但用户在处理数据时应该“表现自己”,例如ordsets
。
但是请注意,在所有情况下,数据都是标准的不可变Erlang数据,与大多数传统的OO语言一样,这些数据不具备可数据性。我只能重申其他答案中所说的内容,不要尝试在Erlang这样的非OO语言中使用OO风格,反之亦然。结果不会优雅和美丽。
最后评论:快捷方式的定义虽然简洁明了,效率很低。
答案 3 :(得分:2)
根据您的示例,您只需使用适当的未排序值列表调用qsort
并获取排序列表:
some_useful_fun(X, Y) ->
% ...
Xsorted = qsort(X),
% do something with Xsorted
...
就是这样。纯函数式编程中没有状态。唯一的状态是作为函数参数传递的数据。函数应该在传递的参数上返回相同的结果,尽管你调用它的次数。
在Erlang中,您可以将对象映射到记录。请考虑以下代码:
-export([sort/0]).
-record(person,
{
name,
age
}).
persons_list() -> [
#person{name="John", age=38},
#person{name="Paul", age=25},
#person{name="Michael", age=23}
].
qsort(_Pred1, _Pred2, []) ->
[];
qsort(Pred1, Pred2, [Pivot|T]) ->
qsort(Pred1, Pred2, [X || X <- T, Pred1(X, Pivot)])
++ [Pivot] ++
qsort(Pred2, Pred2, [X || X <- T, Pred2(X, Pivot)]).
sort() ->
F1 = fun(#person{age = A1}, #person{age = A2}) ->
A1 =< A2 end,
F2 = fun(#person{age = A1}, #person{age = A2}) ->
A1 > A2 end,
qsort(F1, F2, persons_list()).
我们有一个记录person
,其中有两个字段,尤其是name
和age
。我们还有两个谓词F1
和F2
,它们与qsort
的内容相符。如果我们现在使用这两个谓词和qsort/3
记录列表调用person
,我们将获得以下结果:
1> c(persons).
{ok,persons}
2> persons:sort().
[{person,"Michael",23},
{person,"Paul",25},
{person,"John",38}]
3>
这是person
记录的排序列表,您可以在代码中使用。
答案 4 :(得分:-2)
简答:
你可以。
答案很长:
嗯,虽然不方便。更好的方法是将sort函数传递给qsort(正如Yasir Arsanukaev之前提到的,与列表中的相同:sort / 2)。但是“如果你把它放在心上,你可以做任何事情”,正如有人曾经说过的那样。
-module(persons).
-export([sort_persons/0, sort_sku/0]).
-record(person, {name, age}).
-record(sku, {item_number, price}).
-record(sortable, {lt}).
-record(object, {state, methods}).
persons_list() ->
Sortable = #sortable{lt=fun(#person{age = A1}, #person{age = A2}) -> A1 < A2 end},
[
#object{state=#person{name="John", age=38}, methods = Sortable},
#object{state=#person{name="Paul", age=25}, methods = Sortable},
#object{state=#person{name="Michael", age=23}, methods = Sortable}
].
sku_list() ->
Sortable = #sortable{lt=fun(#sku{price = P1}, #sku{price = P2}) -> P1 < P2 end},
[
#object{state=#sku{item_number="11111", price=3.54}, methods = Sortable},
#object{state=#sku{item_number="222222", price=1.58}, methods = Sortable},
#object{state=#sku{item_number="33333", price=2.31}, methods = Sortable},
#object{state=#sku{item_number="44444", price=8.41}, methods = Sortable}
].
qsort([]) ->
[];
qsort([Pivot|T]) ->
qsort([X || X <- T, (X#object.methods#sortable.lt)(X#object.state, Pivot#object.state)])
++ [Pivot] ++
qsort([X || X <- T, not (X#object.methods#sortable.lt)(X#object.state, Pivot#object.state)]).
sort_persons() ->
qsort(persons_list()).
sort_sku() ->
qsort(sku_list()).