Erlang: можно ли написать минимальную функцию в виде списка?

Учитывая функцию:

min(A, B)  when A =< B -> A;
min(_A, B)             -> B.

могу ли я использовать это в функции foldl аналогично этому:

lists:foldl(fun min/2, 0, [1,2,3,4,5,6,7,8,9,10])

Я считаю, что это невозможно, потому что я должен установить начальное значение, которое будет сравниваться с остальной частью списка, например. грамм. нет никакой функции идентичности, о которой я могу думать. Я прав?

Синтаксис написан на Erlang, но должен быть понятен и для программистов, не использующих Erlang.


person Magnus Kronqvist    schedule 02.03.2011    source источник
comment
Разве вы не можете использовать head для начального значения?   -  person Fyodor Soikin    schedule 02.03.2011
comment
Я думаю, что мог бы, и это привело бы к сбою в пустом списке, как указано ниже.   -  person Magnus Kronqvist    schedule 02.03.2011
comment
Ответы Ясира и Адама хороши, сбой в пустом списке может и не может быть приемлемым в зависимости от контекста. BTW исправил ваш пример, чтобы его можно было скомпилировать.   -  person Peer Stritzinger    schedule 02.03.2011
comment
Спасибо, @Peer. Кроме того, я думаю, что undefined не имеет большого смысла, см., например, Лучшее объяснение языков без Null.   -  person YasirA    schedule 02.03.2011
comment
@Ясир. Я согласен с этим.   -  person Magnus Kronqvist    schedule 02.03.2011


Ответы (3)


1> List = [42,13,25,3,19,20].
[42,13,25,3,19,20]
2> lists:foldl(fun(X, Y) -> erlang:min(X,Y) end, hd(List), tl(List)).   
3

Сбой программы в пустом списке, рекомендуемый подход «пусть сбой» в отличие от защитного программирования.

person YasirA    schedule 02.03.2011
comment
К сожалению, последним аргументом foldl должен быть tl(List) (конец списка). Я бы хотел, чтобы у нас была функция foldl1, которая есть в Haskell, чтобы мы не использовали начальное значение. - person YasirA; 02.03.2011

min(List) ->
    Min = fun(A,  B) when A < B -> A;
             (_A, B)            -> B end,
    lists:foldl(Min, undefined, List).

Использование undefined в качестве начального состояния должно помочь. Возвращает undefined для пустого списка, что неплохо для API.

Если вы хотите, чтобы он зависал в пустом списке, используйте вместо этого заголовок этой функции:

min([Head|Rest]) ->
    Min = fun(A,  B) when A < B -> A;
             (_A, B)            -> B end,
    lists:foldl(Min, Head, Rest).
person Adam Lindberg    schedule 02.03.2011
comment
Хороший ответ! Кажется даже, что первая защита (undefined,B) -> B избыточна. - person Magnus Kronqvist; 02.03.2011
comment
На самом деле просто из рандома он не вылетает. Я не знаю, является ли результат детерминированным, но из примеров, с которыми я пробовал, сравнение любого числа и атома возвращает число как меньшее. - person Magnus Kronqvist; 02.03.2011
comment
Передача undefined работает, потому что существует четко определенный порядок для оператора < при работе с гетерогенными типами. В частности, Числа всегда меньше атомов. Поищите функции заказа в справочном руководстве. - person I GIVE CRAP ANSWERS; 02.03.2011

Предложение Адама Линдберга использовать undefined в качестве начального значения имеет тот недостаток, что оно генерирует странные результаты для списков, членами которых являются атомы. Erlang имеет глобальный порядок всех объектов, поэтому хорошим свойством функции min было бы ее использование для всех типов.

Я думаю, что более разумно сбой в пустом списке. Разница в том, что клиент должен беспокоиться о случае, вместо того, чтобы беспокоиться о получении undefined в результате.

person Lii    schedule 04.03.2011