новости сообщество форум вики
Erlang по-русски. Форум » Erlang »

Как вывести полностью список ?

(5 posts)

  1. Я новичок в Erlang.

    Поставил себе простенькую задачку, а именно сделать ре?ето Ератосфена.

    Вот код:

    -module(tut).
    -export([lines/1,eratosfen/1,division_number/3]).

    % Функция которая возвращает последовательность натуральных чисел от 1 до A
    lines(2) -> [ 2 ];
    lines(A) -> lists:append(lines(A - 1) , [ A ]).

    %удаляем из списка все числа, делящиеся на D
    division_number(_, LIST, [ ]) -> LIST;
    division_number(D, LIST, [ A | C ]) -> if
    A rem D == 0 -> division_number(D, LIST, C);
    true -> division_number(D, lists:append(LIST, [ A ]), C)
    end.

    erat([ ] , X) -> X;
    erat([ A ] , SIMPLE) -> erat([ ], lists:append(SIMPLE, [ A ]));
    erat([A | B] , SIMPLE) -> erat(division_number(A, [ ], B), lists:append(SIMPLE, [ A ])).

    %ре?ето эратосфена
    eratosfen( A ) -> erat(lines(A), [ ]).

    Все отлично работает, но вывод обрезает результаты:


    80> tut:eratosfen(10).
    [2,3,5,7]
    81> tut:eratosfen(100).
    [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
    79,83,89,97]
    82> tut:eratosfen(1000).
    [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
    79,83,89,97,101,103,107,109|...]
    83> tut:eratosfen(10000).
    [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
    79,83,89,97,101,103,107,109|...]

    А как вывести полностью список ?

    P.S. Критика исходного кода приветсвуется по части оформления, ну и реализации тоже.

    Спасибо.

    Отправлено 5 мес. назад #
  2. EvilBlueBeaver
    Участник

    Вывести список можно например так
    io:format("~p", [tut:eratosfen(10)])

    Критика.
    1. вместо list:append(List, [A]) луч?е использовать [A | List]. Результат будет в обратном порядке, но эффективнее будет развернуть список один раз, чем пересоздавать его на каждой итерации.
    2. В функции lines отсутствует хвостовая рекурсия.
    В итоге будет выглядеть приблизительно так:
    lines(1, Res) -> Res;
    lines(A, Res) -> lines(A -1, [A | Res]).
    lines(A) -> lines(A, []).
    3. Выносить в экспорт внутренние функции модуля - это моветон
    4. Вместо [A|C] принято писать [H|T]
    5. Полностью заглавными буквами пи?утся обычно дефайны.
    6. вместо if'а можно сделать ли?ний заголовок с гардом.

    Поправил ва? исходник безе пересмотра алгоритма

    -module(tut).
    -export([eratosfen/1]).

    lines(1, Res) ->
    Res;
    lines(A, Res) ->
    lines(A -1, [A | Res]).
    lines(A) ->
    lines(A, []).

    division_number(_, [], Res) ->
    Res;
    division_number(D, [H|T], Res) when H rem D == 0->
    division_number(D, T, Res);
    division_number(D, [H|T], Res) ->
    division_number(D, T, [H | Res]).

    division_number(D, L) ->
    division_number(D, L, []).

    erat([] , X) ->
    X;
    erat([H] , Simple) ->
    erat([], [H |Simple]);
    erat([H|T] , Simple) ->
    erat(lists:reverse(division_number(H, T)), [H | Simple]).

    eratosfen(A) ->
    lists:reverse(erat(lines(A), [ ])).

    Результаты fprof
    Ва?
    % CNT ACC OWN
    [{ totals, 50215, 364.859, 363.727}]. %%%

    Мой
    % CNT ACC OWN
    [{ totals, 17506, 163.154, 162.561}]. %%%

    Отправлено 5 мес. назад #
  3. спасибо боль?ое за развернутый ответ.

    Да действиельно list::append - не очень хоро?ее ре?ение.
    ?значально я делал как раз [ A | List ], однако результат меня не устроил :) при?лось извращаться. Можно было вообще извратиться по другому например так:


    lines0(2) -> [ 2 ];
    lines0(A) -> [ A | lines(A-1) ].
    lines(A) -> list::reverse(lines0(A)).

    Насколько я понимаю оператор [ | ] - слева от черты первый элемент, а справа вся остальная часть списка. А есть ли в языке краткое выражение для взятия например последнего элемента из списка, или списки они только однонаправленные ? Если да, то это боль?е не список, а стэк какой-то :)

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

    Кстати в ерланг существует понятие юнит-тестов? имхо тут сам код как юнит-тест, осталось только подставлять конкретные выражения в определения функций.

    Отправлено 5 мес. назад #
  4. EvilBlueBeaver
    Участник

    lines0(2) -> [ 2 ];
    lines0(A) -> [ A | lines(A-1) ].
    lines(A) -> list::reverse(lines0(A)).

    Так луч?е не делать, поскольку рекурсия не хвостовая.

    lists:last возвратит последний элемент. но это если действительно нужен последний элемент. Если присутствуют операции обхода или конструирования списка, то луч?е их делать с головы, так как внутри ВМ это не приводит к перевыделению памяти и созданию нового списка. Как впрочем и не рекомендуется использовать для этих же целей lists:append

    Отправлено 5 мес. назад #
  5. Спасибо. ?звиняюсь, кажется там опечатка:

    lines0(A) -> [ A | lines<b>0</b>(A-1) ].

    Вопросы про отладку и юнит-тесты, остаются открытыми :)

    Отправлено 5 мес. назад #

RSS экспорт этой темы

Отправить сообщение

Вы должны войти в систему, чтобы оставлять сообщения.

 
 

так же

Популярные тэги



Currently online

No Members around.

twitter