首页 > 解决方案 > 如何管理函数式编程中的状态层次结构?

问题描述

假设我有一个Student有很多动作的类:

final case class Student(name: String, knowledge: List[String]) {
  def learn(item: String) : Student = this.copy(knowledge = knowledge :+ item)
}

在这里你可以注意到这个类不受任何外部状态的影响。

但是如果我把这个类放到一个有状态的环境中(比如一个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
    }
  }
}

然后我不能student.learn(info)直接使用,因为Student甚至不知道环境(School类)存在。所以如果我想调用一个学生的动作,我必须调用proxy functionEnvironment 类的暴露。如果我在 中有很多动作Student,我必须在 中编写相同数量的代理函数School,这很令人沮丧,而且一点也不好玩。

有什么建议吗?如何管理这种状态层次结构?

标签: scalafunctional-programmingscalazscala-cats

解决方案


受@WillemVanOnsem 启发,这是我的解决方案。

  def updateStudent: String => (Student => Student) => School =
    name =>
      func =>
        this.copy(
          students = students + (name -> func(
            students.get(name).getOrElse(Student(name, List()))
          ))
        )

用法喜欢:

    val stu1   = Student("name1", List())
    val school = School(Map(stu1.name -> stu1))

    val newSchool = school.updateStudent("name1") { student =>
      student.learn("someItem")
    }

而且我注意到如果你的层次真的很深,(Student => Student)部分可以用Lens代替,所以你应该准备一堆Lens,而不是一堆不同深度的代理函数,酷!


推荐阅读