This question already has answers here:
Mnesia returns {aborted, no_transaction}
(2 answers)
Closed 10 years ago.
I have a table person which has this record :
-record(person, {id, firstname, lastname, address}).
I want to develop a function which will retreive the last id of this table
I try with this function :
get_userId() ->
Q = qlc:q([{X#person.id} || X <- mnesia:table(person)
]),
case do(Q) of
[{H}] ->
{ok, H};
[] ->
{error, notfound}
end.
And I do the test with this code
test()->
case get_userId() of
{ok, H}->io:format("~s~n",[H]);
[] ->
{error, notfound}
end.
but I have error when I make the test
2> model:test().
** exception error: no case clause matching [{238},
{82},
{76},
{257},
{141},
{2},
{315},
{336},
{275},
{88},
{326},
{211},
{81},
{333},
{351},
{214},
{64},
{265},
{210},
{90},
{302},
{98},
{212},
{197},
{194},
{132},
{226},
{3},
{...}|...]
in function model:get_userId/0
in call from model:test/0
The problem is that the value returned from do(Q) is a list containing many elements. You see them listed in the error report. However patterns which you match this value against only will match a list with one element, [{H}], the list with no elements, the empty list []. Therefore you get a case_clause error as none of the clauses match.
Related
I want to send all of the list content over TCP but i get some error
Code that send the list data
sendHistory(To, List) ->
lists:foreach(fun(#data{timestamp = T, data = D})->
gen_tcp:send(To, T),
gen_tcp:send(To, D)
end, List).
And I get this error.
Error in process <0.65.0> with exit value:
{function_clause,[{lists,foreach,
[#Fun<storage.0.129058542>,
{data,["1495971980"],
["\n\t",
["Jaam: ",
["Kuressaare linn"],
" Temperature: ",[]],
"\n\t",...]}],
[{file,"lists.erl"},{line,1337}]},
{storage,loop,4,[{file,"storage.erl"},{line,61}]}]}
The following line clause in your previous code is creating an improper list:
addToListIfNotAlreadyIn(New, [Old]) -> {[New | Old], ok};
You probably meant to write:
addToListIfNotAlreadyIn(New, [Old]) -> {[New, Old], ok};
The error message means that lists:foreach/2 was called with a second argument which was not a list. Since lists:foreach/2 recursively calls itself with the tail of the list after applying the function to the head, if an improper list is passed to the function, it will end up calling itself with a non-list argument on the last iteration:
1> lists:foreach(fun(X) -> ok end, [1, 2, 3 | 4]).
** exception error: no function clause matching lists:foreach(#Fun<erl_eval.6.118419387>,4) (lists.erl, line 1337)
I need to make an address book in Erlang. I have done almost everything except for one function that's giving me problems.
My record is:
-record(contact, {fname, lname, phone=[], mail=[], city=[], street=[]}).
I have to write a function that will search through instances of contact and find all with a particular city name, and for those instances return {fname,lname} tuples. Different contacts can of course have the same cities.
When I needed similar functions for the mail and phone fields I did it this way:
findByPhone(_,[]) -> {error,"not found"};
findByPhone(Phone,[H|T]) ->
case findPhoneForUser(Phone, H#contact.phone) of
true -> {H#contact.fname, H#contact.lname};
false -> findByPhone(Phone, T)
end.
findPhoneForUser(_,[]) -> false;
findPhoneForUser(Phone, [Phone|_]) -> true;
findPhoneForUser(Phone, [_|T]) -> findPhoneForUser(Phone, T).
But both mail and phone are unique values, so whenever one is found the function is finished. For city, a search can yield multiple return values, so it must collect all matches.
How to handle this problem? I thought about list comprehensions something like:
{X,Y} || X<-H#contact.fname, Y<-H#contact.lname, City=:=H#contact.city
but it will return tuples from single ASCII codes :/
You can use a list comprehension. Assuming your address book is stored in a variable named AddressBook, and the city you're matching is stored in a variable named City, the following will work:
[{C#contact.fname, C#contact.lname} || C <- AddressBook, C#contact.city == City].
Also note that you can simplify your findByPhone function using the lists:keyfind/3 function:
findByPhone(Phone, AddressBook) ->
case lists:keyfind(Phone, #contact.phone, AddressBook) of
#contact{fname=Fname, lname=Lname} -> {Fname, Lname};
false -> {error, not_found}
end.
This works because records are tuples under the covers. The construct #contact.phone used as the second argument to lists:keyfind/3 provides the element number of the phone field of the underlying tuple. In fact, you could write a single non-exported find function supporting any unique field in your record with this approach, and then write exported functions for each such searchable field:
find(Value, Field, AddressBook) ->
case lists:keyfind(Value, Field, AddressBook) of
#contact{fname=Fname, lname=Lname} -> {Fname, Lname};
false -> {error, not_found}
end.
findByPhone(Phone, AddressBook) -> find(Phone, #contact.phone, AddressBook).
findByMail(Mail, AddressBook) -> find(Mail, #contact.mail, AddressBook).
I'm trying to read a text file that contains a integer represented in ASCII (for example, "2446") and parse that into an integer in my Erlang/OTP program. string:to_integer/1 always returns {error, no_integer} when I try to parse "1". Perhaps I made a beginner's mistake. What am I doing wrong? Here's the relevant code, where I try to set Index to the integer:
Index = case file:read_file(Indexpath) of
{ok, Binary} ->
Index2 = case string:to_integer(io_lib:format("~s", [Binary])) of
{error, Reason} ->
io:format("to_integer error from input ~s: ~s~n", [Binary, Reason]),
0;
{Index3, _} -> Index3
end,
Index2;
{error, _} ->
Index2 = 0,
ok = file:write_file(Indexpath, io_lib:format("~B", [Index2+1])),
Index2;
_ ->
io:format("read_file case didn't match!~n", []),
-1
end,
What gets printed to the console when I run this: to_integer error from input 1: no_integer
Clearly, the input is the string "1", so I don't understand why this happens. If I do a little test case,
Indexstr = "4", string:to_integer(Indexstr).
that returns {4, []} as expected.
This is because io_lib:format/2 returns iolist (similar to deep list) instead of flat one. You can find iolist definition here.
Moreover, in new versions of erlang (starting from R16) you can use function `erlang:binary_to_integer/1' to avoid intermediate conversions.
Found the answer as I was typing the question. I replaced
string:to_integer(io_lib:format("~s", [Binary]))
with
string:to_integer(binary_to_list(Binary))
I have a table person with this record
-record(person, {id, firstname, lastname, phone}).
I want to update the phone of all records of this table
Itry with
test()->
Newphone ="216",
Update=#person{phone=Newphone} ,
Fun = fun() ->
List = mnesia:match_object(Update),
lists:foreach(fun(X) ->
mnesia:write_object(X)
end, List)
end,
mnesia:transaction(Fun).
The table person contains
12 alen dumas 97888888
15 franco mocci 55522225
13 ali othmani 44444449
I want that this table became like this :
12 alen dumas 216
15 franco mocci 216
13 ali othmani 216
I try with :
test()->
Newphone ="216",
Update=X#person{phone=Newphone, _ = '_'}
Fun = fun() ->
List = mnesia:match_object(Update),
lists:foreach(fun(X) ->
mnesia:write(X)
end, List)
end,
mnesia:transaction(Fun).
but with this code I have this error :
Variable X is unbound
this is related to this line :
Update=X#person{phone=Newphone, _ = '_'}
to resolve this probleme I do :
test()->
Newphone ="216",
Update=#person{phone=Newphone, _ = '_'}
Fun = fun() ->
List = mnesia:match_object(Update),
lists:foreach(fun(X) ->
mnesia:write(X)
end, List)
end,
mnesia:transaction(Fun).
when I test I have this message :
{atomic,ok}
but when I consult the database I find that the records are not changed
the difficulty in my code is to change all records of the table person
so change 97888888 and 55522225 and 44444449
this values should became 216
Continuing from what #legoscia has started. There are a couple of problems left with your code:
In the mnesia:match_object/1 call Update is being used as a pattern so when you set the phone field phone=NewPhone in Update you are actually saying to match_object give me all the records which have a phone of value "216". Which is not what you want.
You are writing back exactly the same record as you matched. You are not changing the record before writing it back.
A solution could be (untested):
test()->
Newphone ="216",
Match=#person{_ = '_'}, %Will match all records
Fun = fun() ->
List = mnesia:match_object(Match),
lists:foreach(fun(X) ->
%% Create new record with phone=NewPhone and write it back
Update = X#person{phone=NewPhone},
mnesia:write(Update)
end, List)
end,
mnesia:transaction(Fun).
Any fields you set in Match will limit which records you will match in match_object. For example Match = #person{phone="123",_='_'} will match all records which have phone "123".
A few things need changing here:
If you are going to use a record as a template for mnesia:match_object, you should fill in the record fields that you don't care about with the atom '_'. There is a special syntax to do that:
Update=#person{phone=Newphone, _ = '_'}
You probably don't want Newphone in there—the record that you pass to match_object should match the objects that are already in the table but should be changed, not what you want the objects to be changed to.
Which records are you trying to change? That will determine what you should pass to match_object.
The only thing you do in the transaction is reading records and writing them back unchanged. Have a look at the Records chapter of the Erlang reference manual; you probably want something like X#person{phone = Newphone} to change the phone field in X.
The function mnesia:write_object doesn't exist; you probably meant mnesia:write.
So I've been using Erlang for the last eight hours, and I've spent two of those banging my head against the keyboard trying to figure out the exception error my console keeps returning.
I'm writing a dice program to learn erlang. I want it to be able to call from the console through the erlang interpreter. The program accepts a number of dice, and is supposed to generate a list of values. Each value is supposed to be between one and six.
I won't bore you with the dozens of individual micro-changes I made to try and fix the problem (random engineering) but I'll post my code and the error.
The Source:
-module(dice2).
-export([d6/1]).
d6(1) ->
random:uniform(6);
d6(Numdice) ->
Result = [],
d6(Numdice, [Result]).
d6(0, [Finalresult]) ->
{ok, [Finalresult]};
d6(Numdice, [Result]) ->
d6(Numdice - 1, [random:uniform(6) | Result]).
When I run the program from my console like so...
dice2:d6(1).
...I get a random number between one and six like expected.
However when I run the same function with any number higher than one as an argument I get the following exception...
**exception error: no function clause matching dice2:d6(1, [4|3])
... I know I I don't have a function with matching arguments but I don't know how to write a function with variable arguments, and a variable number of arguments.
I tried modifying the function in question like so....
d6(Numdice, [Result]) ->
Newresult = [random:uniform(6) | Result],
d6(Numdice - 1, Newresult).
... but I got essentially the same error. Anyone know what is going on here?
This is basically a type error. When Result is a list, [Result] is a list with one element. E.g., if your function worked, it would always return a list with one element: Finalresult.
This is what happens (using ==> for "reduces to"):
d6(2) ==> %% Result == []
d6(2, [[]]) ==> %% Result == [], let's say random:uniform(6) gives us 3
d6(1, [3]) ==> %% Result == 3, let's say random:uniform(6) gives us 4
d6(0, [4|3]) ==> %% fails, since [Result] can only match one-element lists
Presumably, you don't want [[]] in the first call, and you don't want Result to be 3 in the third call. So this should fix it:
d6(Numdice) -> Result = [], d6(Numdice, Result). %% or just d6(Numdice, []).
d6(0, Finalresult) -> {ok, Finalresult};
d6(Numdice, Result) -> d6(Numdice - 1, [random:uniform(6) | Result]).
Lesson: if a language is dynamically typed, this doesn't mean you can avoid getting the types correct. On the contrary, it means that the compiler won't help you in doing this as much as it could.