Error in erlang when using records - erlang

I have created a simple program that should simulate an address book:
%% API
-export([]).
-export([createAddressBook/0]).
-export([checkIfExist/3]).
-export([addContact/3]).
-record(entry,{nameAndSurname,n_phone,email}).
createAddressBook() ->
Test = #entry{nameAndSurname = {"Marcin", "Majewski"}, n_phone = [997], email=["call#call.tv"]},
[Test].
checkIfExist(_,_,[]) -> false;
checkIfExist(Name,Surname,[H|L]) ->
if
H#entry.nameAndSurname == {Name,Surname} -> true;
true -> checkIfExist(Name,Surname,L)
end.
addContact(Name,Surname,L)->
case checkIfExist(Name,Surname,L) of
true -> io:format("Entry already exist, nothing was created!");
_ -> newEntry = #entry{nameAndSurname = {Name,Surname}, n_phone = [],email = []},lists:append(L,newEntry)
end.
But when I invoke:
X=module_name:createAddressBook().
B=module_name:addContact("Name","Surname",X).
I am getting an error:
** exception error: no match of right hand side value
{entry,{"Name","Surname"},[],[]}
in function addContact
I do not understand what causes this problem.

You are tryin to assign record to atom:
newEntry = #entry{nameAndSurname = {Name,Surname}, n_phone = [],email = []},lists:append(L,newEntry)
Since newEntry starts from lowercase letter, erlang treats it as atom, but not variable. Just change it:
NewEntry = #entry{nameAndSurname = {Name,Surname}, n_phone = [],email]},
lists:append(L,NewEntry)

Related

XUnit/FsUnit framework throwing "Object reference not set to an instance of an objct"

I have written this simple test case for my code
module CustomerTests
open Xunit
open FsUnit
open MyProject.Customer
open MyProject.Customer.Domain
module ``When upgrading customer`` =
let customerVIP = {Id = 1; IsVip = true; Credit = 0.0M}
let customerSTD = {Id = 2; IsVip = false; Credit = 100.0M}
[<Fact>]
let ``should give VIP customer more credit`` () =
let expected = {customerVIP with Credit = customerVIP.Credit + 100.0M }
let actual = upgradeCustomer customerVIP
actual |> should equal expected
Very surprisingly this code fails with error
[xUnit.net 00:00:00.64] CustomerTests+When upgrading customer.should give VIP cstomer more credit [FAIL]
Failed CustomerTests+When upgrading customer.should give VIP cstomer more credit [3 ms]
Error Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
at CustomerTests.When upgrading customer.should give VIP cstomer more credit() in /Users/user/code/fsharp/CustomerProject/CustomerTests.fs:line 12
But line 12 is just a record being created so its not possible for that line to throw an Object reference not set to an instance of object. This is totally puzzling me.
In the dotnet fsi repl I can execute all my method and there is no object reference problem in my function which are being called from my tests here.
As this SO answer explains, XUnit loads the test in a way that skips initialization of those values. One easy fix is to use a class instead of a module:
type ``When upgrading customer``() =
let customerVIP = {Id = 1; isVip = true; Credit = 0.0M}
let customerSTD = {Id = 2; isVip = false; Credit = 100.0M}
[<Fact>]
let ``should give VIP cstomer more credit`` () =
let expected = {customerVIP with Credit = customerVIP.Credit + 100.0M }
let actual = upgradeCustomer customerVIP
actual |> should equal expected
That way, initialization of those values happens as it should.

In F#, how to update/replace a nested record using a list index?

(Totally Newbie).
Please assume the following in F#
module Visit =
type Model =
{ Name: string }
module Cell =
type Model =
{ Visit: Visit.Model option }
module Column =
type Model =
{ AppointmentCount: int
InnerRows: Cell.Model list }
module App =
...stuff with List.tryFind to return an open column ...
let AddVisit (c:Column.Model, v:Visit) =
{ c with c.InnerRows[AppointmentCount] = { c.InnerRows[AppointmentCount] with Visit = v } }
Assuming there will be 4 cells per column, the Visit is supplied by a database read, and the column instance is found through a couple of List.tryFind's, can a nested record (i.e., the visit of a cell) be replaced/updated with the AppointmentCount as an index?
That is, this fails:
let AddVisit (c:Column.Model, v:Visit) =
{ c with c.InnerRows[AppointmentCount] = { c.InnerRows[AppointmentCount] with Visit = v } }
Error: Field bindings must have the form 'id = expr,'
Thank you.
Take for instance a newly created record.
let myRecord2 = { MyRecord.X = 1; MyRecord.Y = 2; MyRecord.Z = 3 }
To update only two fields in that record you can use the copy and update record expression:
let myRecord3 = { myRecord2 with Y = 100; Z = 2 }
Copy and Update Record Expressions
let AddVisit (c:Column.Model, v:Visit) =
{ c.InnerRows.[c.AppointmentCount] with Visit = Some v }
Note that c.InnerRows.[c.AppointmentCount] specifies a specific cell.model to which the Visit will be set. (Also, the "." in front of the [ allows for direct indexing into the list.

Rewrite variable in Erlang

I am playing with records and list. Please, I want to know how to use one variable twice. When I assign any values into variable _list and after that I try rewrite this variable then raising error:
** exception error: no match of right hand side value
-module(hello).
-author("anx00040").
-record(car, {evc, type, color}).
-record(person, {name, phone, addresa, rc}).
-record(driver, {rc, evc}).
-record(list, {cars = [], persons = [], drivers = []} ).
%% API
-export([helloIF/1, helloCase/1, helloResult/1, helloList/0, map/2, filter/2, helloListCaA/0, createCar/3, createPerson/4, createDriver/2, helloRecords/0, empty_list/0, any_data/0, del_Person/1, get_persons/1, do_it_hard/0, add_person/2]).
createCar(P_evc, P_type, P_color) -> _car = #car{evc = P_evc, type = P_type, color = P_color}, _car
.
createPerson(P_name, P_phone, P_addres, P_rc) -> _person= #person{name = P_name, phone = P_phone, addresa = P_addres, rc = P_rc}, _person
.
createDriver(P_evc, P_rc) -> _driver = #driver{rc = P_rc, evc = P_evc}, _driver
.
empty_list() ->
#list{}.
any_data() ->
_car1 = hello:createCar("BL 4", "Skoda octavia", "White"),
_person1 = hello:createPerson("Eduard B.","+421 917 111 711","Kr, 81107 Bratislava1", "8811235"),
_driver1 = hello:createDriver(_car1#car.evc, _person1#person.rc),
_car2 = hello:createCar("BL 111 HK", "BMW M1", "Red"),
_person2 = hello:createPerson("Lenka M","+421 917 111 111","Krizn0, 81107 Bratislava1", "8811167695"),
_driver2 = hello:createDriver(_car2#car.evc, _person2#person.rc),
_car3 = hello:createCar("BL 123 AB", "Audi A1 S", "Black"),
_person3 = hello:createPerson("Stela Ba.","+421 918 111 711","Azna 20, 81107 Bratislava1", "8811167695"),
_driver3 = hello:createDriver(_car3#car.evc, _person3#person.rc),
_list = #list{
cars = [_car1,_car2,_car3],
persons = [_person1, _person2, _person3],
drivers = [_driver1, _driver2, _driver3]},
_list.
add_person(List, Person) ->
List#list{persons = lists:append([Person], List#list.persons) }.
get_persons(#list{persons = P}) -> P.
do_it_hard()->
empty_list(),
_list = add_person(any_data(), #person{name = "Test",phone = "+421Test", addresa = "Testova 20 81101 Testovo", rc =88113545}),
io:fwrite("\n"),
get_persons(add_person(_list, #person{name = "Test2",phone = "+421Test2", addresa = "Testova 20 81101 Testovo2", rc =991135455}))
.
But it raising error when i use variable _list twice:
do_it_hard()->
empty_list(),
_list = add_person(any_data(), #person{name = "Test",phone = "+421Test", addresa = "Testova 20 81101 Testovo", rc =88113545}),
_list =add_person(_list, #person{name = "Test2",phone = "+421Test2", addresa = "Testova 20 81101 Testovo2", rc =991135455}),
get_persons(_list)
.
In the REPL, it can be convenient to experiment with things while re-using variable names. There, you can do f(A). to have Erlang "forget" the current assignment of A.
1> Result = connect("goooogle.com").
{error, "server not found"}
2> % oops! I misspelled the server name
2> f(Result).
ok
3> Result = connect("google.com").
{ok, <<"contents of the page">>}
Note that this is only a REPL convenience feature. You can't do this in actual code.
In actual code, variables can only be assigned once. In a procedural language (C, Java, Python, etc), the typical use-case for reassignment is loops:
for (int i = 0; i < max; i++) {
conn = connect(servers[i]);
reply = send_data(conn);
print(reply);
}
In the above, the variables i, conn, and reply are reassigned in each iteration of the loop.
Functional languages use recursion to perform their loops:
send_all(Max, Servers) ->
send_loop(1, Max, Servers).
send_loop(Current, Max, _Servers) when Current =:= Max->
ok;
send_loop(Current, Max, Servers) ->
Conn = connect(lists:nth(Current, Servers)),
Reply = send_data(Conn),
print(Reply).
This isn't very idiomatic Erlang; I'm trying to make it mirror the procedural code above.
As you can see, I'm getting the same effect, but my assignments within a function are fixed.
As a side note, you are using a lot of variable names beginning with underscore. In Erlang this is a way of hinting that you will not be using the value of these variables. (Like in the above example, when I've reached the end of my list, I don't care about the list of servers.) Using a leading underscore as in your code turns off some useful compiler warnings and will confuse any other developers who look at your code.
In some situations it is convenient to use use SeqBind:
SeqBind is a parse transformation that auto-numbers all occurrences of these bindings following the suffix # (creating L#0, L#1, Req#0, Req#1) and so on.
Simple example:
...
-compile({parse_transform,seqbind}).
...
List# = lists:seq(0, 100),
List# = lists:filter(fun (X) -> X rem 2 == 0 end, List#)
...
I used google...
Erlang is a single-assignment language. That is, once a variable has been given a value, it cannot be given a different value. In this sense it is like algebra rather than like most conventional programming languages.
http://www.cis.upenn.edu/~matuszek/General/ConciseGuides/concise-erlang.html

Coffeescript loop simplifying

Sended data is Ruby format:
mob = {id: 1, xpos:100, ypos:150, xposDest:150, yposDest:100, attacked:0}
WebsocketRails[:channel_name].trigger(:event_name, mob)
How could i make this loop simpler? (it's coffeescript)
get_all_mobs: (mob) -> // getting "mob" with Websockets
mob_list[mob.id].id = mob.id
mob_list[mob.id].xpos = mob.xpos if mob.xpos?
mob_list[mob.id].ypos = mob.ypos if mob.ypos?
mob_list[mob.id].xposDest = mob.xposDest if mob.xposDest?
mob_list[mob.id].yposDest = mob.yposDest if mob.yposDest?
mob_list[mob.id].health = mob.health if mob.health?
mob_list[mob.id].level = mob.level if mob.level?
mob_list[mob.id].max_health = mob.max_health if mob.max_health?
mob_list[mob.id].attacked = mob.attacked if mob.attacked?
mob_list[mob.id].steps = mob.steps if mob.steps?
Was tryed something like this, but its wrong:
get_all_mobs: (mob) -> // getting "mob" with Websockets
for attribute in mob
mob_list[mob.id].attribute = mob.attribute
This should do:
get_all_mobs: (mob) -> // getting "mob" with Websockets
for own key, value of mob
mob_list[mob.id][key] = value if value?

Is there an easier way to modify a value in a subsubsub record field in Erlang?

So I've got a fairly deep hierarchy of record definitions:
-record(cat, {name = '_', attitude = '_',}).
-record(mat, {color = '_', fabric = '_'}).
-record(packet, {cat = '_', mat = '_'}).
-record(stamped_packet, {packet = '_', timestamp = '_'}).
-record(enchilada, {stamped_packet = '_', snarky_comment = ""}).
And now I've got an enchilada, and I want to make a new one that's
just like it except for the value of one of the subsubsubrecords.
Here's what I've been doing.
update_attitude(Ench0, NewState)
when is_record(Ench0, enchilada)->
%% Pick the old one apart.
#enchilada{stamped_packet = SP0} = Ench0,
#stamped_packet{packet = PK0} = SP0,
#packet{cat = Tag0} = PK0,
%% Build up the new one.
Tude1 = Tude0#cat{attitude = NewState},
PK1 = PK0#packet{cat = Tude1},
SP1 = SP0#stamped_packet{packet = PK1},
%% Thank God that's over.
Ench0#enchilada{stamped_packet = SP1}.
Just thinking about this is painful. Is there a better way?
As Hynek suggests, you can elide the temporary variables and do:
update_attitude(E = #enchilada{stamped_packet = (P = #packet{cat=C})},
NewAttitude) ->
E#enchilada{stamped_packet = P#packet{cat = C#cat{attitude=NewAttitude}}}.
Yariv Sadan got frustrated with the same issue and wrote Recless, a type inferring parse transform for records which would allow you to write:
-compile({parse_transform, recless}).
update_attitude(Enchilada = #enchilada{}, Attitude) ->
Enchilada.stamped_packet.packet.cat.attitude = Attitude.
Try this:
update_attitude(E = #enchilada{
stamped_packet = (SP = #stamped_packet{
packet = (P = #packet{
cat = C
})})}, NewState) ->
E#enchilada{
stamped_packet = SP#stamped_packet{
packet = P#packet{
cat = C#cat{
attitude = NewState
}}}}.
anyway, structures is not most powerful part of Erlang.

Resources