Вы наткнулись на что-то сложное: обновление глубоко вложенной записи.
Для записей у вас есть получатели , поэтому #fname (#name (#p employee))
получает поле, по которому вы проверяете, чтобы узнать, что это сотрудник, фамилию которого вы собираетесь обновить.Но записи не дают вам эквивалентных сеттеров , поэтому вы должны их создать.Если вам интересно, линзы (Haskell) - это общий способ решения этой проблемы, но я не знаю какой-либо реализации линз для Standard ML.
Я пойду дальше и уберу часть list
в вашем типе employee
;вам, вероятно, следует хотеть 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
Что касается сеттеров (тех, которые выможно автоматически получить, используя линзы ),
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."}, ... }]