Say I have a Student class which has lots of actions:
final case class Student(name: String, knowledge: List[String]) {
def learn(item: String) : Student = this.copy(knowledge = knowledge :+ item)
}
Here you can notice that this class is not influenced by any outer State.
But if I put this class into a Stateful environment(like a School):
final case class School(students: Map[String, Student]) {
def learn(studentName: String, item: String) : State[School, Student] = State {
oldSchool => {
val oldStudent = students.get(studentName).getOrElse(Student(studentName, List()))
val newStudent = oldStudent.learn(item)
oldSchool.copy(students = students + (studentName -> newStudent)) -> newStudent
}
}
}
And then I cannot use student.learn(info) directly, for Student even doesn't know the environment(School class) exists. So if I want to call the actions of a student, I have to call the proxy function exposed by the Environment class. If I have lots of actions in Student, I HAVE TO write the same count of proxy functions in School, which is frustrating and not fun at all.
Any advices? How to manage this kind of State hierarchy?
Inspired by @WillemVanOnsem, here is my solution.
def updateStudent: String => (Student => Student) => School =
name =>
func =>
this.copy(
students = students + (name -> func(
students.get(name).getOrElse(Student(name, List()))
))
)
And the usage likes:
val stu1 = Student("name1", List())
val school = School(Map(stu1.name -> stu1))
val newSchool = school.updateStudent("name1") { student =>
student.learn("someItem")
}
And I notice that if your hierarchy is really deep, the (Student => Student) part can be replaced by Lens, so the you should prepare a bunch of Lens, rather than a bunch of Proxy Functions of different depth of functions, cool!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With