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;








0















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.










share|improve this question






















  • 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

















0















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.










share|improve this question






















  • 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













0












0








0








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.










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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

















  • 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












2 Answers
2






active

oldest

votes


















2














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.", ... ]





share|improve this answer


















  • 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


















0














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.






share|improve this answer























    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
    );



    );













    draft saved

    draft discarded


















    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









    2














    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.", ... ]





    share|improve this answer


















    • 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















    2














    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.", ... ]





    share|improve this answer


















    • 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













    2












    2








    2







    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.", ... ]





    share|improve this answer













    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.", ... ]






    share|improve this answer












    share|improve this answer



    share|improve this answer










    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












    • 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













    0














    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.






    share|improve this answer



























      0














      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.






      share|improve this answer

























        0












        0








        0







        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.






        share|improve this answer













        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Apr 20 at 19:34









        Sean BowersSean Bowers

        1




        1



























            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

            Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

            Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript