Erlang matchspecs with tuple comparison - erlang

I want to use erlang datetime values in the standard format {{Y,M,D},{H,Min,Sec}} in a MNESIA table for logging purposes and be able to select log entries by comparing with constant start and end time tuples.
It seems that the matchspec guard compiler somehow confuses tuple values with guard sub-expressions. Evaluating ets:match_spec_compile(MatchSpec) fails for
MatchSpec = [
{
{'_','$1','$2'}
,
[
{'==','$2',{1,2}}
]
,
['$_']
}
]
but succeeds when I compare $2 with any non-tuple value.
Is there a restriction that match guards cannot compare tuple values?

I believe the answer is to use double braces when using tuples (see Variables and Literals section of http://www.erlang.org/doc/apps/erts/match_spec.html#id69408). So to use a tuple in a matchspec expression, surround that tuple with braces, as in,
{'==','$2',{{1,2}}}
So, if I understand your example correctly, you would have
22> M=[{{'_','$1','$2'},[{'==','$2',{{1,2}}}],['$_']}].
[{{'_','$1','$2'},[{'==','$2',{{1,2}}}],['$_']}]
23> ets:match_spec_run([{1,1,{1,2}}],ets:match_spec_compile(M)).
[{1,1,{1,2}}]
24> ets:match_spec_run([{1,1,{2,2}}],ets:match_spec_compile(M)).
[]
EDIT: (sorry to edit your answer but this was the easiest way to get my comment in a readable form)
Yes, this is how it must be done. An easier way to get the match-spec is to use the (pseudo) function ets:fun2ms/1 which takes a literal fun as an argument and returns the match-spec. So
10> ets:fun2ms(fun ({A,B,C}=X) when C == {1,2} -> X end).
[{{'$1','$2','$3'},[{'==','$3',{{1,2}}}],['$_']}]
The shell recognises ets:fun2ms/1. For more information see ETS documentation. Mnesia uses the same match-specs as ETS.

Related

F# function multiple return value

Curious about the syntax used in this example (https://learn.microsoft.com/en-us/dotnet/fsharp/get-started/get-started-command-line) within the file Library.js
My question, is the getJson function returning multiple values without a tuple?
Any link to F# documentation that explains this syntax would be nice. thanks.
open System.Text.Json
let getJson value =
let json = JsonSerializer.Serialize(value)
value, json
My question, is the getJson function returning multiple values without a tuple?
Yes to the first part, no to the second. The comma on the last line makes these two values a tuple.
You may think from online examples that a tuple is like (1, 2), but it’s just as fine to remove the parentheses if the expression is only on one line. In this case, value, json is the tuple.
Parentheses are used to disambiguate the order of evaluation. For instance, 1, “two”, “three” is a three-tuple of an int and two strings, but 1, (“two”, “three”) is a two-tuple of an int and the 2nd type being another two-tuple of two strings.
The Microsoft Learning link appears to always use parentheses in the examples. This post goes a little further, and has a bit more to say on tuple deconstruction as well: https://fsharpforfunandprofit.com/posts/tuples/.
Here’s more on parentheses (thanks Brent!): if it has a comma, it’s a tuple.

Unpacking table in a function call

Without giving too much details, this sample snippet demonstrates the problem:
-- Add an extra predefined argument
function one_more_arg(...)
local args = {...}
return function()
print(table.unpack(args), "c")
end
end
local my_new_print = one_more_arg("a", "b")
my_new_print() -- "a c"
Apparently unpacking a table does not work in this scenario. Any ideas on how to make this work, ie print will receive "a", "b", "c"? I'm trying to avoid modifying args, unless it's the only way to achieve it.
When you place table.unpack() as an argument to function there should be no other arguments or it should be the last one. Otherwise only first value from table will be passed.
Lua always adjusts the number of results from a function to the
circumstances of the call. When we call a function as a statement, Lua
discards all of its results. When we use a call as an expression, Lua
keeps only the first result. We get all results only when the call is
the last (or the only) expression in a list of expressions. These
lists appear in four constructions in Lua: multiple assignment,
arguments to function calls, table constructors, and return
statements.
From http://www.lua.org/pil/5.1.html
So you can try to put unpack at the end if it is ok for you:
print("c", table.unpack(args))
Or modify args.
table.concat (list [, sep [, i [, j]]])
Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string.

Simple explanation of Erlang atom

I am learning Erlang and stuck trying to understand the concept of atoms. I know Python: What is a good explanation of these "atoms" in simple terms, or analogously with Python. So far, my understanding is that the type is like a string but without string operations?
Docs say that:
An atom is a literal, a constant with name.
Sometimes you have couple of options, that you would like to choose from. In C for example, you have enum:
enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
In C, it is really an integer, but you can use it in code as one of options. Atoms in Erlang are very useful in pattern matching. Lets consider very simple server:
loop() ->
receive
{request_type_1, Request} ->
handle_request_1(Request),
loop();
{request_type_2, Request} ->
handle_request_2(Request),
loop();
{stop, Reason} ->
{ok, Reason};
_ ->
{error, bad_request}
end.
Your server receives messages, that are two element tuples and uses atoms to differentiate between different types of requests: request_type_1, request_type_2 and stop. It is called pattern matching.
Server also uses atoms as return values. ok atom means, that everything went ok. _ matches everything, so in case, that simple server receives something unexpected, it quits with tuple {error, Reason}, where the reason is also atom bad_request.
Boolean values true and false are also atoms. You can build logical functions using function clauses like this:
and(true, true) ->
true;
and(_, _) ->
false.
or(false, false) ->
false;
or(_, _) ->
true.
(It is a little bit oversimplified, because you can call it like this: or(atom1, atom2) and it will return true, but it is only for illustration.)
Module names in Erlang are also atoms, so you can bind module name to variable and call it, for example type this in Erlang shell:
io:format("asdf").
Variable = io.
Variable:format("asdf").
You should not use atoms as strings, because they are not garbage collected. If you start creating them dynamically, you can run out of memory. They should be only used, when there is fixed amount of options, that you type in code by hand. Of course, you can use the same atom as many times as you want, because it always points to the same point in memory (an atom table).
They are better than C enums, because the value is known at runtime. So while debugging C code, you would see 1 instead of Tuesday in debugger. Using atoms doesn't have that disadvantage, you will see tuesday in your both in your code and Erlang shell.
Also, they're often used to tag a tuple, for descriptiveness. For example:
{age, 42}
Rather than just
42
Atom is a literal constant. Has no value but can be used as a value. Examples are: true, false, undefined. If you want to use it as a string, you need to apply atom_to_list(atom) to get a string (list) to work with. Module names are also atoms.
Take a look at http://www.erlang.org/doc/reference_manual/data_types.html

Erlang function already defined with guard clauses

Writing a recursive function, I want one fn that executes when the list has elements and another when it is empty:
transfer(Master, [H|Tail]) ->
Master ! {transfer, H},
transfer(Master, Tail).
transfer(_Master, []) ->
nil.
The problem I'm getting is src/redis/redis_worker.erl:13: function transfer/2 already defined. I understand it is upset about two functions with the same name and arity, but these two should be different.
The problem is that clauses of a function need to be separated by a semicolon instead of a period.
transfer(Master, [H|Tail]) ->
Master ! {transfer, H},
transfer(Master, Tail); % use semicolon here, not period
transfer(_Master, []) ->
nil.
When you use a period to terminate the clause, the compiler considers that function's definition to be complete, so it sees your code as two separate functions instead of different clauses of the same function.
See the Erlang reference for Function Declaration Syntax for more details.
You need to use a semicolon instead of a colon to separate the two function clauses.

String splitting problems in Erlang

I've been playing around with the splitting of atoms and have a problem with strings. The input data will always be an atom that consists of some letters and then some numbers, for instance ms444, r64 or min1. Since the function lists:splitwith/2 takes a list the atom is first converted into a list:
24> lists:splitwith(fun (C) -> is_atom(C) end, [m,s,4,4,4]).
{[m,s],[4,4,4]}
25> lists:splitwith(fun (C) -> is_atom(C) end, atom_to_list(ms444)).
{[],"ms444"}
26> atom_to_list(ms444).
"ms444"
I want to separate the letters from the numbers and I've succeeded in doing that when using a list, but since I start out with an atom I get a "string" as result to put into my splitwith function...
Is it interpreting each item in the list as a string or what is going on?
You might want to have a look at the string module documentation:
http://www.erlang.org/doc/man/string.html
The following function might interest you:
tokens(String, SeparatorList) -> Tokens
Since strings in Erlang are just a list() of integer() the test in the fun will be made if the item is an atom() when it is in fact an integer(). If the test is changed to look for letters it works:
29> lists:splitwith(fun (C) -> (C >= $a) and (C =< $Z) end, atom_to_list(ms444)).
{"ms","444"}
An atom in erlang is a named constant and not a variable (or not like a variable is in an imperative language).
You should really not create atoms in dynamic fashion (that is, don't convert things to atoms at runtime)
They are used more in pattern matching and send recive code.
Pid ! {matchthis, X}
recive
{foobar,Y} -> doY(Y);
{matchthis,X} -> doX(X);
Other -> doother(Other)
end
A variable, like X could be set to an atom. For example X=if 1==1 -> ok; true -> fail end. I could suffer from poor imagination but I can't think of a way why you would like to parse atom. You should be in charge of what atoms you write and not use list_to_atom(CharIntegerList).
Can you perhaps give a more overview of what you like to accomplish?
A "string" in Erlang is not a primitive type: it is just a list() of integers(). So if you want to "separate" the letters from the digits, you'll have to do comparison with the integer representation of the characters.

Resources