Property List get_value undefined erlang - erlang

I am new to erlang. I have property list as follows.
[{name,<<"127.0.0.1:53290 -> 127.0.0.1:1883">>},{pid,<0.987.0>},{user,<<"guest">>},{type,direct}]
This is my function.
close_single_connection(Conn, ReqData) ->
io:format("~p\n", Conn),
case proplists:get_value(pid, Conn) of
undefined -> io:format("Undefined~n"),ok;
Pid when is_pid(Pid) ->
io:format(Pid),
force_close_connection(ReqData, Conn, Pid)
end.
io:format("~p\n", Conn) return my property list correctly. But proplists:get_value(pid, Conn) return undefined.
When I am executing following in erlang shell it return Pid value correctly.
List = [{name,<<"127.0.0.1:53290 -> 127.0.0.1:1883">>},{pid,<0.987.0>},{user,<<"guest">>},{type,direct}],
proplists:get_value(pid, List).
Please give me a way to identify the reason.

Issue is in list creation step.
List should create as follows. This is working properly.
List = [],
List ++ [{name,<<"127.0.0.1:53290 -> 127.0.0.1:1883">>},{pid,<0.987.0>},{user,<<"guest">>},{type,direct}].
Following is the wrong one. I added redundant [] like this.
List = [],
X = [{name,<<"127.0.0.1:53290 -> 127.0.0.1:1883">>},{pid,<0.987.0>},{user,<<"guest">>},{type,direct}],
List ++ [X].

Related

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.
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.
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 :)

Erlang: syntax error before: ","word"

I have the following functions:
search(DirName, Word) ->
NumberedFiles = list_numbered_files(DirName),
Words = make_filter_mapper(Word),
Index = mapreduce(NumberedFiles, Words, fun remove_duplicates/3),
dict:find(Word, Index).
list_numbered_files(DirName) ->
{ok, Files} = file:list_dir(DirName),
FullFiles = [ filename:join(DirName, File) || File <- Files ],
Indices = lists:seq(1, length(Files)),
lists:zip(Indices, FullFiles). % {Index, FileName} tuples
make_filter_mapper(MatchWord) ->
fun (_Index, FileName, Emit) ->
{ok, [Words]} = file:consult(FileName), %% <---- Line 20
lists:foreach(fun (Word) ->
case MatchWord == Word of
true -> Emit(Word, FileName);
false -> false
end
end, Words)
end.
remove_duplicates(Word, FileNames, Emit) ->
UniqueFiles = sets:to_list(sets:from_list(FileNames)),
lists:foreach(fun (FileName) -> Emit(Word, FileName) end, UniqueFiles).
However, when i call search(Path_to_Dir, Word) I get:
Error in process <0.185.0> with exit value:
{{badmatch,{error,{1,erl_parse,["syntax error before: ","wordinfile"]}}},
[{test,'-make_filter_mapper/1-fun-1-',4,[{file,"test.erl"},{line,20}]}]}
And I do not understand why. Any ideas?
The Words variable will match to content of the list, which might not be only one tuple, but many of them. Try to match {ok, Words} instead of {ok, [Words]}.
Beside the fact that the function file:consult/1 may return a list of several elements so you should replace {ok,[Words]} (expecting a list of one element = Words) by {ok,Words}, it actually returns a syntax error meaning that in the file you are reading, there is a syntax error.
Remember that the file should contain only valid erlang terms, each of them terminated by a dot. The most common error is to forget a dot or replace it by a comma.

Erlang filter list using lists:keyfind partial string

I am almost new with Erlang
I have a list as:
List = [[{name, <<"redCar1">>}, {turbo, true}], [{name, <<"redCar2">>}, {turbo, true}], [{name, <<"greenCard">>}, {turbo, false}]].
Now I want to filter all "red" Cars
I tried using:
filterCar() ->
MyF = fun(List) ->
case lists:keyfind(name, 1, List) of
{name, <<"red", _Rest/binary>>} ->
true:
_ ->
false
end
end,
MyF.
Then
lists:filter(MyF, List),
It works perfectly.
Now I want to create an generic function to filter, like:
myfilter(Value, List) ->
case lists:keyfind(name, 1, List) of
{name, <<Value, _Rest/binary>>} ->
true;
_ ->
false
end.
But when I try to execute this function I got always [] empty list.
I am sure the problem is when I try to pass Value because if I replace
{name, <<Value, _Rest/binary>>}
with
{name, <<"red", _Rest/binary>>}
It works.
My aim it to find all string that start with car in ignore case.
You just need to indicate two more things to use a general value in your binary: that it's a binary, and the size of that binary.
filterCar(Value) when is_binary(Value) ->
MyF = fun(List) ->
Size = byte_size(Value),
case lists:keyfind(name, 1, List) of
{name, <<Value:Size/binary, _Rest/binary>>} ->
true;
_ ->
false
end
end,
MyF.
First we changed filterGuard to take one argument, Value, which is the pattern we want to look for. We use a guard on the function to ensure Value is a binary. Inside the internal fun we first retrieve the size of Value via byte_size/1, which we need so that we can set the expected field size in the matching binary. This leads to the key change, which is <<Value:Size/binary, _Rest/binary>>: we set the expected size of the Value field, and we define it as a binary field.
With this change in place, we can successfully apply it to your List variable, passing <<"red">> for Value:
1> lists:filter(filterCar(<<"red">>), List).
[[{name,<<"redCar1">>},{turbo,true}],
[{name,<<"redCar2">>},{turbo,true}]]

Returning specific xml tag with erlang

get_currency() ->
URL = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22GBPEUR%22)&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
{Result, Info} = httpc:request(URL),
case Result of
error ->
{Result, Info};
ok ->
{{_Protocol, Code, _CodeStr}, _Attrs, WebData} = Info,
WebData
end.
extract_text(Content) ->
Item = hd(Content),
case element(1, Item) of
xmlText -> Item#xmlText.value;
_ -> ""
end.
analyze_info(WebData) ->
ToFind = [rate],
Parsed = element(1, xmerl_scan:string(WebData)),
Children = Parsed#xmlElement.content,
ElementList = [{El#xmlElement.name, extract_text(El#xmlElement.content)} || El <- Children, element(1, El) == xmlElement],
lists:map(fun(Item) -> lists:keyfind(Item, 1, ElementList) end, ToFind).
the above is the code im using to try to extract the contents of the tag from the url http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22GBPEUR%22)&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys.
here is what i do in the shell.
inets:start().
XML = scrapetest:get_currency().
scrapetest:analyze_info(XML).
and the return i get is simply "false". Im not sure what im doing wrong.
Just add some logs to your code.
Eg. adding io:format("~p~n", [ElementList]), - will show you that ElementList contains only result tag, and you should go one level deeper in your list comprehension to get tag named rate
This is common advice.
In your case, seems that better decision is recursive find function (if you want to write some code)
or use some batteries, like xmerl_xpath
Just example for another analyze_info :
analyze_info(WebData) ->
Parsed = element(1, xmerl_scan:string(WebData)),
xmerl_xpath:string("//Rate/text()", Parsed).
This will return:
[{xmlText,[{'Rate',2},{rate,1},{results,1},{query,1}],
1,[],"1.1813",text}]

Erlang record handling using filter

I have the following code to return a record from a list of records that has a field with value equal to Accountnumber.
lookup(AccountNumber, [#account{no=AccountNumber} = Rec | _]) ->
Rec;
lookup(AccountNumber, [_| T]) ->
lookup(AccountNumber, T);
lookup(AccountNumber, []) ->
not_found.
The above code works fine, but when I try to convert it to filter using the following code:
lookup(AccountNumber, DBRef) ->
lists:filter(fun(#account{no=AccountNumber} = Rec) -> Rec end, DBRef).
I got the following error:
** exception error: no case clause matching #account{no = 2,balance = 0,pin = undefined,name = "Ali",
transactions = []}
in function lists:'-filter/2-lc$^0/1-0-'/2 (lists.erl, line 1271)
What is the reason for the error?
There are multiple problems in the code
1.The filter should always return atom true or false for all list elements. This is causing you the error.
2.When the variable outside the fun block is used in fun header, they are not patterned matched, the variable outside is masked. Hence the pattern match fails.
You can see the modified code below.
lookup(AccountNumber, DBRef) ->
lists:filter(
fun(#account{no=AccNo}) when AccNo =:= AccountNumber -> true;
(_) -> false
end, DBRef).

Resources