我想创建一个适用于数组作为选项的通用函数:
val numbers = Array(1, 2, 3)
val numberO: Option[Int] = Some(4)
def addOnes(numbers: ???[Int]) = numbers.map(_+1)
addOnes(numbers)
addOnes(numberO)
现在我为每个结构都有一个单独的功能
def addOnesForArray(numbers: Array[Int]) = numbers.map(_+1)
def addOnesForOption(numberO: Option[Int]) = numberO.map(_+1)
addOnesForArray(numbers)
addOnesForOption(numberO)
所以基本上我需要一个Array和Option的超类,它有functor和monad方法map,flatMap,filter,......
答案 0 :(得分:2)
你可以使用结构类型(又名"鸭子打字"),我们可以说你需要字面意思"带有地图的东西",写成{ def map(): T }
。但是,丑陋,b)使用反射,c)很难(注意map(): T
只是一个例子;实际上你必须匹配地图的确切签名,CanBuildFrom和所有爵士乐)。
更好的方法是达到scalaz或cats并使用类别理论概念。只需选择能够完成工作的最不强大的抽象。如果您只需要map
,那么它就是一个Functor。如果你想要映射多个参数的(curried)函数,那么它就是一个Applicative。如果您还想要flatMap
,那么它就是monad等等。
仿函数示例:
import scalaz._, Scalaz._
def addOne[F[Int]](f: F[Int])(implicit m: Functor[F]) = f.map(_ + 1)
val numbers = Array(1, 2, 3).toList
val numberO = Option(123)
addOne(numbers) // List(2, 3, 4)
addOne(numberO) // Some(124)
您会注意到我必须将您的数组转换为List,因为没有类型实例(我知道)用于数组上的仿函数,应用程序,monad等。但阵列是老式的和不变的,无论如何都不是惯用的Scala。如果你从其他地方获得它们,只需将它们转换为Lists,Vectors等(根据你的用例)并从那时开始使用它们。
答案 1 :(得分:2)
总的来说,我同意@slouc。如果你想让现有的类扩展一些其他特性,你需要类型类。
但在您的特定情况下,由于Option
和Array
都是Traversable
,因此不需要它:
object Example extends App {
def plus1(data: Traversable[Int]): Traversable[Int] = data.map(x => x + 1)
println(plus1(Array(1, 2, 3)))
println(plus1(Some(4)))
}