Erlang: определение некоторого класса объектов с помощью методов и полей - PullRequest
5 голосов
/ 08 февраля 2011

Как определить некоторый класс (или тип) объектов с помощью методов и т. Д. (Например, целочисленное сравнение) в Erlang?

Как я могу, например, сделать это:

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

Если я хочу отсортировать список некоторых объектов, например, людей.

Ответы [ 5 ]

10 голосов
/ 08 февраля 2011

Очень быстрый ответ: Вы не хотите туда идти.

Более длинный ответ: Erlang не является объектно-ориентированным языком в «традиционном смысле», например, Java.Но у него есть несколько механизмов, которые могут выступать в качестве замены для объектов: во-первых, есть замыкания , которые могут легко кодировать эквивалент объектов, хотя кодирование настолько громоздко, что едва ли когда-либо используется.Скорее люди, как правило, «выбирают черри» и получают конкретную идею, которая им нужна от ОО, будь то инкапсуляция, наследование, полиморфизм и т. Д.

Во-вторых, процессы .Процесс - это отдельная инкапсулированная сущность, на которую вы можете отправлять сообщения и получать ответы.Это почти то же самое, что «Класс - это отдельная инкапсулированная сущность, для которой вы можете использовать методы для работы с ней».Поскольку порождение процесса обходится дешево, не проблема использовать процессы в некоторой степени как объекты в стиле OO.

В-третьих, есть параметризованные модули , которые некоторые люди любят использовать, как будто они возвращаютКод в стиле ОО к языку.

В-четвертых, есть первоклассные функции .Поскольку вы можете передавать функцию так же легко, как данные, вы часто можете использовать это для обобщения кода, а не для построения иерархии объектов.


В заключение: если вы пишете Erlang в идиоматическом стиле, вы редконайдите потребность в эквиваленте «класса».

6 голосов
/ 08 февраля 2011

Короткий ответ

Вы не можете (по крайней мере, если вы хотите, чтобы вас серьезно воспринимали как программиста на Erlang, имея код Erlang, который работает правильно).

Длинный ответ

Erlang - это функциональный язык программирования, а не объектно-ориентированный язык программирования.Все базовое понятие «объект» (совокупность состояний с прикрепленными функциями) является анафемой для функционального подхода (который максимально избегает изменяемого состояния).Вы могли бы объединить объектоподобную установку в функциональном языке - особенно нечистом, например, в Erlang, - но полученный код будет трудно читать, трудно поддерживать, хрупким и безобразным.(Труднее читать и поддерживать, более хрупкий и уродливый, чем даже ООП-код, написанный на языке ООП, как ни трудно в это поверить.)

Вы бы намного лучше справились со своими потребностями:1011 *

  • изучение естественных идиом и способов выражения идей, родных для Erlang ( LYSE является хорошей отправной точкой для этого предпочтительного решения);или
  • с использованием объектно-ориентированного языка программирования для объектно-ориентированного программирования.

Выполнение неполного ООП на языке без ООП, как правило, бесплодно и болезненно.

3 голосов
/ 08 февраля 2011

Эрланг не имеет абстрактных типов данных как таковых. Стандартный способ определения типа данных - это модуль, который обеспечивает все функции доступа к данным, и ожидается, что пользователь не будет их обходить. Примерами этого в OTP являются такие вещи, как sets, dict и array. Обычно это работает хорошо, но вы должны знать , какой тип данных. Иногда структура определяется, но пользователь, как ожидается, будет "вести себя" при работе с данными, например: ordsets.

Обратите внимание, что во всех случаях данные являются стандартными неизменяемыми данными Эрланга, которые не обновляются, как в большинстве традиционных ОО-языков. Я могу только повторить то, что было сказано в других ответах, и не пытаться использовать ОО-стиль в не-ОО-языке, таком как Erlang, и наоборот. Результат не будет элегантным и красивым.

Последний комментарий: определение быстрой сортировки, хотя оно и лаконично и просто, очень неэффективно.

2 голосов
/ 08 февраля 2011

Согласно вашему примеру, вы просто вызываете ваш 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 записей, которые вы затем можете использовать в своем коде.

0 голосов
/ 08 февраля 2011

Краткий ответ:

Можно.

Длинный ответ:

Ну, это не удобно, хотя. Лучше было бы передать функцию сортировки в qsort (как упоминал Ясир Арсанукаев, так же, как в списках: 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()).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...