How to update record value in SML?SML-NJ, how to compile standalone executableSML function on record listUsing fold in SMLSML Value Restriction - HeapConvert a Haskell function to SMLSML record subset and updateInterpreting []::[], []::[]::[] in smlUpdating a list of 2-tuples in SMLHow to pattern match 0.0 in SML?How to have function returned value in a SML record
Which is the common name of Mind Flayers?
Binary Search in C++17
How can I specify the last parameters in a function call and let the others default to the DEFAULT in the declaration?
Is real public IP Address hidden when using a system wide proxy in Windows 10?
What are the real benefits of using Salesforce DX?
What is quasi-aromaticity?
Employer asking for online access to bank account - Is this a scam?
Why do Ryanair allow me to book connecting itineraries through a third party, but not through their own website?
Why colon to denote that a value belongs to a type?
Boss wants me to falsify a report. How should I document this unethical demand?
Is there an efficient way to replace text matching the entire content of one file with the entire content of another file?
Where is the logic in castrating fighters?
Is this resistor leaking? If so, is it a concern?
A steel cutting sword?
Why does Mjolnir fall down in Age of Ultron but not in Endgame?
Cipher Block Chaining - How do you change the plaintext of all blocks?
Would Brexit have gone ahead by now if Gina Miller had not forced the Government to involve Parliament?
Adding spaces to string based on list
Count rotary dial pulses in a phone number (including letters)
Writing with dry erase marker on Shabbos, is it permitted?
Looking for a soft substance that doesn't dissolve underwater
Computing the matrix powers of a non-diagonalizable matrix
Why did David Cameron offer a referendum on the European Union?
Should I disclose a colleague's illness (that I should not know) when others badmouth him
How to update record value in SML?
SML-NJ, how to compile standalone executableSML function on record listUsing fold in SMLSML Value Restriction - HeapConvert a Haskell function to SMLSML record subset and updateInterpreting []::[], []::[]::[] in smlUpdating a list of 2-tuples in SMLHow to pattern match 0.0 in SML?How to have function returned value in a SML record
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I am writing SML program to update records in a list.For example, I have type person_name.
type person_name = fname:string, lname:string, mname:string
Then I have person_bio which has person_name embedded in it.
type person_bio = age:real, gender:string, name:person_name, status:string
Next I have employee which has person_bio.
type employee = p:person_bio, payrate:real, whours:real list;
Now, I have to define function 'updateLastName' by passing the first name.
As of now, created one record 'e1' with below data.
p=age=40.0,gender="M",namefname="rob",lname="sen",mname="",status="M",
payrate=30.0,whours=10.0
But I am facing challenge to traverse the list and then updating one field in record.
fun updateLastName(x:string,l:employee)=
if (L=[]) then []
else if (x= #fname(#name(#p hd l)) //cheking name of 1st record in list
//not getting how to update,this kind of line did not work
#fname(#name(#p hd l) = "abc"
else updateLastName(x,tl(l)); // hope this is right
Please suggest.
functional-programming sml smlnj
add a comment |
I am writing SML program to update records in a list.For example, I have type person_name.
type person_name = fname:string, lname:string, mname:string
Then I have person_bio which has person_name embedded in it.
type person_bio = age:real, gender:string, name:person_name, status:string
Next I have employee which has person_bio.
type employee = p:person_bio, payrate:real, whours:real list;
Now, I have to define function 'updateLastName' by passing the first name.
As of now, created one record 'e1' with below data.
p=age=40.0,gender="M",namefname="rob",lname="sen",mname="",status="M",
payrate=30.0,whours=10.0
But I am facing challenge to traverse the list and then updating one field in record.
fun updateLastName(x:string,l:employee)=
if (L=[]) then []
else if (x= #fname(#name(#p hd l)) //cheking name of 1st record in list
//not getting how to update,this kind of line did not work
#fname(#name(#p hd l) = "abc"
else updateLastName(x,tl(l)); // hope this is right
Please suggest.
functional-programming sml smlnj
Values in SML are immutable, and#fname(#name(#p hd l) = "abc"
is a comparison. You need to build a new list with the updated record. (And read up on pattern matching – it makes everything less messy and more readable.)
– molbdnilo
Mar 24 at 10:49
Start with something simpler than records, such as integers.
– molbdnilo
Mar 24 at 11:45
thanks,I am bit confused. To update lname only, i have to remove and add it someway if direct updation is not possible?
– Sri
Mar 25 at 0:23
I did this to update lastname but not working. fun updateLname(fnm:string,lnm:string,[]) = [] | updateLname(fnm:string,lnm:string,x::xs)= ( if fnm= (#fname ( #name ( #p x))) then if lnm <> (#lname ( #name ( #p ( x)))) then lnm else (#lname ( #name ( #p ( x))))) :: updateLname(fnm,lnm,xs)
– Sri
Mar 25 at 5:01
add a comment |
I am writing SML program to update records in a list.For example, I have type person_name.
type person_name = fname:string, lname:string, mname:string
Then I have person_bio which has person_name embedded in it.
type person_bio = age:real, gender:string, name:person_name, status:string
Next I have employee which has person_bio.
type employee = p:person_bio, payrate:real, whours:real list;
Now, I have to define function 'updateLastName' by passing the first name.
As of now, created one record 'e1' with below data.
p=age=40.0,gender="M",namefname="rob",lname="sen",mname="",status="M",
payrate=30.0,whours=10.0
But I am facing challenge to traverse the list and then updating one field in record.
fun updateLastName(x:string,l:employee)=
if (L=[]) then []
else if (x= #fname(#name(#p hd l)) //cheking name of 1st record in list
//not getting how to update,this kind of line did not work
#fname(#name(#p hd l) = "abc"
else updateLastName(x,tl(l)); // hope this is right
Please suggest.
functional-programming sml smlnj
I am writing SML program to update records in a list.For example, I have type person_name.
type person_name = fname:string, lname:string, mname:string
Then I have person_bio which has person_name embedded in it.
type person_bio = age:real, gender:string, name:person_name, status:string
Next I have employee which has person_bio.
type employee = p:person_bio, payrate:real, whours:real list;
Now, I have to define function 'updateLastName' by passing the first name.
As of now, created one record 'e1' with below data.
p=age=40.0,gender="M",namefname="rob",lname="sen",mname="",status="M",
payrate=30.0,whours=10.0
But I am facing challenge to traverse the list and then updating one field in record.
fun updateLastName(x:string,l:employee)=
if (L=[]) then []
else if (x= #fname(#name(#p hd l)) //cheking name of 1st record in list
//not getting how to update,this kind of line did not work
#fname(#name(#p hd l) = "abc"
else updateLastName(x,tl(l)); // hope this is right
Please suggest.
functional-programming sml smlnj
functional-programming sml smlnj
asked Mar 24 at 5:58
SriSri
345
345
Values in SML are immutable, and#fname(#name(#p hd l) = "abc"
is a comparison. You need to build a new list with the updated record. (And read up on pattern matching – it makes everything less messy and more readable.)
– molbdnilo
Mar 24 at 10:49
Start with something simpler than records, such as integers.
– molbdnilo
Mar 24 at 11:45
thanks,I am bit confused. To update lname only, i have to remove and add it someway if direct updation is not possible?
– Sri
Mar 25 at 0:23
I did this to update lastname but not working. fun updateLname(fnm:string,lnm:string,[]) = [] | updateLname(fnm:string,lnm:string,x::xs)= ( if fnm= (#fname ( #name ( #p x))) then if lnm <> (#lname ( #name ( #p ( x)))) then lnm else (#lname ( #name ( #p ( x))))) :: updateLname(fnm,lnm,xs)
– Sri
Mar 25 at 5:01
add a comment |
Values in SML are immutable, and#fname(#name(#p hd l) = "abc"
is a comparison. You need to build a new list with the updated record. (And read up on pattern matching – it makes everything less messy and more readable.)
– molbdnilo
Mar 24 at 10:49
Start with something simpler than records, such as integers.
– molbdnilo
Mar 24 at 11:45
thanks,I am bit confused. To update lname only, i have to remove and add it someway if direct updation is not possible?
– Sri
Mar 25 at 0:23
I did this to update lastname but not working. fun updateLname(fnm:string,lnm:string,[]) = [] | updateLname(fnm:string,lnm:string,x::xs)= ( if fnm= (#fname ( #name ( #p x))) then if lnm <> (#lname ( #name ( #p ( x)))) then lnm else (#lname ( #name ( #p ( x))))) :: updateLname(fnm,lnm,xs)
– Sri
Mar 25 at 5:01
Values in SML are immutable, and
#fname(#name(#p hd l) = "abc"
is a comparison. You need to build a new list with the updated record. (And read up on pattern matching – it makes everything less messy and more readable.)– molbdnilo
Mar 24 at 10:49
Values in SML are immutable, and
#fname(#name(#p hd l) = "abc"
is a comparison. You need to build a new list with the updated record. (And read up on pattern matching – it makes everything less messy and more readable.)– molbdnilo
Mar 24 at 10:49
Start with something simpler than records, such as integers.
– molbdnilo
Mar 24 at 11:45
Start with something simpler than records, such as integers.
– molbdnilo
Mar 24 at 11:45
thanks,I am bit confused. To update lname only, i have to remove and add it someway if direct updation is not possible?
– Sri
Mar 25 at 0:23
thanks,I am bit confused. To update lname only, i have to remove and add it someway if direct updation is not possible?
– Sri
Mar 25 at 0:23
I did this to update lastname but not working. fun updateLname(fnm:string,lnm:string,[]) = [] | updateLname(fnm:string,lnm:string,x::xs)= ( if fnm= (#fname ( #name ( #p x))) then if lnm <> (#lname ( #name ( #p ( x)))) then lnm else (#lname ( #name ( #p ( x))))) :: updateLname(fnm,lnm,xs)
– Sri
Mar 25 at 5:01
I did this to update lastname but not working. fun updateLname(fnm:string,lnm:string,[]) = [] | updateLname(fnm:string,lnm:string,x::xs)= ( if fnm= (#fname ( #name ( #p x))) then if lnm <> (#lname ( #name ( #p ( x)))) then lnm else (#lname ( #name ( #p ( x))))) :: updateLname(fnm,lnm,xs)
– Sri
Mar 25 at 5:01
add a comment |
2 Answers
2
active
oldest
votes
You have stumbled upon something difficult: Updating a deeply nested record.
For records you have getters, so #fname (#name (#p employee))
gets the field that you're checking against to know that this is the employee whose last name you are going to update. But records don't grant you equivalent setters, so you have to make those. If you're curious, lenses (Haskell) are a general way to solve this, but I don't know of any implementation of lenses for Standard ML.
I'll go ahead and remove the list
part in your employee
type; you should probably want an employee list
if you want multiple employees modelled, rather than to say that an employee is multiple persons.
type person_name = fname:string, lname:string, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
type employee = p:person_bio, payrate:real, whours:real
val name1 = fname = "John", lname = "Doe", mname = "W." : person_name
val bio1 = age = 42.0, gender = "M", name = name1, status = "?" : person_bio
val my_employee1 = p = bio1, payrate = 1000.0, whours = 37.0 : employee
val name2 = fname = "Freddy", lname = "Mercury", mname = "X." : person_name
val bio2 = age = 45.0, gender = "M", name = name2, status = "?" : person_bio
val my_employee2 = p = bio2, payrate = 2000.0, whours = 37.0 : employee
val my_employees = [ my_employee1, my_employee2 ] : employee list
As for the setters (the ones that you could automatically derive using lenses),
fun setP (p : person_bio, e : employee) =
p = p
, payrate = #payrate e
, whours = #whours e : employee
fun setName (name : person_name, pb : person_bio) =
age = #age pb
, gender = #gender pb
, name = name
, status = #status pb : person_bio
fun setLname (lname, pn : person_name) =
fname = #fname pn
, lname = lname
, mname = #mname pn : person_name
you can compose these, e.g. like:
- setP (setName (setLname ("Johnson", #name (#p my_employee1)), #p my_employee1), my_employee1)
> val it =
p =
age = 42.0, gender = "M",
name = fname = "John", lname = "Johnson", mname = "W.",
status = "?", payrate = 1000.0, whours = 37.0 :
p :
age : real, gender : string,
name : fname : string, lname : string, mname : string,
status : string, payrate : real, whours : real
Or you can split that line a little apart to make it more readable:
fun updateLname (fname, lname, employees) =
let fun update employee =
if #fname (#name (#p employee)) = fname
then let val new_name = setLname (lname, #name (#p employee))
val new_bio = setName (new_name, #p employee)
val new_employee = setP (new_bio, employee)
in new_employee end
else employee
in List.map update employees
end
Trying this out:
- updateLname ("Freddy", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Doe", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Johnson", mname = "X.", ... ]
- updateLname ("John", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Johnson", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Mercury", mname = "X.", ... ]
1
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
add a comment |
Depending on your situation, references may be appropriate here.
For any values you may need to change, you can make them a reference, i.e.
type person_name = fname:string, lname:string ref, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
fun change_lname(new_lname: string, bio: person_bio) = (#lname (#name bio)) := new_lname
val p1 = ...
print !(#lname (#name p1)) ==> LastName1
change_lname("LastName2", p1)
print !(#lname (#name p1)) ==> LastName2
If you plan on modifying data in a record a lot, it's probably a good idea to make it a reference so that your program is not rewriting memory every time it needs to change one value (though in many situations the compiler/interpreter will be able to optimize this). It also saves you from having to rewrite setter functions if the signature of your record changes. The downside is that you'll be introducing complexity into your program by using references.
For example, in the above code, we're not actually modifying p1's last name, instead p1 and a copy (passed to the function) both point to the same string, and we modify that string in the function. At no point are we actually changing any of the data in either record, we're only changing data that the records point to. It's a subtle difference, and it doesn't really make a difference in this example, but it can lead to strange bugs that are hard to debug.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55321130%2fhow-to-update-record-value-in-sml%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You have stumbled upon something difficult: Updating a deeply nested record.
For records you have getters, so #fname (#name (#p employee))
gets the field that you're checking against to know that this is the employee whose last name you are going to update. But records don't grant you equivalent setters, so you have to make those. If you're curious, lenses (Haskell) are a general way to solve this, but I don't know of any implementation of lenses for Standard ML.
I'll go ahead and remove the list
part in your employee
type; you should probably want an employee list
if you want multiple employees modelled, rather than to say that an employee is multiple persons.
type person_name = fname:string, lname:string, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
type employee = p:person_bio, payrate:real, whours:real
val name1 = fname = "John", lname = "Doe", mname = "W." : person_name
val bio1 = age = 42.0, gender = "M", name = name1, status = "?" : person_bio
val my_employee1 = p = bio1, payrate = 1000.0, whours = 37.0 : employee
val name2 = fname = "Freddy", lname = "Mercury", mname = "X." : person_name
val bio2 = age = 45.0, gender = "M", name = name2, status = "?" : person_bio
val my_employee2 = p = bio2, payrate = 2000.0, whours = 37.0 : employee
val my_employees = [ my_employee1, my_employee2 ] : employee list
As for the setters (the ones that you could automatically derive using lenses),
fun setP (p : person_bio, e : employee) =
p = p
, payrate = #payrate e
, whours = #whours e : employee
fun setName (name : person_name, pb : person_bio) =
age = #age pb
, gender = #gender pb
, name = name
, status = #status pb : person_bio
fun setLname (lname, pn : person_name) =
fname = #fname pn
, lname = lname
, mname = #mname pn : person_name
you can compose these, e.g. like:
- setP (setName (setLname ("Johnson", #name (#p my_employee1)), #p my_employee1), my_employee1)
> val it =
p =
age = 42.0, gender = "M",
name = fname = "John", lname = "Johnson", mname = "W.",
status = "?", payrate = 1000.0, whours = 37.0 :
p :
age : real, gender : string,
name : fname : string, lname : string, mname : string,
status : string, payrate : real, whours : real
Or you can split that line a little apart to make it more readable:
fun updateLname (fname, lname, employees) =
let fun update employee =
if #fname (#name (#p employee)) = fname
then let val new_name = setLname (lname, #name (#p employee))
val new_bio = setName (new_name, #p employee)
val new_employee = setP (new_bio, employee)
in new_employee end
else employee
in List.map update employees
end
Trying this out:
- updateLname ("Freddy", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Doe", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Johnson", mname = "X.", ... ]
- updateLname ("John", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Johnson", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Mercury", mname = "X.", ... ]
1
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
add a comment |
You have stumbled upon something difficult: Updating a deeply nested record.
For records you have getters, so #fname (#name (#p employee))
gets the field that you're checking against to know that this is the employee whose last name you are going to update. But records don't grant you equivalent setters, so you have to make those. If you're curious, lenses (Haskell) are a general way to solve this, but I don't know of any implementation of lenses for Standard ML.
I'll go ahead and remove the list
part in your employee
type; you should probably want an employee list
if you want multiple employees modelled, rather than to say that an employee is multiple persons.
type person_name = fname:string, lname:string, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
type employee = p:person_bio, payrate:real, whours:real
val name1 = fname = "John", lname = "Doe", mname = "W." : person_name
val bio1 = age = 42.0, gender = "M", name = name1, status = "?" : person_bio
val my_employee1 = p = bio1, payrate = 1000.0, whours = 37.0 : employee
val name2 = fname = "Freddy", lname = "Mercury", mname = "X." : person_name
val bio2 = age = 45.0, gender = "M", name = name2, status = "?" : person_bio
val my_employee2 = p = bio2, payrate = 2000.0, whours = 37.0 : employee
val my_employees = [ my_employee1, my_employee2 ] : employee list
As for the setters (the ones that you could automatically derive using lenses),
fun setP (p : person_bio, e : employee) =
p = p
, payrate = #payrate e
, whours = #whours e : employee
fun setName (name : person_name, pb : person_bio) =
age = #age pb
, gender = #gender pb
, name = name
, status = #status pb : person_bio
fun setLname (lname, pn : person_name) =
fname = #fname pn
, lname = lname
, mname = #mname pn : person_name
you can compose these, e.g. like:
- setP (setName (setLname ("Johnson", #name (#p my_employee1)), #p my_employee1), my_employee1)
> val it =
p =
age = 42.0, gender = "M",
name = fname = "John", lname = "Johnson", mname = "W.",
status = "?", payrate = 1000.0, whours = 37.0 :
p :
age : real, gender : string,
name : fname : string, lname : string, mname : string,
status : string, payrate : real, whours : real
Or you can split that line a little apart to make it more readable:
fun updateLname (fname, lname, employees) =
let fun update employee =
if #fname (#name (#p employee)) = fname
then let val new_name = setLname (lname, #name (#p employee))
val new_bio = setName (new_name, #p employee)
val new_employee = setP (new_bio, employee)
in new_employee end
else employee
in List.map update employees
end
Trying this out:
- updateLname ("Freddy", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Doe", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Johnson", mname = "X.", ... ]
- updateLname ("John", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Johnson", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Mercury", mname = "X.", ... ]
1
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
add a comment |
You have stumbled upon something difficult: Updating a deeply nested record.
For records you have getters, so #fname (#name (#p employee))
gets the field that you're checking against to know that this is the employee whose last name you are going to update. But records don't grant you equivalent setters, so you have to make those. If you're curious, lenses (Haskell) are a general way to solve this, but I don't know of any implementation of lenses for Standard ML.
I'll go ahead and remove the list
part in your employee
type; you should probably want an employee list
if you want multiple employees modelled, rather than to say that an employee is multiple persons.
type person_name = fname:string, lname:string, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
type employee = p:person_bio, payrate:real, whours:real
val name1 = fname = "John", lname = "Doe", mname = "W." : person_name
val bio1 = age = 42.0, gender = "M", name = name1, status = "?" : person_bio
val my_employee1 = p = bio1, payrate = 1000.0, whours = 37.0 : employee
val name2 = fname = "Freddy", lname = "Mercury", mname = "X." : person_name
val bio2 = age = 45.0, gender = "M", name = name2, status = "?" : person_bio
val my_employee2 = p = bio2, payrate = 2000.0, whours = 37.0 : employee
val my_employees = [ my_employee1, my_employee2 ] : employee list
As for the setters (the ones that you could automatically derive using lenses),
fun setP (p : person_bio, e : employee) =
p = p
, payrate = #payrate e
, whours = #whours e : employee
fun setName (name : person_name, pb : person_bio) =
age = #age pb
, gender = #gender pb
, name = name
, status = #status pb : person_bio
fun setLname (lname, pn : person_name) =
fname = #fname pn
, lname = lname
, mname = #mname pn : person_name
you can compose these, e.g. like:
- setP (setName (setLname ("Johnson", #name (#p my_employee1)), #p my_employee1), my_employee1)
> val it =
p =
age = 42.0, gender = "M",
name = fname = "John", lname = "Johnson", mname = "W.",
status = "?", payrate = 1000.0, whours = 37.0 :
p :
age : real, gender : string,
name : fname : string, lname : string, mname : string,
status : string, payrate : real, whours : real
Or you can split that line a little apart to make it more readable:
fun updateLname (fname, lname, employees) =
let fun update employee =
if #fname (#name (#p employee)) = fname
then let val new_name = setLname (lname, #name (#p employee))
val new_bio = setName (new_name, #p employee)
val new_employee = setP (new_bio, employee)
in new_employee end
else employee
in List.map update employees
end
Trying this out:
- updateLname ("Freddy", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Doe", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Johnson", mname = "X.", ... ]
- updateLname ("John", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Johnson", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Mercury", mname = "X.", ... ]
You have stumbled upon something difficult: Updating a deeply nested record.
For records you have getters, so #fname (#name (#p employee))
gets the field that you're checking against to know that this is the employee whose last name you are going to update. But records don't grant you equivalent setters, so you have to make those. If you're curious, lenses (Haskell) are a general way to solve this, but I don't know of any implementation of lenses for Standard ML.
I'll go ahead and remove the list
part in your employee
type; you should probably want an employee list
if you want multiple employees modelled, rather than to say that an employee is multiple persons.
type person_name = fname:string, lname:string, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
type employee = p:person_bio, payrate:real, whours:real
val name1 = fname = "John", lname = "Doe", mname = "W." : person_name
val bio1 = age = 42.0, gender = "M", name = name1, status = "?" : person_bio
val my_employee1 = p = bio1, payrate = 1000.0, whours = 37.0 : employee
val name2 = fname = "Freddy", lname = "Mercury", mname = "X." : person_name
val bio2 = age = 45.0, gender = "M", name = name2, status = "?" : person_bio
val my_employee2 = p = bio2, payrate = 2000.0, whours = 37.0 : employee
val my_employees = [ my_employee1, my_employee2 ] : employee list
As for the setters (the ones that you could automatically derive using lenses),
fun setP (p : person_bio, e : employee) =
p = p
, payrate = #payrate e
, whours = #whours e : employee
fun setName (name : person_name, pb : person_bio) =
age = #age pb
, gender = #gender pb
, name = name
, status = #status pb : person_bio
fun setLname (lname, pn : person_name) =
fname = #fname pn
, lname = lname
, mname = #mname pn : person_name
you can compose these, e.g. like:
- setP (setName (setLname ("Johnson", #name (#p my_employee1)), #p my_employee1), my_employee1)
> val it =
p =
age = 42.0, gender = "M",
name = fname = "John", lname = "Johnson", mname = "W.",
status = "?", payrate = 1000.0, whours = 37.0 :
p :
age : real, gender : string,
name : fname : string, lname : string, mname : string,
status : string, payrate : real, whours : real
Or you can split that line a little apart to make it more readable:
fun updateLname (fname, lname, employees) =
let fun update employee =
if #fname (#name (#p employee)) = fname
then let val new_name = setLname (lname, #name (#p employee))
val new_bio = setName (new_name, #p employee)
val new_employee = setP (new_bio, employee)
in new_employee end
else employee
in List.map update employees
end
Trying this out:
- updateLname ("Freddy", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Doe", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Johnson", mname = "X.", ... ]
- updateLname ("John", "Johnson", my_employees);
> val it =
[p = ... fname = "John", lname = "Johnson", mname = "W.", ... ,
p = ... fname = "Freddy", lname = "Mercury", mname = "X.", ... ]
answered Mar 25 at 8:22
Simon ShineSimon Shine
10.5k13050
10.5k13050
1
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
add a comment |
1
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
1
1
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
That idea of lenses seems interesting. I wonder how possible it would be to implement it in straight SML. I don't see why not, but on the other hand, I don't know what that link means when it refers to "Template Haskell".
– John Coleman
Mar 26 at 10:33
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
You could generate lenses as part of a preprocessing step. If I were to make such a preprocessor, I'd probably extend the work of Morten Brøns-Pedersen's PreML SML preprocessor.
– Simon Shine
Mar 26 at 12:06
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
Thanks a lot for the elaborate explanation.It helped a lot.
– Sri
Mar 26 at 19:34
add a comment |
Depending on your situation, references may be appropriate here.
For any values you may need to change, you can make them a reference, i.e.
type person_name = fname:string, lname:string ref, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
fun change_lname(new_lname: string, bio: person_bio) = (#lname (#name bio)) := new_lname
val p1 = ...
print !(#lname (#name p1)) ==> LastName1
change_lname("LastName2", p1)
print !(#lname (#name p1)) ==> LastName2
If you plan on modifying data in a record a lot, it's probably a good idea to make it a reference so that your program is not rewriting memory every time it needs to change one value (though in many situations the compiler/interpreter will be able to optimize this). It also saves you from having to rewrite setter functions if the signature of your record changes. The downside is that you'll be introducing complexity into your program by using references.
For example, in the above code, we're not actually modifying p1's last name, instead p1 and a copy (passed to the function) both point to the same string, and we modify that string in the function. At no point are we actually changing any of the data in either record, we're only changing data that the records point to. It's a subtle difference, and it doesn't really make a difference in this example, but it can lead to strange bugs that are hard to debug.
add a comment |
Depending on your situation, references may be appropriate here.
For any values you may need to change, you can make them a reference, i.e.
type person_name = fname:string, lname:string ref, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
fun change_lname(new_lname: string, bio: person_bio) = (#lname (#name bio)) := new_lname
val p1 = ...
print !(#lname (#name p1)) ==> LastName1
change_lname("LastName2", p1)
print !(#lname (#name p1)) ==> LastName2
If you plan on modifying data in a record a lot, it's probably a good idea to make it a reference so that your program is not rewriting memory every time it needs to change one value (though in many situations the compiler/interpreter will be able to optimize this). It also saves you from having to rewrite setter functions if the signature of your record changes. The downside is that you'll be introducing complexity into your program by using references.
For example, in the above code, we're not actually modifying p1's last name, instead p1 and a copy (passed to the function) both point to the same string, and we modify that string in the function. At no point are we actually changing any of the data in either record, we're only changing data that the records point to. It's a subtle difference, and it doesn't really make a difference in this example, but it can lead to strange bugs that are hard to debug.
add a comment |
Depending on your situation, references may be appropriate here.
For any values you may need to change, you can make them a reference, i.e.
type person_name = fname:string, lname:string ref, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
fun change_lname(new_lname: string, bio: person_bio) = (#lname (#name bio)) := new_lname
val p1 = ...
print !(#lname (#name p1)) ==> LastName1
change_lname("LastName2", p1)
print !(#lname (#name p1)) ==> LastName2
If you plan on modifying data in a record a lot, it's probably a good idea to make it a reference so that your program is not rewriting memory every time it needs to change one value (though in many situations the compiler/interpreter will be able to optimize this). It also saves you from having to rewrite setter functions if the signature of your record changes. The downside is that you'll be introducing complexity into your program by using references.
For example, in the above code, we're not actually modifying p1's last name, instead p1 and a copy (passed to the function) both point to the same string, and we modify that string in the function. At no point are we actually changing any of the data in either record, we're only changing data that the records point to. It's a subtle difference, and it doesn't really make a difference in this example, but it can lead to strange bugs that are hard to debug.
Depending on your situation, references may be appropriate here.
For any values you may need to change, you can make them a reference, i.e.
type person_name = fname:string, lname:string ref, mname:string
type person_bio = age:real, gender:string, name:person_name, status:string
fun change_lname(new_lname: string, bio: person_bio) = (#lname (#name bio)) := new_lname
val p1 = ...
print !(#lname (#name p1)) ==> LastName1
change_lname("LastName2", p1)
print !(#lname (#name p1)) ==> LastName2
If you plan on modifying data in a record a lot, it's probably a good idea to make it a reference so that your program is not rewriting memory every time it needs to change one value (though in many situations the compiler/interpreter will be able to optimize this). It also saves you from having to rewrite setter functions if the signature of your record changes. The downside is that you'll be introducing complexity into your program by using references.
For example, in the above code, we're not actually modifying p1's last name, instead p1 and a copy (passed to the function) both point to the same string, and we modify that string in the function. At no point are we actually changing any of the data in either record, we're only changing data that the records point to. It's a subtle difference, and it doesn't really make a difference in this example, but it can lead to strange bugs that are hard to debug.
answered Apr 20 at 19:34
Sean BowersSean Bowers
1
1
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55321130%2fhow-to-update-record-value-in-sml%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Values in SML are immutable, and
#fname(#name(#p hd l) = "abc"
is a comparison. You need to build a new list with the updated record. (And read up on pattern matching – it makes everything less messy and more readable.)– molbdnilo
Mar 24 at 10:49
Start with something simpler than records, such as integers.
– molbdnilo
Mar 24 at 11:45
thanks,I am bit confused. To update lname only, i have to remove and add it someway if direct updation is not possible?
– Sri
Mar 25 at 0:23
I did this to update lastname but not working. fun updateLname(fnm:string,lnm:string,[]) = [] | updateLname(fnm:string,lnm:string,x::xs)= ( if fnm= (#fname ( #name ( #p x))) then if lnm <> (#lname ( #name ( #p ( x)))) then lnm else (#lname ( #name ( #p ( x))))) :: updateLname(fnm,lnm,xs)
– Sri
Mar 25 at 5:01