Erlang Mnesia Select result not same as read, foldl - erlang

I have a situation with 3 use cases for returning data from an mnesia table
1. return all values of a table so I use a foldl,
2. return 1 row so I use read
3. return a variable number of records based on criteria so I use select.
I would like to use the same code to manage the results, but the select returns a different data structure. I am hoping someone can help me restructure my select to return the same as the others.
below is sample code of the issue and the results. The issue is the select does not return the record name for the table as does read and foldl.
-module(testselect2).
-export([runtest/0]).
-record(record_a, {b, c, d}).
-record(record_b, {record_a, e}).
-record(record_c, {record_b, f, intval}).
runtest() ->
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(record_c, [{attributes, record_info(fields, record_c)}]),
A1 = #record_a{b = "R1", c = "T1", d = "C1"},
B1 = #record_b{record_a = A1, e = "E1"},
C1 = #record_c{record_b = B1, f = "F1", intval = 100},
A2 = #record_a{b = "R2", c = "T2", d = "C2"},
B2 = #record_b{record_a = A2, e = "E2"},
C2 = #record_c{record_b = B2, f = "F2", intval = 200},
A3 = #record_a{b = "R3", c = "T3", d = "C3"},
B3 = #record_b{record_a = A3, e = "E3"},
C3 = #record_c{record_b = B3, f = "F3", intval = 300},
{atomic, Rw} = mnesia:transaction(
fun () ->
mnesia:write(C1),
mnesia:write(C2),
mnesia:write(C3)
end),
io:fwrite("Result write = ~w~n", [Rw]),
{atomic, Rr} = mnesia:transaction(
fun () ->
mnesia:read({record_c, B1})
end),
io:fwrite("Result read = ~w~n", [Rr]),
{atomic, Rf} =
mnesia:transaction(fun () ->
mnesia:foldl(fun (Rec, Acc) -> [Rec | Acc] end,
[],
record_c)
end),
io:fwrite("Result foldl = ~w~n", [Rf]),
MatchHead = #record_c{record_b='$1', f='$2', intval='$3'},
Guard = {'>', '$3', 100},
Result = {{'$1', '$2', '$3'}},
{atomic, Rs} = mnesia:transaction(
fun () ->
mnesia:select(record_c, [{MatchHead, [Guard], [Result]}])
end),
io:fwrite("Result select = ~w~n", [Rs]).
=====
RESULTS
44> testselect2:runtest().
Result write = ok
Result read = [{record_c,{record_b,{record_a,[82,49],[84,49],[67,49]},[69,49]},[70,49],100}]
Result foldl = [{record_c,{record_b,{record_a,[82,49],[84,49],[67,49]},[69,49]},[70,49],100},{record_c,{record_b,{record_a,[82,51],[84,51],[67,51]},[69,51]},[70,51],300},{record_c,{record_b,{record_a,[82,50],[84,50],[67,50]},[69,50]},[70,50],200}]
Result select = [{{record_b,{record_a,[82,51],[84,51],[67,51]},[69,51]},[70,51],300},{{record_b,{record_a,[82,50],[84,50],[67,50]},[69,50]},[70,50],200}]
ok
As you can see above read and foldl records start with {record_c,{... where select is missing the record_c and just has {{...
I have been unable to find a way to get select to return the same structure so my processing code can work for all 3 use cases. Any suggestions would be greatly appreciated.

I'm no mnesia expert, but I know when you use an ETS match expression, you determine what the result looks like. You use Result = {{'$1', '$2', '$3'}} to create your result terms, which makes them come out as three-tuples in a one-tuple, as we see in your output. Per ets:select/1, you want to use the special variable '$_' to return the whole matched object, so this should work in place of your Result = ... line:
Result = '$_',

Related

Get atoms of a Boolean formula in Z3

I was wondering if there is a method to get the atoms of a Boolean formula:
a = Bool('a')
b = Bool('b')
c = Bool('C')
d = Bool('D')
e = Bool('E')
f = Bool('F')
formula = And(Or(a, b), Or(c, d), Or(e, f))
I wonder if something like this exists:
formula.get_atoms() or get_atoms(formula)
to give me following desired output:
{A, B, C, D, E, F}
In pySMT, get_atoms() exists the provides the atoms. However, for some reason, I need to experiment on Z3.
You can traverse through the hierarchy of children() (documentation):
def atoms(expr):
a = set()
if not str(expr) in {'True', 'False'}:
c = expr.children()
if len(c):
for child in c:
a = a.union(atoms(child))
else:
a = {expr}
return a
a = Bool('a')
b = Bool('b')
c = Bool('C')
d = Bool('D')
e = Bool('E')
f = Bool('F')
formula = And(Or(a, b), Or(c, d), Or(e, f))
print(atoms(formula))

How to write a generic function that updates fields of a Record

Consider
type alias Rec = { a: Int, b: Int, c:Int }
updateRec r aVal = { r|a = aVal }
updateRec2 r aVal bVal = { r|a = aVal, b= bVal }
updateRec3 r aVal bVal cVal = ...
How to generalize updateRec and updateRec2... into one function?
Here's a better way of doing the same thing:
updateA : Int -> Rec -> Rec
updateA x rec = { rec | a = x }
-- Similarly for b, c
Now you can do the following, supposing you already have a value rec : Rec you want to update:
myUpdatedRec : Rec
myUpdatedRec =
rec
|> updateA 7
|> updateB 19
You can now update an arbitrary number of fields by stringing together |> updateX ....
You want to write a function that has a variable number of differently-typed parameters. That's common in dynamically typed languages (Javascript, Python, Ruby) but usually not allowed in typed languages. Elm doesn't allow it.
You can emulate a variable number of differently-typed parameterswith the Maybe type, understanding Nothing as "missing argument":
updateRec : Rec -> Maybe Int -> Maybe Int -> Maybe Int -> Rec
updateRec r a b c =
{ r
| a = a |> Maybe.withDefault r.a
, b = b |> Maybe.withDefault r.b
, c = c |> Maybe.withDefault r.c
}
If the record fields are all of the same type (here Int), you could accept a List Int instead:
updateRec : Rec -> List Int -> Rec
updateRec r fields =
case fields of
[a] -> { r | a = a }
[a,b] -> { r | a = a, b = b }
[a,b,c] -> { r | a = a, b = b, c = c }
_ -> r
I don't like this solution because you it'll fail silently if you accidentally supply a list with 0 or 4+ elements. If this function is helpful to you anyway, perhaps it would be better to use List Int instead of Rec in the first place.
Elm's record update syntax seems to be exactly what you are looking for. You "pass in" the record that you want updated, r below, and you can return a record with whatever fields you want changed without having to specify every field:
ex1 = { r|a = 1 }
ex2 = { r|b = 2, c = 3 }
You don't need to create a set of additional functions for updating only certain fields at certain times, because Elm's record update syntax is that generalized function.

searching in a list for a record with specific fields and ignoring the rest

I have a record defined as:
1> rd(fact, {a,b,c}).
fact
I create three records and put them in a list
2> F1 = #fact{a=1,b=1,c=1}.
#fact{a = 1,b = 1,c = 1}
(3> F2 = #fact{a=2,b=2,c=2}.
#fact{a = 2,b = 2,c = 2}
3> F3 = #fact{a=3,b=3,c=3}.
#fact{a = 3,b = 3,c = 3}
4> L = [F1,F2,F3].
[#fact{a = 1,b = 1,c = 1},
#fact{a = 2,b = 2,c = 2},
#fact{a = 3,b = 3,c = 3}]
Now, I want to check if the list contains a record in which 'a' is 1 and I don't care for the rest of the fields
(dilbert#Martin-PC)21> lists:member(#fact{a=1}, L).
false
(dilbert#Martin-PC)23> lists:member(#fact{a=1,b=1,c=1}, L).
true
How can I accomplish it?
Or you could use keyfind.
lists:keyfind(1, #fact.a, L).
Records are pure syntactic sugar. When you don't specify the values of the other fields in a record declaration the atom 'undefined' is used. Therefore your search is for:
#fact{a=1, b='undefined', c='undefined'}
... which of course doesn't exist.
Try this instead:
lists:any(fun(#fact{a=A}) -> A =:= 1 end, L).
Or list comprehension:
OneList = [E || E <- L, E#fact.a =:= 1]

Update list's values

I have the following setup:
1> rd(rec, {name, value}).
rec
2> L = [#rec{name = a, value = 1}, #rec{name = b, value = 2}, #rec{name = c, value = 3}].
[#rec{name = a,value = 1},
#rec{name = b,value = 2},
#rec{name = c,value = 3}]
3> M = [#rec{name = a, value = 111}, #rec{name = c, value = 333}].
[#rec{name = a,value = 111},#rec{name = c,value = 333}]
The elements in list L are unique based on their name. I also don't know the previous values of the elements in list M. What I am trying to do is to update list L with the values in list M, while keeping the elements of L that are not present in M. I did the following:
update_values([], _M, Acc) ->
Acc;
update_attributes_from_fact([H|T], M, Acc) ->
case [X#rec.value || X <- M, X#rec.name =:= H#rec.name] of
[] ->
update_values(T, M, [H|Acc]);
[NewValue] ->
update_values(T, M, [H#rec{value = NewValue}|Acc])
end.
It does the job but I wonder if there is a simpler method that uses bifs.
Thanks a lot.
There's no existing function that does this for you, since you just want to update the value field rather than replacing the entire record in L (like lists:keyreplace() does). If both L and M can be long, I recommend that if you can, you change L from a list to a dict or gb_tree using #rec.name as key. Then you can loop over M, and for each element in M, look up the correct entry if there is one and write back the updated record. The loop can be written as a fold. Even if you convert the list L to a dict first and convert it back again after the loop, it will be more efficient than the L*M approach. But if M is always short and you don't want to keep L as a dict in the rest of the code, your current approach is good.
Pure list comprehensions solution:
[case [X||X=#rec{name=XN}<-M, XN=:=N] of [] -> Y; [#rec{value =V}|_] -> Y#rec{value=V} end || Y=#rec{name=N} <- L].
little bit more effective using lists:keyfind/3:
[case lists:keyfind(N,#rec.name,M) of false -> Y; #rec{value=V} -> Y#rec{value=V} end || Y=#rec{name=N} <- L].
even more effective for big M:
D = dict:from_list([{X#rec.name, X#rec.value} || X<-M]),
[case dict:find(N,D) of error -> Y; {ok,V} -> Y#rec{value=V} end || Y=#rec{name=N} <- L].
but for really big M this approach can be fastest:
merge_join(lists:keysort(#rec.name, L), lists:ukeysort(#rec.name, M)).
merge_join(L, []) -> L;
merge_join([], _) -> [];
merge_join([#rec{name=N}=Y|L], [#rec{name=N, value=V}|_]=M) -> [Y#rec{value=V}|merge_join(L,M)];
merge_join([#rec{name=NL}=Y|L], [#rec{name=NM}|_]=M) when NL<NM -> [Y|merge_join(L,M)];
merge_join(L, [_|M]) -> merge_join(L, M).
You could use lists:ukeymerge/3:
lists:ukeymerge(#rec.name, M, L).
Which:
returns the sorted list formed by merging TupleList1 and TupleList2.
The merge is performed on the Nth element of each tuple. Both
TupleList1 and TupleList2 must be key-sorted without duplicates prior
to evaluating this function. When two tuples compare equal, the tuple
from TupleList1 is picked and the one from TupleList2 deleted.
A record is a tuple and you can use #rec.name to return the position of the key in a transparent way. Note that I reverted the lists L and M, since the function keeps the value from the first list.

F# elegance needed for Master-Detail scenario

The master-detail scenario. Been around forever. OK, if not forever, at least I was doing master-detail with FORTRAN on punch cards in the 70's. It's still around - plenty of master-detail questions here on STO.
I looked for a good way to do a master-detail recognizer in F#, didn't find it. Apologies if I missed it, and if so, can someone just reply with the sto thread or url? thanks
Here's my F#-newbie take on doing a master-detail recognizer in F#. That is: Reducing a raw/flat list of master-detail strings to a list of F#-records, where the master-strings are paired with their detail string-list.
Not looking for code golf here folks. Elegance. I had hoped to end up with something elegant, but the below is just a straight-forward recursive list walk. My F#-newbie brain failed to see how to make good use here of folds, comprehensions, fold-backs, maps, active patterns, computation expressions, etc.
Let's keep it to what can be done in F#. If there is a pre-built flat-file master-detail XML-data loader in .Net that makes master-detail .txt files into .Net XML in a one-line .Net call, that's quite interesting because it can be used in F#.
As someone with a long imperative programming history, I was trying to stick to immutable F# for practice. But if dipping into imperative or mutable code is really the best way for this in F#, please explain away. The output could be a list of tuples, a sequence of records, an array of tuples, etc.
Any comments/feedback.... thanks
let testInput =
["master Homer" ; "Doh.."; "Doh!!" ;
"master Has none" ;
"master JoyJoyJoy"; "Yaa!" ; "Yaa!!!"; "Yaa!!!!!!"]
type md = {m: string; d: string list}
member x.addDetail newd = {m = x.m; d = x.d # [newd]}
static member noMaster = {m = "" ; d = []} // master records can never be null-strings, so "" works here
static member isMaster (L:string) = L.StartsWith("master ")
static member isDetail (L:string) = not (md.isMaster L) // There is no third kind of record - if not a master then it is a detail
let rec masterDetails flatList currentMaster =
if md.noMaster = currentMaster then
match flatList with
| [] -> [] // If no master and no more input: input list was empty and the empty list is the overall result
| h :: t -> if md.isMaster h then // If no master, then head becomes the first master of the run
masterDetails t {m = h; d = []}
else
failwith "Bad input: First record must be a master record"
else
match flatList with
| [] -> [currentMaster] // End of input; return current master as a one-entry-list
| h :: t -> if md.isMaster h then // Head will now replace the current master as the new master
[currentMaster] # masterDetails t {m = h; d = []}
else // Keep current master; and add detail record to current master's detail list
masterDetails t (currentMaster.addDetail h)
let testSolution = // Required: 1) Preserve order of the master sets. 2) Preserve sort order of details-within-masters.
[{m = "master Homer" ; d = ["Doh.."; "Doh!!" ]};
{m = "master Has none" ; d = [ ]};
{m = "master JoyJoyJoy"; d = ["Yaa!"; "Yaa!!!"; "Yaa!!!!!!"]} ]
let tryIt = masterDetails testInput md.noMaster
let testTry = (tryIt = testSolution)
This sounds like a job for takeDrop.
// split a list into a prefix of elements that all
// meet predicate 'p', and the suffix remainder
let takeDrop p l =
let rec loop acc l =
match l with
| h::t when p h -> loop (h::acc) t
| _ -> List.rev acc, l
loop [] l
let rec masterDetail input =
[match input with
| [] -> ()
| h::t ->
assert(md.isMaster h)
let det, rest = takeDrop (not << md.isMaster) t
yield { m = h; d = det }
yield! masterDetail rest]
Full test code below.
let testInput =
["master Homer" ; "Doh.."; "Doh!!" ;
"master Has none" ;
"master JoyJoyJoy"; "Yaa!" ; "Yaa!!!"; "Yaa!!!!!!"]
type md = {m: string; d: string list}
static member isMaster (s:string) = s.StartsWith("master ")
let testSolution = // Required: 1) Preserve order of the master sets.
// 2) Preserve sort order of details-within-masters.
[{m = "master Homer" ; d = ["Doh.."; "Doh!!" ]};
{m = "master Has none" ; d = [ ]};
{m = "master JoyJoyJoy"; d = ["Yaa!"; "Yaa!!!"; "Yaa!!!!!!"]} ]
// split a list into a prefix of elements that all
// meet predicate 'p', and the suffix remainder
let takeDrop p l =
let rec loop acc l =
match l with
| h::t when p h -> loop (h::acc) t
| _ -> List.rev acc, l
loop [] l
let rec masterDetail input =
[match input with
| [] -> ()
| h::t ->
assert(md.isMaster h)
let det, rest = takeDrop (not << md.isMaster) t
yield { m = h; d = det }
yield! masterDetail rest]
let briSol = masterDetail testInput
printfn "%A" (briSol = testSolution)
As far as I know, there is no built-in function that would automatically split a list in this fashion. In the real-world, you would probably use a different representation of the data in the first place, so you wouldn't need to solve this problem (when loading data from XML, you'd already have hierarchical structure and when grouping data using LINQ, you'd also get hierarchical data). However, your function may still be needed, for example when loading data from a text-file.
Here is a slightly simpler version that uses sequence expression to generate the outer collection (of master-details records). The inner collection is accumulated in a parameter in the usual way:
let rec groupMasterDetails l acc master = seq {
match l with
// No master found yet, if the first element isn't master, we throw
| x::xs when not (md.isMaster x) && master = None ->
failwith "The first element must be master"
// Starting a new group, yield the previous group
| x::xs when md.isMaster x ->
if master <> None then yield { m = master.Value; d = List.rev acc }
yield! groupMasterDetails xs [] (Some x)
// Continue the current group
| x:: xs ->
yield! groupMasterDetails xs (x::acc) master
// End of processing, yield the last group
| [] ->
if master <> None then yield { m = master.Value; d = List.rev acc } }
let masterDetails l = l [] None
Note that the elements are accumulated in the reversed order (as opposed to using [el]#rest and then reversed, because this is a lot more efficient - using # involves copying of the entire list, so it is a bad practice to use it often). This also means that the implementation doesn't need your addDetail member.
However, this is still relatively long piece of code - I'm interested to see if this can be implemented by composing standard F# functions (I didn't find any good way to do this).
Here's an example, building off of Brain's answer, that takes separation too far however it does show the power of functional programming.
let takeDrop p l =
let rec loop acc l =
match l with
| h::t when p h -> loop (h::acc) t
| _ -> List.rev acc, l
loop [] l
let rec listSplit spliter neo l =
[match l with
| [] -> ()
| h::t ->
let det, rest = spliter t
yield neo h det
yield! listSplit spliter neo rest]
let masterDetail =
listSplit
(takeDrop (not << md.isMaster))
(fun h det -> { m = h; d = det })

Resources