Junqi CHENG
Junqi CHENG

Reputation: 1

What causes Erlang runtime error {undef,[{rand,uniform,[2],[]},...]}?

When executing an implementation of the Tarry distributed algorithm, a problem occurs that I don't know how to address: a crash containing the error {undef,[{rand,uniform,[2],[]}. My module is below:

-module(assign2_ex).
-compile(export_all).

%% Tarry's Algorithm with depth-first version
start() ->
    Out = get_lines([]),
    Nodes = createNodes(tl(Out)),
    Initial = lists:keyfind(hd(Out), 1, Nodes),
    InitialPid = element(2, Initial),
    InitialPid ! {{"main", self()}, []},
    receive
        {_, List} ->
            Names = lists:map(fun(X) -> element(1, X) end, List),
            String = lists:join(" ", lists:reverse(Names)),
            io:format("~s~n", [String])
    end.

get_lines(Lines) ->
    case io:get_line("") of
        %% End of file, reverse the input for correct order
        eof -> lists:reverse(Lines);
        Line ->
            %% Split each line on spaces and new lines
            Nodes = string:tokens(Line, " \n"),
            %% Check next line and add nodes to the result
            get_lines([Nodes | Lines])
    end.

%% Create Nodes
createNodes(List) ->
    NodeNames = [[lists:nth(1, Node)] || Node <- List],
    Neighbours = [tl(SubList) || SubList <- List],
    Pids = [spawn(assign2_ex, midFunction, [Name]) || Name <-NodeNames],                         
    NodeIDs = lists:zip(NodeNames, Pids),
    NeighbourIDs = [getNeighbours(N, NodeIDs) || N <- lists:zip(NodeIDs,   Neighbours)],
    [Pid ! NeighbourPids || {{_, Pid}, NeighbourPids} <- NeighbourIDs],
    NodeIDs.

getNeighbours({{Name, PID}, NeighboursForOne}, NodeIDs) ->
    FuncMap = fun(Node) -> lists:keyfind([Node], 1, NodeIDs) end,
    {{Name, PID}, lists:map(FuncMap, NeighboursForOne)}.

midFunction(Node) ->
    receive
        Neighbours -> tarry_depth(Node, Neighbours, [])
    end.

%% Tarry's Algorithm with depth-first version
%% Doesn't visit the nodes which have been visited
tarry_depth(Name, Neighbours, OldParent) ->
    receive
        {Sender, Visited} ->
            Parent = case OldParent of [] -> [Sender]; _ -> OldParent end,
            Unvisited = lists:subtract(Neighbours, Visited),
            Next = case Unvisited of
                       [] -> hd(Parent);
                       _ -> lists:nth(rand:uniform(length(Unvisited)), Unvisited)
                   end,
            Self = {Name, self()},
            element(2, Next) ! {Self, [Self | Visited]},
            tarry_depth(Name, Neighbours, Parent)
    end.

Upvotes: 0

Views: 357

Answers (2)

legoscia
legoscia

Reputation: 41618

An undef error means that the program tried to call an undefined function. There are three reasons that this can happen for:

  • There is no module with that name (in this case rand), or it cannot be found and loaded for some reason
  • The module doesn't define a function with that name and arity. In this case, the function in question is uniform with one argument. (Note that in Erlang, functions with the same name but different numbers of arguments are considered separate functions.)
  • There is such a function, but it isn't exported.

You can check the first by typing l(rand). in an Erlang shell, and the second and third by running rand:module_info(exports)..

In this case, I suspect that the problem is that you're using an old version of Erlang/OTP. As noted in the documentation, the rand module was introduced in release 18.0.

Upvotes: 1

codeadict
codeadict

Reputation: 2753

Will be good if you provide the version of Erlang/OTP you are using for future questions as Erlang has changed a lot over the years. As far as i know there is no rand:uniform with arity 2 at least in recent Erlang versions and that is what you are getting the undef error, for that case you could use crypto:rand_uniform/2 like crypto:rand_uniform(Low, High). Hope this helps :)

Upvotes: 0

Related Questions