Erlang:使用方法和字段定义某类对象

时间:2011-02-08 12:35:10

标签: erlang

如何在Erlang中使用方法等定义某些类(或类型)对象(如整数比较)?

我怎样才能这样做:

qsort([Pivot|T]) ->
    qsort([X || X <- T, X =< Pivot])
    ++ [Pivot] ++
    qsort([X || X <- T, X > Pivot]).

如果我想对某些对象的列表进行排序,例如人。

5 个答案:

答案 0 :(得分:10)

答案很快:你不想去那里。

答案越长:Erlang不是Java等“传统意义”中的面向对象语言。但它有几种机制可以作为对象的替身:首先有闭包,它可以很容易地编码对象的等价物,尽管编码是如此笨拙以至于几乎没有使用过。相反,人们倾向于“挑选”并从OO获得他们需要的具体想法,无论是封装,继承,多态等等。

其次是进程。进程是一个单独的封装实体,您可以向其发送消息并接收答案。它几乎与“一个类是一个单独的封装实体,您可以使用它来操作它的方法”相同。由于产生一个过程很便宜,所以将过程稍微用作OO风格的对象并不是一个问题。

第三,有参数化模块,有些人喜欢使用它们,就好像它们将OO风格的代码带回语言一样。

第四,有一流的功能。由于您可以像数据一样轻松地传递函数,因此您通常可以使用它来概括代码而不是构建对象层次结构。


总之:如果你用惯用语来写Erlang,你很少会发现需要等同于'class'。

答案 1 :(得分:6)

简短回答

你不能(至少如果你想让Erlang程序员认真对待,而Erlang代码可以正常工作)。

长答案

Erlang是一种函数式编程语言,而不是面向对象的编程语言。 “对象”(具有附加功能的状态集合)的整个基本概念是功能方法(尽可能避开可变状态)的诅咒。你可以将功能语言中的类似对象的设置整合在一起 - 尤其是像Erlang这样不纯净的设置 - 但是生成的代码将难以阅读,难以维护,脆弱和丑陋。 (难以阅读和维护,比使用OOP语言编写的OOP代码更加脆弱和丑陋,这似乎很难相信。)

您可以通过以下方式更好地满足您的需求:

  • 学习自然习语和表达Erlang原生思想的方法(LYSE是这个首选解决方案的一个很好的起点);或
  • 使用面向对象的编程语言进行面向对象的编程。

用非OOP语言做一半的OOP通常没有结果,也很痛苦。

答案 2 :(得分:3)

Erlang没有这样的抽象数据类型。定义数据类型的标准方法是通过一个模块,该模块将所有访问功能提供给数据,并且期望用户不绕过它们。 OTP中的示例包括setsdictarray。这通常很有效,但您必须知道数据的类型。有时结构是定义的,但用户在处理数据时应该“表现自己”,例如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,其中有两个字段,尤其是nameage。我们还有两个谓词F1F2,它们与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()).