How to convert this string "[{type,a},{to,room01023123},{body,hey what's up mister},{by,someone}]" into a tuple like this [{"type","a"},{"to","room01023123"},{"body","hey what's up mister"},{"by","someone"}]
If you need to read from file, just use file:consult
-spec consult(Filename) -> {ok, Terms} | {error, Reason}
Otherwise you can use erl_parse module combined with erl_scan for this. In the simplest case like this
{ok, Tokens, _Line} = erl_scan:string("{hello, world}."),
erl_parse:parse_term(Tokens).
And don't forget that terms should end with full stop.
Related
Erlang: what is the difference between [string()] and list() ??
I saw them as return types of ct_telnet:cmd and ct_ssh:exec ?
http://erlang.org/doc/man/ct_ssh.html
exec(SSH, Command, Timeout) -> {ok, Data} | {error, Reason}
Types:
Data = list()
http://erlang.org/doc/man/ct_telnet.html
cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}
Types:
Data = [string()]
The type list() stands for any list, without specifying the type of its elements. Another way to write it is [_] or [term()].
A string() is a special case of list(): it is a list containing integers representing Unicode code points (or Latin-1 characters, if less than 256, or ASCII characters, if less than 128). Another way to write string() is list(char()) or [char()].
A [string()] is a list of strings. This type can also be written as list(string()). Since it is a special case of a list, it is also valid (though less informative) to write it as list().
Formally there is no such type as "string" in Erlang, however strings are denoted using a list of codes. So essentially
String() -> [Positive_Integer()] (list of positive integers)
[String()] -> [[Positive_Integer()]] (list of list of positive integers)
where [] denotes a list.
Looking at Erlang docs, sometimes I come across type specs, that document a function type without really specifying the type...
Hard to explain, so let me give you an example. In the gen_server the handle_call function shows up as the following in the docs:
Request = term()
From = {pid(),Tag}
State = term()
Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}
| {reply,Reply,NewState,hibernate}
| {noreply,NewState} | {noreply,NewState,Timeout}
| {noreply,NewState,hibernate}
| {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
Reply = term()
NewState = term()
Timeout = int()>=0 | infinity
Reason = term()
Here the type Tag is never shown (i.e. it's just a variable name).
Is the same possible to do with edoc? The closest I found was opaque type spec, but that documents it as abstract - is that the same?
It is possible as long as the argument variable name in the function (in all clauses) and that name used in the #spec are same. For example.
%% #spec start_link(Args) -> {ok, pid()}
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
will generate the following doc
start_link(Args) -> {ok, pid()}
If you have a different name for example
%% #spec start_link(Args) -> {ok, pid()}
start_link(Num) when is_integer(Num) ->
gen_server:start_link(?MODULE, [], []);
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
It would generate as
start_link(Num::Args) -> {ok, pid()}
assuming Args as a type.
I would personally not recommend to use edoc #spec and instead use -spec as they are used by dialyzer and hence can be validated.
edoc can generate the doc from -spec too. Given both -spec and #spec, edoc overrides to #spec directive.
%% #spec start_link(Args) -> {ok, Pid}
-spec start_link(term()) -> {ok, pid()}.
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
Above will result in
start_link(Args) -> {ok, Pid}
And removing #spec from above will result in
start_link(Args::term()) -> {ok, pid()}
As far as I can see, this is not possible with Edoc.
I tried using a spec like this:
-spec foo(Something) -> term().
foo(X) ->
X.
And while Edoc is actually happy about it, and gives the type spec as foo(Something) in the docs without specifying what Something is, the compiler complains about it, and says:
type variable 'Something' is only used once (is unbound)
So you'd have to write:
-spec foo(Something::_) -> term().
foo(X) ->
X.
which shows up as foo(Something::term()), thereby giving a type specification for Something.
Using an Edoc-only type specification:
%% #spec foo(Something) -> term()
foo(X) ->
X.
Edoc treats Something as a type name that applies to the variable X and puts foo(X::Something) in the documentation.
So neither way would do exactly what you want to achieve.
What's correct Erlang way to have separated implementations from the contract and how to switch between them?
While others mention the behaviour feature, it is merely a small helper to make sure you implement all functions in a module for a callback structure. If you have two implementations, a and b, and both implements the same functions, you can just statically substitute a for b in a calling module. For static configuration where you have a better implementation, this is preferable.
If the question is of a more dynamic nature, you can just do
Mod = a,
Mod:f(Args).
And then in code set Mod appropriately. This lets you dynamically control what module to call while the program is running. It is not entirely clear which of the two you want.
Nice example of polymorphism is qlc module and structure table. See various M:table/1,2 implementations in ets, dets, mnesia and so. Try ets:table(ets:new(foo, [set])). in shell for example and look into qlc documentation and examples.
Since Erlang is dynamically typed, function guards (the when … -> bits) are the way to express polymorphism.
E.g:
len (T) when is_tuple(T) -> size(T);
len (L) when is_list(L) -> length(L).
Maybe have a look on behaviours concept. At least for me there is small similarity to OOP in terms of having interface definition and multiple implementation modules.
If I realized your question, here is example for approach, that pretty much works for me. This approach helps to separate interface and implementation.
"Interface" module.
-module(contract).
-export([
new/2,
do_something/2
]).
%% Behavioural callbacks definition. Each of "derived" modules should implement it.
-callback new(Arg :: any()) -> {ok, ImplState :: any()} | {error, Reason :: atom()}.
-callback do_something( Arg :: any(), ImplState :: any() ) -> {ok, ReturnVal :: any(), NewImplState :: any()} | {error, Reason :: atom()}.
%% Opaque state to hold implementation details
-record(
contract_impl, {
impl_module :: module(),
impl_state :: any()
}
).
%% Interface for creation "polymorphic" instance, like base-class constructor.
new(ImplModule, ImplInitArgs) ->
case ImplModule:new(ImplInitArgs) of
{ok, State} ->
{ok,
#contract_impl {
impl_module = ImplModule,
impl_state = State
}
};
{error, Reason} ->
{error, Reason}
end.
%% Interface function, like an abstract method in OOP.
do_something(
Arg,
#contract_impl {
impl_module = ImplModule,
impl_state = ImplState
} = ContractImpl
) ->
case ImplModule:do_something(Arg, ImplState) of
{ok, ReturnVal, NewState} ->
{ok, ReturnVal, ContractImpl#contract_impl{ impl_state = NewState }};
{error, Reason} -> {error, Reason}
end.
Some implementation example (like derived class).
-module(foo).
-behaviour(contract).
-export([
new/1,
do_something/2
]).
-record(
foo_state, {
repeat_count
}
).
new(Options) ->
{ok,
#foo_state{
repeat_count = proplists:get_value(repeat_count, Options)
}
}.
do_something(Arg, #foo_state{ repeat_count = RepeatCount } = State) ->
Result = [ io_lib:format("Foo ~p", [Arg]) || _Index <- lists:seq(1, RepeatCount) ],
{ok, Result, State}.
Now you can do the following:
usage_example() ->
{ok, State} = contract:new(foo, [{repeat_count, 15}]),
{ok, Result, NewState} = contract:do_something("bar", State),
ok.
I hope this helps.
I have a variable:
Data = [[<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]
I am trying to pattern match for two specific cases..
One where anything that resembles the outside structure - simply []
Anything inside goes I have tried [ _ ] but no go?
The Second, for a specific pattern inside, like when I see a <<"10">> or <<"112">> or <<"52">> then I am going to take the right side which is the actual data into an atom.
Basically the <<"10">> or <<"112">> or <<"52">> are the fields, the right side the data.
I have tried statements like [<<"10">>, _ ] still no go
Here is the rest of the code:
dataReceived(Message) ->
receive
{start} ->
ok;
[ _ ] -> %%No go
io:format("Reply 1 = ~p~n", [Message]);
[<<"10">>, _ ] -> %%No go
io:format("Reply 1 = ~p~n", [Message])
end.
As a note the Message is not sent as a tuple it is exactly like Data =
Can anyone lead me in the right direction?
Thanks and Goodnight!
-B
UPDATE
Ok now I think Im getting warmer, I have to pattern match whatever comes in.
So if I had say
Message = = [[<<>>],
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]
And I was looking to pattern match the field <<"112">>
Such as the 112 is always going to say 112, but the Gen2067 can change whenever to whatever.. its the data, it will be stored in a variable.
loop() ->
receive
[_,[<<"112">>, Data], _] when is_list(X) -> %% Match a list inside another.
?DEBUG("Got a list ~p~n", [X]),
loop();
_Other ->
?DEBUG("I don't understand ~p~n", [_Other]),
loop()
end.
I feel im close, but not 100%
-B
Update OP is trying to pass an argument to the function and not send messages.
As the name indicates the receive block is used to receive and process messages sent to a process. When you call dataReceived with an argument it proceeds to wait for messages. As no messages are sent it will continue to wait endlessly. Given the current code if you want it to do something then you'll have to spawn the function, get the process ID and then send a message to the process ID.
You probably need a function where the argument is pattern matched and not messages.
Something like this:
dataReceived([Message]) when is_list(Message) ->
io:format("Got a list as arg ~p~n", [Message]);
dataReceived(_Other) ->
io:format("Unknown arg ~p~n", [_Other]).
On a side note your third pattern [X] when is_list(X) will never match as the second pattern is a superset of the third. Anything that matches [X] when is_list(X) will always match [X] and therefore your third match clause will never get triggered.
Original Answer
I am not sure I understand your question. Are you trying to send a message to the function or are you passing it an argument?
This is a partial answer about how to match a list of lists in case you are sending a message.
-module(mtest).
-export([run/0]).
-ifdef(debug).
-define(DEBUG(Format, Args), io:format(Format, Args)).
-else.
-define(DEBUG(Format, Args), void).
-endif.
loop() ->
receive
[X] when is_list(X) -> %% Match a list inside another.
?DEBUG("Got a list ~p~n", [X]),
loop();
_Other ->
?DEBUG("I don't understand ~p~n", [_Other]),
loop()
end.
Take a look at the first clause in the receive block. [X] when is_list(X) will bind the inner list to the name X. I tested it with the value of Data you provided and it worked.
%% From the shell.
1> c(mtest, {d, debug}).
{ok,mtest}
2> Pid = mtest:run().
<0.40.0>
3> Data = [[<<>>, [<<"10">>,<<"171">>], [<<"112">>,<<"Gen20267">>], [<<"52">>,<<"20100812-06:32:30.687">>]]].
[[<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]]
4> Pid ! Data.
[[<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]]
Got a list [<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]
5>
I'm trying to get around a problem with file:consult/1 not allowing tuples with fun in them like in this example:
{add_one, fun(X) -> X+1 end}.
To get around this I'm considering writing the fun inside a string and evaluating it
{add_one, "fun(X) -> X+1 end"}.
The question is. How do I convert the string into a fun?
parse_fun_expr(S) ->
{ok, Ts, _} = erl_scan:string(S),
{ok, Exprs} = erl_parse:parse_exprs(Ts),
{value, Fun, _} = erl_eval:exprs(Exprs, []),
Fun.
Note that you need a period at the end of your fun expression, e.g. S = "fun(X) -> X + 1 end.".
file:script/1 almost does what you want - it evaluates a series of erlang expressions from a file and returns the last result. You could use it in place of file:consult/1 but you'd need to change the format of the file from "term. term. term." giving [term, term ,term] to "[term, term , term]." giving [term, term, term] - place a single expression in the file instead of a sequence.
I'd like to point out that Zed's answer creates an interpreted fun. When the fun is called it enters the evaluator which starts to evaluates the abstract syntax tree returned by erl_parse:parse_exprs/1 that it has captured. Looking at the fun created:
11> erlang:fun_info(Fun, env).
{env,[[],none,none,
[{clause,1,
[{var,1,'X'}],
[],
[{op,1,'+',{var,1,'X'},{integer,1,1}}]}]]}
12> erlang:fun_info(Fun, module).
{module,erl_eval}
One can see that it has closed over the parsed abstract syntax tree as seen in the env info, and it is a fun created inside erlang_eval as seen in the module info.
It is possible to use the erlang compiler to create a compiled module at runtime, and a pointer toward that is compile:forms/2 and code:load_binary/3. But the details of that should probably go into another stackoverflow question.
Maybe by using the erl_eval module?
2> F =fun(Str,Binding) ->
{ok,Ts,_} = erl_scan:string(Str),
Ts1 = case lists:reverse(Ts) of
[{dot,_}|_] -> Ts;
TsR -> lists:reverse([{dot,1} | TsR])
end,
{ok,Expr} = erl_parse:parse_exprs(Ts1),
erl_eval:exprs(Expr, Binding) end.
#Fun<erl_eval.12.111823515>
3> F("A=23.",[]).
{value,23,[{'A',23}]}
5> F("12+B.",[{'B',23}]).
{value,35,[{'B',23}]}