I have a stack, I want to push a list into the stack. for eg.
comp:stack({push,[{{plus,{num,2},{num,2}}}]}, []).
It should then be stored in the stack, something like this
{{num,2},{num,2},plus} - for eg. push plus will go at bottom, then num2 will go top and the other num2 will go top of that prev num2.
Now I want to pop the whole list and get something like this
{{num,2},{num,2},plus}
Here is my code so far, all it does is push one and pop one at a time.
stack([],StackList) -> [];
stack({push,[H|T]},StackList) ->
{[H|T]++StackList}.
stack(pop,[StackH|StackT])-> {StackH,StackT}.
I am new to er lang, my explanation maybe horrendous to some. Please help me out, Thank you.
I think this should work for you:
stack({push, []}, StackList) -> StackList;
stack({push,[H|T]}, StackList) ->
stack({push, T}, [H | StackList]);
stack(pop,[StackH|StackT])-> {StackH,StackT}.
stack({push, _}, _) is called recursively for every element to be pushed.
Use example:
1> S0 = comp:stack({push, [plus,{num,2},{num,2}]}, []).
[{num,2},{num,2},plus]
2> {Reg1, S1} = comp:stack(pop, S0).
{{num,2},[{num,2},plus]}
3> {Reg2, S2} = comp:stack(pop, S1).
{{num,2},[plus]}
4> {Op, S3} = comp:stack(pop, S2).
{plus,[]}
5> Resault = comp:operation(Op, Reg1, Reg2). %% my guess
6> S4 = comp:stack({push, [Resault]}, S3).
...
It is up to you how you want to deal with errors in case of poping from empty stack.
The usage in erlang is to create a module dedicated to the management of data structure, and provide some interface to manipulate it. You will find example of this in the stdlib libraries: dict, lists, gb_trees ...
The way you will use is then: Stack = stack:new(), NewStack = stack:push(Value,Stack), {Value,NewStack} = stack:pop(Stack)... In the case of stack it is quite easy since the erlang list type fit to all usage of stack. You can then write a module:
-module(stack).
-export([new/0, push/2, is_empty/1]).
% add your own interfaces
new() -> [].
push(Value,Stack) when is_list(Stack) -> [Value|Stack].
is_empty([]) -> true;
is_empty(Stack) when is_list(Stack) -> false.
% and so on...
Related
Suppose I wanted to do something like:
dict
.values()
.map(fun scrub/1)
.flatMap(fun split/1)
.groupBy(fun keyFun/1, fun count/1)
.to_dict()
What is the most elegant way to achieve this in Erlang?
There is no direct easy way of doing that. All attempts I saw looked even worse than straightforward composition. If you will look at majority of open source project in Erlang, you will find that they use generic composition. Re-using your example:
to_dict(
groupBy(fun keyFun/1, fun count/1,
flatMap(fun split/1,
map(fun scrub/1,
values(dict))))).
This isn't a construct that's natural in Erlang. If you have a couple functions, regular composition is what I'd use:
lists:flatten(lists:map(fun (A) ->
do_stuff(A)
end,
generate_list())).
For a longer series of operations, intermediary variables:
Dict = #{hello => world, ...},
Values = maps:values(Dict),
ScrubbedValues = lists:map(fun scrub/1, Values),
SplitValues = lists:flatten(lists:map(fun split/1, ScrubbedValues)),
GroupedValues = basil_lists:group_by(fun keyFun/1, fun count/1, SplitValues),
Dict2 = maps:from_list(GroupedValues).
That's how it'd look if you wanted all of those operations grouped in one shot together.
However, I'd more likely write this in a different way:
-spec remap_values(map()) -> map().
remap_values(Map) ->
map_values(maps:values(Map)).
-spec map_values(list()) -> map().
map_values(Values) ->
map_values(Values, [], []).
-spec map_values(list(), list(), list()) -> map().
map_values([], OutList, OutGroup) ->
%% Base case: transform into a map
Grouped = lists:zip(OutGroup, OutList),
lists:foldl(fun ({Group, Element}, Acc = #{Group := Existing}) ->
Acc#{Group => [Element | Existing]};
({Group, Element}, Acc) ->
Acc#{Group => [Element]}
end,
#{},
Grouped;
map_values([First|Rest], OutList, OutGroup) ->
%% Recursive case: categorize process the first element and categorize the result
Processed = split(scrub(First)),
Categories = lists:map(fun categorize/1, Processed),
map_values(Rest, OutList ++ Processed, OutGroup ++ Categories).
The actual correct implementation depends a lot on how the code's going to be run -- what I've written here is pretty simple, but might not perform well on large amounts of data. If you're actually looking to process an endless stream of data you'll need to write that yourself (though you may find Gen Servers to be a very useful framework for doing so).
I have a list like this one ['a','b','c','d'] and what I need is to add a affix to each item in that list like : ['a#erlang','b#erlang','c#erlang','d#erlang']
I tried using 1lists:foreach1 and then concat two strings to one and then lists:append to the main list, but that didn't work for me.
Example of what I tried:
LISTa = [],
lists:foreach(fun (Item) ->
LISTa = lists:append([Item,<<"#erlang">>])
end,['a','b','c','d'])
Thanks in advance.
1> L = ['a','b','c','d'].
[a,b,c,d]
2> [ list_to_atom(atom_to_list(X) ++ "#erlang") ||X <- L].
[a#erlang,b#erlang,c#erlang,d#erlang]
Please try this code, you can use list_to_atom and atom_to_list.
This will do the trick (using list comprehensions):
1> L = ["a","b","c","d"].
["a","b","c","d"]
2> R = [X ++ "#erlang" || X <- L].
["a#erlang","b#erlang","c#erlang","d#erlang"]
3>
Notice that I changed the atoms for strings; It's discouraged to "create atoms on the fly/dynamically" in Erlang, so I have that framed in my mind. If you still need so, change the implementation a little bit and you are good to go.
NOTE: I'm assuming the concatenation between atoms and binaries is, somehow, something you did not do on purpose.
I am learning Erlang from a Ruby background and having some difficulty grasping the thought process. The problem I am trying to solve is the following:
I need to make the same request to an api, each time I receive a unique ID in the response which I need to pass into the next request until there is not ID returned. From each response I need to extract certain data and use it for other things as well.
First get the iterator:
ShardIteratorResponse = kinetic:get_shard_iterator(GetShardIteratorPayload).
{ok,[{<<"ShardIterator">>,
<<"AAAAAAAAAAGU+v0fDvpmu/02z5Q5OJZhPo/tU7fjftFF/H9M7J9niRJB8MIZiB9E1ntZGL90dIj3TW6MUWMUX67NEj4GO89D"...>>}]}
Parse out the shard_iterator..
{_, [{_, ShardIterator}]} = ShardIteratorResponse.
Make the request to kinesis for the streams records...
GetRecordsPayload = [{<<"ShardIterator">>, <<ShardIterator/binary>>}].
[{<<"ShardIterator">>,
<<"AAAAAAAAAAGU+v0fDvpmu/02z5Q5OJZhPo/tU7fjftFF/H9M7J9niRJB8MIZiB9E1ntZGL90dIj3TW6MUWMUX67NEj4GO89DETABlwVV"...>>}]
14> RecordsResponse = kinetic:get_records(GetRecordsPayload).
{ok,[{<<"NextShardIterator">>,
<<"AAAAAAAAAAFy3dnTJYkWr3gq0CGo3hkj1t47ccUS10f5nADQXWkBZaJvVgTMcY+nZ9p4AZCdUYVmr3dmygWjcMdugHLQEg6x"...>>},
{<<"Records">>,
[{[{<<"Data">>,<<"Zmlyc3QgcmVjb3JkISEh">>},
{<<"PartitionKey">>,<<"BlanePartitionKey">>},
{<<"SequenceNumber">>,
<<"49545722516689138064543799042897648239478878787235479554">>}]}]}]}
What I am struggling with is how do I write a loop that keeps hitting the kinesis endpoint for that stream until there are no more shard iterators, aka I want all records. Since I can't re-assign the variables as I would in Ruby.
WARNING: My code might be bugged but it's "close". I've never ran it and don't see how last iterator can look like.
I see you are trying to do your job entirely in shell. It's possible but hard. You can use named function and recursion (since release 17.0 it's easier), for example:
F = fun (ShardIteratorPayload) ->
{_, [{_, ShardIterator}]} = kinetic:get_shard_iterator(ShardIteratorPayload),
FunLoop =
fun Loop(<<>>, Accumulator) -> % no clue how last iterator can look like
lists:reverse(Accumulator);
Loop(ShardIterator, Accumulator) ->
{ok, [{_, NextShardIterator}, {<<"Records">>, Records}]} =
kinetic:get_records([{<<"ShardIterator">>, <<ShardIterator/binary>>}]),
Loop(NextShardIterator, [Records | Accumulator])
end,
FunLoop(ShardIterator, [])
end.
AllRecords = F(GetShardIteratorPayload).
But it's too complicated to type in shell...
It's much easier to code it in modules.
A common pattern in erlang is to spawn another process or processes to fetch your data. To keep it simple you can spawn another process by calling spawn or spawn_link but don't bother with links now and use just spawn/3.
Let's compile simple consumer module:
-module(kinetic_simple_consumer).
-export([start/1]).
start(GetShardIteratorPayload) ->
Pid = spawn(kinetic_simple_fetcher, start, [self(), GetShardIteratorPayload]),
consumer_loop(Pid).
consumer_loop(FetcherPid) ->
receive
{FetcherPid, finished} ->
ok;
{FetcherPid, {records, Records}} ->
consume(Records),
consumer_loop(FetcherPid);
UnexpectedMsg ->
io:format("DROPPING:~n~p~n", [UnexpectedMsg]),
consumer_loop(FetcherPid)
end.
consume(Records) ->
io:format("RECEIVED:~n~p~n",[Records]).
And fetcher:
-module(kinetic_simple_fetcher).
-export([start/2]).
start(ConsumerPid, GetShardIteratorPayload) ->
{ok, [ShardIterator]} = kinetic:get_shard_iterator(GetShardIteratorPayload),
fetcher_loop(ConsumerPid, ShardIterator).
fetcher_loop(ConsumerPid, {_, <<>>}) -> % no clue how last iterator can look like
ConsumerPid ! {self(), finished};
fetcher_loop(ConsumerPid, ShardIterator) ->
{ok, [NextShardIterator, {<<"Records">>, Records}]} =
kinetic:get_records(shard_iterator(ShardIterator)),
ConsumerPid ! {self(), {records, Records}},
fetcher_loop(ConsumerPid, NextShardIterator).
shard_iterator({_, ShardIterator}) ->
[{<<"ShardIterator">>, <<ShardIterator/binary>>}].
As you can see both processes can do their job concurrently.
Try from your shell:
kinetic_simple_consumer:start(GetShardIteratorPayload).
Now your see that your shell process turns to consumer and you will have your shell back after fetcher will send {ItsPid, finished}.
Next time instead of
kinetic_simple_consumer:start(GetShardIteratorPayload).
run:
spawn(kinetic_simple_consumer, start, [GetShardIteratorPayload]).
You should play with spawning processes - it's erlang main strength.
In Erlang, you can write loop using tail recursive functions. I don't know the kinetic API, so for simplicity, I just assume, that kinetic:next_iterator/1 return {ok, NextIterator} or {error, Reason} when there are no more shards.
loop({error, Reason}) ->
ok;
loop({ok, Iterator}) ->
do_something_with(Iterator),
Result = kinetic:next_iterator(Iterator),
loop(Result).
You are replacing loop with iteration. First clause deals with case, where there are no more shards left (always start recursion with the end condition). Second clause deals with case, where we got some iterator, we do something with it and call next.
The recursive call is last instruction in the function body, which is called tail recursion. Erlang optimizes such calls - they don't use call stack, so they can run infinitely in constant memory (you will not get anything like "Stack level too deep")
I work in erlang
Now, I have a big problem
I want to have a log from a table mnesia and this log should be write in excel file
So the goal is write data from table mnesia to the excel file
I think and this is related to some code find in this forum that the best way is to write .txt file then transfer data from .txt file to excel file
I find this code in this forum in this link.
exporttxt()->
F = fun(T) -> mnesia:foldl(fun(X,Acc) -> [X|Acc] end, [],T) end,
{atomic,L} = mnesia:transaction(F(user)),
file:write_file("test.txt",[io_lib:format("~p\t~p\t~p~n",[F1,F2,F3]) ||
#user{id = F1,adress = F2,birthday = F3} <- L]).
But this code produces an error
As commented, the problem is clearly explained in the link itself. If you want the code then here it is. But please understand before directly jumping into the code.
exporttxt()->
F = fun() -> mnesia:foldl(fun(X,Acc) -> [X|Acc] end, [],user) end,
{atomic,L} = mnesia:transaction(F),
file:write_file("test.txt",[io_lib:format("~p\t~p\t~p~n",[F1,F2,F3]) ||
#user{id = F1,adress = F2,birthday = F3} <- L]).
in the subject you mention, I said that I didn't test the code, and of course there was a syntax error.
Here is a code that run.
1> ok = mnesia:create_schema([node()]).
ok
2> rd(my_user,{firstname,lastname,age}).
my_user
3> ok =application:start(mnesia).
ok
4> {atomic,ok} = mnesia:create_table(my_user,[{attributes,record_info(fields,my_user)},{disc_copies,[node()]},{type,bag}]).
{atomic,ok}
5> Add_user = fun(Fn,Ln,Ag) ->
5> F = fun() -> mnesia:write(my_user,#my_user{firstname=Fn,lastname=Ln,age=Ag},write) end,
5> mnesia:activity(transaction,F)
5> end.
#Fun<erl_eval.18.82930912>
6> ok = Add_user("Georges","Boy",25).
ok
7> ok = Add_user("Joe","Armstrong",52).
ok
8> ok = Add_user("Pascal","Me",55).
ok
9> F = fun(T) -> mnesia:foldl(fun(X,Acc) -> [X|Acc] end, [],T) end.
#Fun<erl_eval.6.82930912>
10> {atomic,L} = mnesia:transaction(F,[my_user]).
{atomic,[#my_user{firstname = "Pascal",lastname = "Me",
age = 55},
#my_user{firstname = "Joe",lastname = "Armstrong",age = 52},
#my_user{firstname = "Georges",lastname = "Boy",age = 25}]}
11> ok = file:write_file("test.txt",[io_lib:format("~p\t~p\t~p~n",[F1,F2,F3]) || #my_user{firstname = F1, lastname = F2, age = F3} <- L]).
ok
12>
you will have in your working directory a file named test.txt containing
"Pascal" "Me" 55
"Joe" "Armstrong" 52
"Georges" "Boy" 25
and if you open it with excel you will get
But this is not a code sequence you should use directly.
line 1 should take place in a code use for the deployment of your application.
line 2 is a record definition, necessary for the shell to understand the next lines. It should be replaced by a -record(...) in a module or an included file.
lines 3 and 4 should take place in the init function of one of the higher level supervisor (with some test to check already started application, existing table...)
line 5 should be in the interface definition of a server
line 6,7,8 should be generated by a user interface in some client
and last line 9,10,11 in another interface (for admin?).
Message to Lost_with_coding and his fellows,
If I may give you my opinion, you are burning steps. You should focus on mastering the Erlang syntax, the concept of pattern matching and variable bounding... after you should look at more advance construction such as list and binary comprehensions. Take time to look at error messages and use them to solve simple problems. The official Erlang documentation is great for this purpose. I always have it open in my browser and sometimes I also use this link http://erldocs.com/R15B/ when I look for function I don't know.
Next will come higher order functions, error handling, processes, concurrency, OTP... plus the usage of the efficient but not sexy Erlang tools (tv, appmon, debugger...).
I recommend it very often, but use the fantastic Fred Hebert's web site http://learnyousomeerlang.com/ and follow it step by step, rewriting the code, not copy/paste; it really worths the effort.
In most applications, its hard to avoid the need to query large amounts of information which a user wants to browse through. This is what led me to cursors. With mnesia, cursors are implemented using qlc:cursor/1 or qlc:cursor/2. After working with them for a while and facing this problem many times,
11> qlc:next_answers(QC,3).
** exception error: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
in function qlc:next_loop/3 (qlc.erl, line 1359)
12>
It has occured to me that the whole cursor thing has to be within one mnesia transaction: executes as a whole once. like this below
E:\>erl
Eshell V5.9 (abort with ^G)
1> mnesia:start().
ok
2> rd(obj,{key,value}).
obj
3> mnesia:create_table(obj,[{attributes,record_info(fields,obj)}]).
{atomic,ok}
4> Write = fun(Obj) -> mnesia:transaction(fun() -> mnesia:write(Obj) end) end.
#Fun<erl_eval.6.111823515>
5> [Write(#obj{key = N,value = N * 2}) || N <- lists:seq(1,100)],ok.
ok
6> mnesia:transaction(fun() ->
QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
Ans = qlc:next_answers(QC,3),
io:format("\n\tAns: ~p~n",[Ans])
end).
Ans: [{obj,20,40},{obj,21,42},{obj,86,172}]
{atomic,ok}
7>
When you attempt to call say: qlc:next_answers/2 outside a mnesia transaction, you will get an exception. Not only just out of the transaction, but even if that method is executed by a DIFFERENT process than the one which created the cursor, problems are bound to happen.
Another intresting finding is that, as soon as you get out of a mnesia transaction, one of the processes which are involved in a mnesia cursor (apparently mnesia spawns a process in the background), exits, causing the cursor to be invalid. Look at this below:
-module(cursor_server).
-compile(export_all).
cursor(Q)->
case mnesia:is_transaction() of
false ->
F = fun(QH)-> qlc:cursor(QH,[]) end,
mnesia:activity(transaction,F,[Q],mnesia_frag);
true -> qlc:cursor(Q,[])
end.
%% --- End of module -------------------------------------------
Then in shell, i use that method:
7> QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])).
{qlc_cursor,{<0.59.0>,<0.30.0>}}
8> erlang:is_process_alive(list_to_pid("<0.59.0>")).
false
9> erlang:is_process_alive(list_to_pid("<0.30.0>")).
true
10> self().
<0.30.0>
11> qlc:next_answers(QC,3).
** exception error: {qlc_cursor_pid_no_longer_exists,<0.59.0>}
in function qlc:next_loop/3 (qlc.erl, line 1359)
12>
So, this makes it very Extremely hard to build a web application in which a user needs to browse a particular set of results, group by group say: give him/her the first 20, then next 20 e.t.c. This involves, getting the first results, send them to the web page, then wait for the user to click NEXT then ask qlc:cursor/2 for the next 20 and so on. These operations cannot be done, while hanging inside a mnesia transaction !!! The only possible way, is by spawning a process which will hang there, receiving and sending back next answers as messages and receiving the next_answers requests as messages like this:
-define(CURSOR_TIMEOUT,timer:hours(1)).
%% initial request is made here below
request(PageSize)->
Me = self(),
CursorPid = spawn(?MODULE,cursor_pid,[Me,PageSize]),
receive
{initial_answers,Ans} ->
%% find a way of hidding the Cursor Pid
%% in the page so that the subsequent requests
%% come along with it
{Ans,pid_to_list(CursorPid)}
after ?CURSOR_TIMEOUT -> timedout
end.
cursor_pid(ParentPid,PageSize)->
F = fun(Pid,N)->
QC = cursor_server:cursor(qlc:q([XX || XX <- mnesia:table(obj)])),
Ans = qlc:next_answers(QC,N),
Pid ! {initial_answers,Ans},
receive
{From,{next_answers,Num}} ->
From ! {next_answers,qlc:next_answers(QC,Num)},
%% Problem here ! how to loop back
%% check: Erlang Y-Combinator
delete ->
%% it could have died already, so we be careful here !
try qlc:delete_cursor(QC) of
_ -> ok
catch
_:_ -> ok
end,
exit(normal)
after ?CURSOR_TIMEOUT -> exit(normal)
end
end,
mnesia:activity(transaction,F,[ParentPid,PageSize],mnesia_frag).
next_answers(CursorPid,PageSize)->
list_to_pid(CursorPid) ! {self(),{next_answers,PageSize}},
receive
{next_answers,Ans} ->
{Ans,pid_to_list(CursorPid)}
after ?CURSOR_TIMEOUT -> timedout
end.
That would create a more complex problem of managing process exits, tracking / monitoring e.t.c. I wonder why the mnesia implementers didnot see this !
Now, that brings me to my questions. I have been walking around the web for solutions and you could please check out these links from which the questions arise: mnemosyne, Ulf Wiger's Solution to Cursor Problems, AMNESIA - an RDBMS implementation of mnesia.
1. Does anyone have an idea on how to handle mnesia query cursors in a different way from what is documented, and is worth sharing ?
2. What are the reasons why mnesia implemeters decided to force the cursors within a single transaction: even the calls for the next_answers ?
3. Is there anything, from what i have presented, that i do not understand clearly (other than my bad buggy illustration code - please ignore those) ?
4. AMNESIA (on section 4.7 of the link i gave above), has a good implementation of cursors, because the subsequent calls for the next_answers, do not need to be in the same transaction, NOR by the same process. Would you advise anyone to switch from mnesia to amnesia due to this and also, is this library still supported ?
5. Ulf Wiger , (the author of many erlang libraries esp. GPROC), suggests the use of mnesia:select/4. How would i use it to solve cursor problems in a web application ? NOTE: Please do not advise me to leave mnesia and use something else, because i want to use mnesia for this specific problem. I appreciate your time to read through all this question.
The motivation is that transaction grabs (in your case) read locks.
Locks can not be kept outside of transactions.
If you want, you can run it in a dirty_context, but you loose the
transactional properties, i.e. the table may change between invocations.
make_cursor() ->
QD = qlc:sort(mnesia:table(person, [{traverse, select}])),
mnesia:activity(async_dirty, fun() -> qlc:cursor(QD) end, mnesia_frag).
get_next(Cursor) ->
Get = fun() -> qlc:next_answers(Cursor,5) end,
mnesia:activity(async_dirty, Get, mnesia_frag).
del_cursor(Cursor) ->
qlc:delete_cursor(Cursor).
I think this may help you :
use async_dirty instead of transaction
{Record,Cont}=mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read])
then read next Limit number of records:
mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])
full code:
-record(md,{id,name}).
batch_delete(Id,Limit) ->
Match_head = #md{id='$1',name='$2'},
Guard = {'<','$1',Id},
Result = '$_',
{Record,Cont} = mnesia:activity(async_dirty, fun mnesia:select/4,[md,[{Match_head,[Guard],[Result]}],Limit,read]),
delete_next({Record,Cont}).
delete_next('$end_of_table') ->
over;
delete_next({Record,Cont}) ->
delete(Record),
delete_next(mnesia:activity(async_dirty, fun mnesia:select/1,[Cont])).
delete(Records) ->
io:format("delete(~p)~n",[Records]),
F = fun() ->
[ mnesia:delete_object(O) || O <- Records]
end,
mnesia:transaction(F).
remember you can not use cursor out of one transaction