如何更新SML中的记录值?
How to update record value in SML?
我正在编写 SML 程序来更新 list.For 示例中的记录,我的类型为 person_name.
type person_name = {fname:string, lname:string, mname:string}
然后我有 person_bio,其中嵌入了 person_name。
type person_bio = {age:real, gender:string, name:person_name, status:string}
接下来我有员工 person_bio。
type employee = {p:person_bio, payrate:real, whours:real} list;
现在,我必须通过传递名字来定义函数 'updateLastName'。
截至目前,使用以下数据创建了一条记录 'e1'。
{p={age=40.0,gender="M",name{fname="rob",lname="sen",mname=""},status="M"},
payrate=30.0,whours=10.0}
但我面临遍历列表然后更新记录中的一个字段的挑战。
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
求推荐。
您遇到了困难:更新深度嵌套的记录。
对于您有 getters 的记录,因此 #fname (#name (#p employee))
获取您正在检查的字段以了解这是您要访问其姓氏的员工更新。但是记录不会授予您等效的 setters,因此您必须创建它们。如果你很好奇,lenses (Haskell) 是解决这个问题的一般方法,但我不知道标准 ML 的任何镜头实现。
我会继续删除您的 employee
类型中的 list
部分;如果你想为多个员工建模,你可能应该想要一个 employee list
,而不是说一个员工是多个人。
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
至于 setters(您可以使用 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
你可以编写这些,例如喜欢:
- 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}
或者您可以将该行分开一点以使其更具可读性:
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
试试这个:
- 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."}, ... }]
根据您的情况,此处可能适合参考。
对于您可能需要更改的任何值,您可以将它们作为参考,即
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
如果您打算经常修改一条记录中的数据,将它作为一个引用可能是个好主意,这样您的程序就不会在每次需要更改一个值时都重写内存(尽管在许多情况下 compiler/interpreter就能优化这个)。如果您的记录签名发生更改,它还使您不必重写 setter 函数。缺点是使用引用会给程序带来复杂性。
例如,在上面的代码中,我们实际上并没有修改 p1 的姓氏,而是 p1 和一个副本(传递给函数)都指向同一个字符串,我们在函数中修改了那个字符串。在任何时候我们实际上都不会更改任何一条记录中的任何数据,我们只是更改记录指向的数据。这是一个细微的差别,在这个例子中并没有真正的区别,但它会导致难以调试的奇怪错误。
我正在编写 SML 程序来更新 list.For 示例中的记录,我的类型为 person_name.
type person_name = {fname:string, lname:string, mname:string}
然后我有 person_bio,其中嵌入了 person_name。
type person_bio = {age:real, gender:string, name:person_name, status:string}
接下来我有员工 person_bio。
type employee = {p:person_bio, payrate:real, whours:real} list;
现在,我必须通过传递名字来定义函数 'updateLastName'。
截至目前,使用以下数据创建了一条记录 'e1'。
{p={age=40.0,gender="M",name{fname="rob",lname="sen",mname=""},status="M"},
payrate=30.0,whours=10.0}
但我面临遍历列表然后更新记录中的一个字段的挑战。
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
求推荐。
您遇到了困难:更新深度嵌套的记录。
对于您有 getters 的记录,因此 #fname (#name (#p employee))
获取您正在检查的字段以了解这是您要访问其姓氏的员工更新。但是记录不会授予您等效的 setters,因此您必须创建它们。如果你很好奇,lenses (Haskell) 是解决这个问题的一般方法,但我不知道标准 ML 的任何镜头实现。
我会继续删除您的 employee
类型中的 list
部分;如果你想为多个员工建模,你可能应该想要一个 employee list
,而不是说一个员工是多个人。
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
至于 setters(您可以使用 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
你可以编写这些,例如喜欢:
- 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}
或者您可以将该行分开一点以使其更具可读性:
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
试试这个:
- 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."}, ... }]
根据您的情况,此处可能适合参考。
对于您可能需要更改的任何值,您可以将它们作为参考,即
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
如果您打算经常修改一条记录中的数据,将它作为一个引用可能是个好主意,这样您的程序就不会在每次需要更改一个值时都重写内存(尽管在许多情况下 compiler/interpreter就能优化这个)。如果您的记录签名发生更改,它还使您不必重写 setter 函数。缺点是使用引用会给程序带来复杂性。
例如,在上面的代码中,我们实际上并没有修改 p1 的姓氏,而是 p1 和一个副本(传递给函数)都指向同一个字符串,我们在函数中修改了那个字符串。在任何时候我们实际上都不会更改任何一条记录中的任何数据,我们只是更改记录指向的数据。这是一个细微的差别,在这个例子中并没有真正的区别,但它会导致难以调试的奇怪错误。