Search code examples
windowsmemoryerlangerlang-shell

Recursive function call hanging, Erlang


I am currently teaching my self Erlang. Everything is going well until I found a problem with this function.

-module(chapter).
-compile(export_all).

list_length([])      ->   0;
list_length([_|Xs])  ->   1+list_length([Xs]).

This was taken out of an textbook. When I run this code using OTP 17, it just hangs, meaning it just sits as shown below.

1> c(chapter).
{ok,chapter}
2> chapter:list_length([]).
0
3> chapter:list_length([1,2]).

When looking in the task manager the Erlang OTP is using 200 Mb to 330 Mb of memory. What causes this.


Solution

  • It is not terminating because you are creating a new non-empty list in every case: [Anything] is always a non-empty list, even if that list contains an empty list as its only member ([[]] is a non-empty list of one member).

    A proper list terminates like this: [ Something | [] ].

    So with that in mind...

    list_length([])      ->   0;
    list_length([_|Xs])  ->   1 + list_length(Xs).
    

    In most functional languages "proper lists" are cons-style lists. Check out the Wikipedia entry on "cons" and the Erlang documentation about lists, and then meditate on examples of list operations you see written in example code for a bit.

    NOTES

    1. Putting whitespace around operators is a Good Thing; it will prevent you from doing confused stuff with arrows and binary syntax operators next to each other along with avoiding a few other ambiguities (and its easier to read anyway).

    2. As Steve points out, the memory explosion you noticed is because while your function is recursive, it is not tail recursive -- that is, 1 + list_length(Xs) leaves pending work to be done, which must leave a reference on the stack. To have anything to add 1 to it must complete execution of list_length/1, return a value, and in this case remember that pending value as many times as there are members in the list. Read Steve's answer for an example of how tail recursive functions can be written using an accumulator value.