Related
E.g. suppose I have a module named caller, and one of the functions defined therein contains this expression:
Callee:some_function(foo, Bar)
caller could try to catch function_clause, but how would caller know that it comes directly from Callee:some_function as opposed to some other function call (e.g. a call that Callee:some_function itself makes)?
You could catch function_clause errors with try-catch, and check if the stacktrace matches:
-module(foo).
-compile(export_all).
maybe_apply(Mod, Fun, Args) ->
try apply(Mod, Fun, Args)
catch
error:function_clause ->
case erlang:get_stacktrace() of
[{Mod, Fun, Args} | _] ->
{error, function_clause};
[{Mod, Fun, Args, _LineNumber} | _] ->
{error, function_clause};
Stacktrace ->
{error, other_function_clause, Stacktrace}
end
end.
Here is an example that shows how it distinguishes between a function clause error in lists:filter itself, and a function clause in a function called by lists:filter:
> foo:maybe_apply(lists, filter, [x, [1,2,3]]).
{error,function_clause}
> foo:maybe_apply(lists, filter, [fun(x) -> true end, [1,2,3]]).
{error,other_function_clause,
[{erl_eval,'-inside-an-interpreted-fun-',[1],[]},
{erl_eval,expr,3,[]}]}
You can use catch (callee:some_function(foo, Bar)) and analyse the error message if any:
1> catch (lists:filter(5,[1,2,3])).
{'EXIT',{function_clause,[{lists,filter,
[5,[1,2,3]],
[{file,"lists.erl"},{line,1283}]},
{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,
[{file,"shell.erl"},{line,624}]}]}}
2> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4}])).
[3,7]
3> catch(lists:map(fun ({X,Y}) -> X + Y end, [{1,2},{3,4,5}])).
{'EXIT',{function_clause,[{erl_eval,'-inside-an-interpreted-fun-',
[{3,4,5}],
[]},
{erl_eval,expr,3,[]}]}}
4>
4> catch(lists:map(fun ({X,Y}) -> X / Y end, [{1,2},{3,0}])).
{'EXIT',{badarith,[{erlang,'/',[3,0],[]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{lists,map,2,[{file,"lists.erl"},{line,1237}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
{shell,exprs,7,[{file,"shell.erl"},{line,684}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,639}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,624}]}]}}
5>
you can recognize the case that you are looking for because it has the form:
{'EXIT',{function_clause,[{callee,some_function,
[foo, Bar],
[{file,"callee.erl"},{line,LineNumber}]}|Stack]}}
Using Erlang, I have the following expression:
{add,{var,a},{mul,{num,2},{var,b}}}
and I am using lists:keymember to see whether the letter b is within the expression as such:
lists:keymember(b,2,[expr])
However, it doesn't look within the third tuple '{mul,{num,2},{var,b}' as that is a separate tuple. Is there a function that will search through the whole tuple and tuples within?
Thanks
As far I as I know there are no such functions. Probably you will have to implement some custom solution using recursion. Here is my example:
-module(test).
-compile(export_all).
find(_, []) -> false;
find(E, T) when is_tuple(T) ->
find(E, tuple_to_list(T));
find(E, [H|T]) ->
case find(E, H) of
false -> find(E, T);
true -> true
end;
find(V, E) -> V == E.
And usage:
1> test:find(b, {add,{var,a},{mul,{num,2},{var,b}}}).
true
2> test:find(b, {add,{var,a},{mul,{num,2},{var,c}}}).
false
Please review your code.
Line1: this is a tree, not a list.
Line2: expr is not a variable.
What you want to do is a visitor function, and you'll have to write it yourself.
A very good start would be to read this.
Two tables are related and I want to write function to delete all records in these two tables, but the output indicates that I can't do that. Is the low efficient choice to delete record one by one is the only available choice?
clear_gyne()->
R = execute_mnesia_transaction(
fun()->
mnesia:clear_table(bas_gyne),
mnesia:clear_table(bas_gyne_property)
end),
R.
execute_mnesia_transaction(TxFun) ->
%% Making this a sync_transaction allows us to use dirty_read
%% elsewhere and get a consistent result even when that read
%% executes on a different node.
%% case worker_pool:submit(
%% fun () ->
Result_a = case mnesia:is_transaction() of
false -> DiskLogBefore = mnesia_dumper:get_log_writes(),
Res = mnesia:sync_transaction(TxFun),
DiskLogAfter = mnesia_dumper:get_log_writes(),
case DiskLogAfter == DiskLogBefore of
true -> Res;
false -> {sync, Res}
end;
true -> mnesia:sync_transaction(TxFun)
end,
case Result_a of
{sync, {atomic, Result}} -> mnesia_sync:sync(), Result;
{sync, {aborted, Reason}} -> throw({error, Reason});
{atomic, Result} -> Result;
{aborted, Reason} -> throw({error, Reason})
end.
execute_mnesia_transaction is copied from rabbitmq project's source code.
The output is
bas_store:clear_gyne().
** exception throw: {error,{aborted,nested_transaction}}
in function bas_store:execute_mnesia_transaction/1 (src/bas_store.erl, line 29)
mnesia:clear_table/1 is categorized into schema transactions, so can not be nested in another transaction.
cf. mnesia:clear_table
http://erlang.org/pipermail/erlang-questions/2005-August/016582.html
How do I do the below, for example
A = atom_a,
case A of
atom_b or atom_c ->
%do something here;
atom a ->
%do something else!
end.
You can use guards:
A = 'atom_a',
case A of
B when B =:= 'atom_b'; B =:= 'atom_c' ->
%do something here;
'atom_a' ->
%do something else!
end.
Try the following:
case is_special_atom(A) of
true ->
%do something here;
false ->
%do something else!
end.
is_special_atom(atom_b) -> true;
is_special_atom(atom_c) -> true;
is_special_atom(_) -> false.
I am looking for a way to find tuples in a list in Erlang using a partial tuple, similarly to functors matching in Prolog. For example, I would like to following code to return true:
member({pos, _, _}, [..., {pos, 1, 2}, ...])
This code does not work right away because of the following error:
variable '_' is unbound
Is there a brief way to achieve the same effect?
For simple cases it's better to use already mentioned lists:keymember/3. But if you really need member function you can implement it yourself like this:
member(_, []) ->
false;
member(Pred, [E | List]) ->
case Pred(E) of
true ->
true;
false ->
member(Pred, List)
end.
Example:
>>> member(fun ({pos, _, 2}) -> true; (_) -> false end, [..., {pos, 1, 2}, ...]).
Use lists:keymember/3 instead.
You can do it with a macro using a list comprehension:
-define(member(A,B), length([0 || A <- B])>0).
?member({pos, _, _}, [{width, 17, 42}, {pos, 1, 2}, totally_irrelevant]).
It is not very efficient (it runs through the whole list) but it is the closest I can think to the original syntax.
If you want to actually extract the elements that match you just remove 'length' and add a variable:
-define(filter(A,B), [_E || A =_E <- B]).
You could do it using list comprehension:
Matches = [ Match || {Prefix, _, _} = Match <- ZeList, Prefix == pos].
Another possibility would be to do what match specs do and use the atom '_' instead of a raw _. Then, you could write a function similar to the following:
member(X, List) when is_tuple(X), is_list(List) ->
member2(X, List).
% non-exported helper functions:
member2(_, []) ->
false;
member2(X, [H|T]) when not is_tuple(H); size(X) =/= size(H) ->
member2(X, T);
member2(X, [H|T]) ->
case is_match(tuple_to_list(X), tuple_to_list(H)) of
true -> true;
false -> member2(X, T)
end.
is_match([], []) ->
true;
is_match(['_'|T1], [_|T2]) ->
is_match(T1, T2);
is_match([H|T1], [H|T2]) ->
is_match(T1, T2);
is_match(_, _) ->
false.
Then, your call would now be:
member({pos, '_', '_'}, [..., {pos, 1, 2}, ...])
This wouldn't let you match patterns like {A, A, '_'} (checking where the first two elements are identical), but if you don't need variables this should work.
You could also extend it to use variables using a similar syntax to match specs ('$1', '$2', etc) with a bit more work -- add a third parameter to is_match with the variable bindings you've seen so far, then write function clauses for them similar to the clause for '_'.
Granted, this won't be the fastest method. With the caveat that I haven't actually measured, I expect using the pattern matching in the language using a fun will give much better performance, although it does make the call site a bit more verbose. It's a trade-off you'll have to consider.
May use ets:match:
6> ets:match(T, '$1'). % Matches every object in the table
[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]]
7> ets:match(T, {'_',dog,'$1'}).
[[7],[5]]
8> ets:match(T, {'_',cow,'$1'}).
[]