Erlang Dynamic Record Editing - dynamic

I'm storing some data in mnesia, and I'd like to be able to change most of the values involved.
The naive
change(RecordId, Slot, NewValue) ->
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
NewRec = Rec#rec{Slot=NewValue},
F = fun() -> mnesia:write(NewRec) end,
{atomic, Val} = mnesia:transaction(F),
Val.
doesn't do it; the compiler complains that Slot is not an atom or _. Is there a way to express a general slot editing function as above, or am I going to be stuck defining a whole bunch of change_slots?
A marginally better approach is to pull out the insert and find pieces
atomic_insert(Rec) ->
F = fun() -> mnesia:write(Rec) end,
{atomic, Val} = mnesia:transaction(F),
Val.
find(RecordId) ->
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
Rec.
change(RecordId, name, NewValue) ->
Rec = find(RecordId),
NewRec = Rec#rec{name=NewValue},
atomic_insert(NewRec);
change(RecordId, some_other_property, NewValue) ->
Rec = find(RecordId),
NewRec = Rec#rec{some_other_property=NewValue},
...
but there's still a bit of code duplication there. Is there any way to abstract that pattern out? Is there an established technique to allow records to be edited? Any ideas in general?

Since records are represented by tuples, you could try using tuple operations to set individual values.
-module(rec).
-export([field_num/1, make_rec/0, set_field/3]).
-record(rec, {slot1, slot2, slot3}).
make_rec() ->
#rec{slot1=1, slot2=2, slot3=3}.
field_num(Field) ->
Fields = record_info(fields, rec),
DifField = fun (FieldName) -> Field /= FieldName end,
case length(lists:takewhile(DifField, Fields)) of
Length when Length =:= length(Fields) ->
{error, not_found};
Length ->
Length + 2
end.
set_field(Field, Value, Record) ->
setelement(field_num(Field), Record, Value).
set_field will return an updated record:
Eshell V5.9.1 (abort with ^G)
1> c(rec).
{ok,rec}
2> A = rec:make_rec().
{rec,1,2,3}
3> B = rec:set_field(slot3, other_value, A).
{rec,1,2,other_value}

You can also define change as a macro (especially if it used only inside the module):
-define(change(RecordId, Slot, NewValue),
begin
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
NewRec = Rec#rec{Slot=NewValue},
F = fun() -> mnesia:write(NewRec) end,
{atomic, Val} = mnesia:transaction(F),
Val
end).
Usage:
test(R, Id) ->
?change(Id, name, 5).
With macro you can also pass _ as a field (good for pattern matching).

Another way of using that a record is really a tuple would be:
change(RecordId, Index, NewValue) ->
[Rec] = do(qlc:q([X || X <- mnesia:table(rec), X#rec.id =:= RecordId])),
NewRec = setelement(Index, Rec, NewValue),
F = fun() -> mnesia:write(NewRec) end,
{atomic, Val} = mnesia:transaction(F),
Val.
which you could use like this:
5> Val = record:change(id58, #rec.name, new_value).
This is also a "clean" use of records as tuples as you are using the #rec.name syntax to find the index of the field in the tuple. It was the reason this syntax was added.

Related

Ensure same results from multiple calls to a ref

I call a function in a module to generate unique labels, eg.
MyMod.gensym
defined as
let gensym : string -> string =
let c = ref 0 in
fun s -> incr c; Printf.sprintf "!%s%d" s (!c)
But, I want to be able to get reproducible results at certain times from functions that use this gensym, eg.
let reproducible = SomeMod.call x
may return ["!a1"; "!a2"] the first time and ["!a3"; ...] the second
How can I ensure reproducible output in this case (eg. force ref to start from the same value), but without needing to change the implementation of gensym in its module?
You could add an optional argument to reset it:
let gensym : ?reset:bool -> string -> string =
let c = ref 0 in
fun ?(reset=false) s ->
if reset then
c := 1
else
incr c;
Printf.sprintf "!%s%d" s (!c)

Getting syntax error in ocaml

I am trying to make a module that would allow to create a table in ocaml. It would do a query called project to limit the table's values. However on the last line of the definition of the function chooser I am getting syntax error.
module type TABLE =
sig
type database
type table
val create_table: string list * string list* (string list) list -> table
val printTable : table -> string
val listToString : string list -> string
val project : string list * table -> table
val chooser : string list * string list-> string list
end;;
module UsingTable : TABLE =
struct
type table = (string list * string list* (string list) list)
type database = table list
let create_table (a,b,c) = (a,b,c)
let chooser inputList = (
for i = 0 to (List.length trueFalseList-1) do
if List.nth trueFalseList i = "True"
then
(List.nth inputList i)::ans
done
List.rev ans;;)
let project (conditions, aTable)= (
let rec innerProc tmp= function
n,[],v->List.rev tmp
|n,cH::cT,v-> if List.mem cH conditions
then innerProc (["True"]::tmp) (n,cT,v)
else innerProc (["False"]::tmp) (n,cT,v)
in
let trueFalseList = innerProc [] aTable
let rec finalListCreator = match aTable with
n,[],[]->n,[],[]
|n,cH::cT,[]->n,chooser cH ::finalListCreator cT,[]
|n,c,h::t -> n,c,chooser h ::finalListCreator t
)
let rec listToString aList = match aList with
[] -> ""
| h::t -> "\t"^h^"\t"^listToString t
let rec printTable aTable = match aTable with
[],[],[] -> ""
| [],[],vH::vT -> "\n"^(listToString vH)^printTable ([],[],vT)
| [],cH::cT,v -> "\t"^cH^"\t"^printTable([],cT, v)
| n, c , v-> "\n"^(List.hd n)^"\n\n"^printTable([],c, v)
end;;
let atable =UsingTable.create_table (["Student"], ["Id";"Name";"Gender";"Course"],
[["001";"Jim";"M";"AlgoDS"];
["002";"Linnea";"F";"Databases"];
["003";"Anna";"F";"C#"];
["004";"Abby";"F";"C#"];
["005";"Arthur";"M";"JavaScript"]]);;
print_string (UsingTable.printTable atable) ;;
These lines have at least two syntax problems:
let chooser inputList = (
for i = 0 to (List.length trueFalseList-1) do
if List.nth trueFalseList i = "True"
then
(List.nth inputList i)::ans
done
List.rev ans;;)
First, the for .. done is one expression, and List.rev ans is another expression. You need a semicolon (;) between them.
Second, you should use ;; only when you want the input up to that point to be processed. But here if you process the input at the ;; you are missing a right parenthesis.
In my opinion, you should be entering ;; only at the toplevel. The best way to think of this token is as an instruction to the toplevel. It's not part of normal OCaml syntax.
These are only the first two errors. There are quite a few other errors in the code. It might be good to add one function at a time to the module so you can concentrate on a few problems at a time.
Update
The environment you're using is a little bit extra complicated because it has an Evaluate button that asks to evaluate what you've typed so far. This makes the ;; token much less useful.
It would be a good discipline to use this environment without using the ;; token at all. Just click the Evaluate button when you want an evaluation.
The main trick is if you want to evaluate a statement (a unit-valued expression in OCaml) at the outer level, like say Printf.printf "hello world\n". The usual idiom to avoid putting ;; before this is to make it into a declaration like so:
let () = Printf.printf "hello world\n"
That is the one non-obvious idiom that people use when writing source code (where the ;; almost never appears in my experience).

F# Evaluate variables passed into functions as arguments (out of scope)

I'm working on a function that takes two arguments: a match value and a list of tuples. The goal is to match the first value (a string) in each tuple against the match value (also a string) and add the second value (an int) in those matching tuples to a new list, which is returned in sorted order. I started out with:
let getElems strMatch tupList =
let rec loop acc = function
| [] -> acc
| hd :: tl ->
match hd with
| (strMatch, v) -> loop (v :: acc) tl
| _ -> loop (acc) tl
List.sort (loop [] tupList)
...but came to realize that strMatch is out of scope as a pattern match so the second rule would never get matched. So I started trying to pass strMatch to the inner code blocks like so:
let getElems strMatch tupList =
let rec loop strMatch acc tupList =
match tupList with
| [] -> acc
| hd :: tl ->
match hd with
| (strMatch, v) -> loop strMatch (v :: acc) tl
| _ -> loop strMatch (acc) tl
List.sort (loop strMatch [] tupList)
...but the value is still out of scope in the match blocks. I suppose it would be possible to pass strMatch into those blocks but this seems messy and I'm wondering if there is a more elegant way.
EDIT: So here are my results...
First, I get the warning "This rule will never be matched." When I run the function as-is:
getElems "A" [("A",5);("BB",6);("AA",9);("A",0)];;
> val it : int list = [0; 5; 6; 9]
But if I hard code strMatch as "A" in the function:
getElems "A" [("A",5);("BB",6);("AA",9);("A",0)];;
> val it : int list = [0; 5]
Which is what is desired. But I'm required to take any match as an argument.

Generalizing functions in F#

I need a function that produces primes in F#. I found this:
let primesSeq =
let rec nextPrime n p primes =
if primes |> Map.containsKey n then
nextPrime (n + p) p primes
else
primes.Add(n, p)
let rec prime n primes =
seq {
if primes |> Map.containsKey n then
let p = primes.Item n
yield! prime (n + 1) (nextPrime (n + p) p (primes.Remove n))
else
yield n
yield! prime (n + 1) (primes.Add(n * n, n))
}
prime 2 Map.empty
This works very well, but sometimes I need to work with int64/BigInts as well. Is there a more clever way of reusing this code than providing another sequences like these:
let primesSeq64 = Seq.map int64 primesSeq
let primesBigInts = Seq.map (fun (x : int) -> BigInteger(x)) primesSeq
I've heard about modifying a code using "inline" and "LanguagePrimitives", but all I've found was connected with function while my problem is related to a value.
Moreover - I'd like to have a function that works with integer types and computes a floor of a square root.
let inline sqRoot arg = double >> Math.Sqrt >> ... ?
but I can't see a way of returning the same type as "arg" is, as Math.Sqrt returns a double. Again - is there anything better than reimplementing the logic that computes a square root by myself ?
So the general way to do this requires a function and languageprimitives - in your case everywhere you have 1 you write LanguagePrimitives.GenericOne which will produce 1 or 1.0 etc depending on what is required.
To get this to work, you need to create a function value - you can avoid this by doing something like:
let inline primesSeq() = ...
let primesintSeq = primesSeq() //if you use this as an int seq later the compiler will figure it out, otherwise you use
let specified : int seq = primesSeq()
I am not so sure about the sqrt case though - it probably depends on how hacky you are willing to make the solution.
A naïve implementation of generic sqRoot may go along these lines:
let sqRoot arg =
let inline sqrtd a = (double >> sqrt) a
let result = match box(arg) with
| :? int64 as i -> (sqrtd i) |> int64 |> box
| :? int as i -> (sqrtd i) |> int |> box
// cases for other relevant integral types
| _ -> failwith "Unsupported type"
unbox result
and then, checking in FSI:
> let result: int = sqRoot 4;;
val result : int = 2
> let result: int64 = sqRoot 9L;;
val result : int64 = 3L

Checking for equality in lists in SML

i want to write a function that checks for equality of lists in SML
for instance :
[1,2,3]=[1,2,3];
val it = true : bool
So instead of writing down the whole thing, i want to make a function that takes two predefined lists, and compare them, so that if list01 is [1,2,3] and list09 is [1,2,3]
then fun equal (list01, list09); will return -val it = true : bool;
You seem to be aware that = works on lists, so (as I already said in my comment) I don't see why you need to define an equal function.
That being said, you can just write:
fun equal (a, b) = (a = b);
Here is a not checked sample:
fun compare ([], []) = true # both empty
| compare (x::xs, y::ys) = (x = y) and compare(xs,ys)
| compare (_, _) = false # different lengths