scala - 如何替换通用匿名函数?

标签 scala anonymous-function function-signature

假设有腿动物有一个特征:

trait Legged {
  val legs: Int

  def updateLegs(legs: Int): Legged
}
有两种这样的有腿的动物:
case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
  override def updateLegs(legs: Int): Legged = copy(legs = legs)
}

case class Dog(name: String, legs: Int = 4) extends Legged {
  override def updateLegs(legs: Int): Legged = copy(legs = legs)
}
在农场里还有这些动物的持有人
case class Farm(chicken: Chicken, dog: Dog)
以及一种通过添加一条额外的腿来变异所有有腿动物的通用方法
def mutate(legged: Legged): Legged = legged.updateLegs(legged.legs + 1)
问题是如何在Farm上实现一个方法所以它需要 mutate: Legged => Legged函数作为参数并将其应用于所有 Legged动物?
val farm = Farm(Chicken(1500), Dog("Max"))
farm.mapAll(mutate) //this should return a farm whose animals have an extra leg
到目前为止我所带来的,但实际上并没有用
trait LeggedFunc[T <: Legged] extends (T => T)


case class Farm(chicken: Chicken, dog: Dog) {
  def mapAll(leggedFunc: LeggedFunc[Legged]): Farm = {
    //todo how to implement?
    val c = leggedFunc[Chicken](chicken)
  }
}
我知道如何使用模式匹配来做到这一点,但这会导致潜在的 MatchError .

最佳答案

一种可能的方法(类型安全,不使用 asInstanceOf )可能是使用依赖于对象的类型。
首先,我们应该添加一个抽象成员,它使用 Legged 的具体类型。子类:

sealed trait Legged { self =>
  type Me >: self.type <: Legged // F-Bounded like type, Me have to be the same type of the subclasses
  val legs: Int
  def updateLegs(legs: Int): Me
}
然后,Legged子类变成了:

case class Chicken(feathers: Int, legs: Int = 2) extends Legged {
  type Me = Chicken
  override def updateLegs(legs: Int): Chicken = copy(legs = legs)
}

case class Dog(name: String, legs: Int = 4) extends Legged {
  type Me = Dog
  override def updateLegs(legs: Int): Dog = copy(legs = legs)
}
这样,就可以定义一个返回Legged的具体子类的函数。通过(类似于@Gaël J 所做的):
trait LeggedFunc {
  def apply(a : Legged): a.Me
}

val mutate = new LeggedFunc { override def apply(legged: Legged): legged.Me = legged.updateLegs(legged.legs + 1) }
最后,Farm类很简单,定义为:
case class Farm(chicken: Chicken, dog: Dog) {
  def mapAll(leggedFunc: LeggedFunc): Farm = {
    val c : Chicken = leggedFunc(chicken)
    val d : Dog = leggedFunc(dog)
    Farm(c, d)
  }
}
Scastie对于 Scala 2
但是为什么是对象依赖类型呢?
在 Scala 3.0 中,可以定义 dependent function type作为:
type LeggedFunc = (l: Legged) => l.Me
val mutate: LeggedFunc = (l) => l.updateLegs(l.legs + 1)
使这个解决方案(依赖于对象的类型)更清晰和类型安全。
Scastie对于 Scala 3 版本

关于scala - 如何替换通用匿名函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68888089/

相关文章:

OOP 哲学(摘自《Scala 编程》中的组合和继承)

javascript - 如何从嵌套的匿名函数返回值给父函数

lambda - Kotlin:命名 lambda 参数的用途是什么?

c# - 委托(delegate)、Lambda、Action、Func、匿名函数

c++ - 为什么名称修改没有破坏我的程序?

ScalaTest 运行时的 Scala Play Slick RejectedExecutionException

xml - Scala 中的递归 XML

scala - Scala 中的协变树

TypeScript - 检查对象的属性是否是具有给定签名的函数

c++ - 作为模板参数的函数指针和作为模板参数的函数签名之间的区别