Scala 中的类型类有什么用? [英] What are type classes in Scala useful for?

查看:26
本文介绍了Scala 中的类型类有什么用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我了解 这篇博文输入Scala 中的类"只是一种使用特征和隐式适配器实现的模式".

As I understand from this blog post "type classes" in Scala is just a "pattern" implemented with traits and implicit adapters.

正如博客所说,如果我有特征 A 和一个适配器 B ->A 然后我可以调用一个函数,该函数需要 A 类型的参数,使用 B 类型的参数,而无需显式调用此适配器.

As the blog says if I have trait A and an adapter B -> A then I can invoke a function, which requires argument of type A, with an argument of type B without invoking this adapter explicitly.

我觉得它不错,但不是特别有用.你能给出一个用例/例子,说明这个功能有什么用吗?

I found it nice but not particularly useful. Could you give a use case/example, which shows what this feature is useful for ?

推荐答案

一个用例,根据要求...

One use case, as requested...

假设您有一个列表,可以是整数、浮点数、矩阵、字符串、波形等.鉴于此列表,您想要添加内容.

Imagine you have a list of things, could be integers, floating point numbers, matrices, strings, waveforms, etc. Given this list, you want to add the contents.

实现此目的的一种方法是拥有一些 Addable 特性,这些特性必须由可以添加在一起的每个类型继承,或者隐式转换为 Addable如果处理来自第三方库的对象,而您无法对其进行接口改造.

One way to do this would be to have some Addable trait that must be inherited by every single type that can be added together, or an implicit conversion to an Addable if dealing with objects from a third party library that you can't retrofit interfaces to.

当您还想开始添加其他可以对对象列表执行的此类操作时,这种方法很快就会变得势不可挡.如果您需要替代方案(例如,添加两个波形是将它们连接起来还是叠加它们?),它也不能很好地工作改装为现有类型.

This approach becomes quickly overwhelming when you also want to begin adding other such operations that can be done to a list of objects. It also doesn't work well if you need alternatives (for example; does adding two waveforms concatenate them, or overlay them?) The solution is ad-hoc polymorphism, where you can pick and chose behaviour to be retrofitted to existing types.

对于原来的问题,你可以实现一个 Addable 类型的类:

For the original problem then, you could implement an Addable type class:

trait Addable[T] {
  def zero: T
  def append(a: T, b: T): T
}
//yup, it's our friend the monoid, with a different name!

然后您可以创建隐式子类实例,对应于您希望添加的每种类型:

You can then create implicit subclassed instances of this, corresponding to each type that you wish to make addable:

implicit object IntIsAddable extends Addable[Int] {
  def zero = 0
  def append(a: Int, b: Int) = a + b
}

implicit object StringIsAddable extends Addable[String] {
  def zero = ""
  def append(a: String, b: String) = a + b
}

//etc...

对列表求和的方法然后变得微不足道...

The method to sum a list then becomes trivial to write...

def sum[T](xs: List[T])(implicit addable: Addable[T]) =
  xs.FoldLeft(addable.zero)(addable.append)

//or the same thing, using context bounds:

def sum[T : Addable](xs: List[T]) = {
  val addable = implicitly[Addable[T]]
  xs.FoldLeft(addable.zero)(addable.append)
}

这种方法的美妙之处在于您可以提供某个类型类的替代定义,或者通过导入控制您想要的隐式范围,或者通过显式提供其他隐式参数.因此,可以提供不同的波形相加方式,或者为整数相加指定模运算.将某个 3rd 方库中的类型添加到您的类型类中也相当轻松.

The beauty of this approach is that you can supply an alternative definition of some typeclass, either controlling the implicit you want in scope via imports, or by explicitly providing the otherwise implicit argument. So it becomes possible to provide different ways of adding waveforms, or to specify modulo arithmetic for integer addition. It's also fairly painless to add a type from some 3rd-party library to your typeclass.

顺便说一句,这正是 2.8 集合 API 所采用的方法.虽然 sum 方法定义在 TraversableLike 而不是 List 上,并且类型类是 Numeric(它也包含更多的操作,而不仅仅是 zeroappend)

Incidentally, this is exactly the approach taken by the 2.8 collections API. Though the sum method is defined on TraversableLike instead of on List, and the type class is Numeric (it also contains a few more operations than just zero and append)

这篇关于Scala 中的类型类有什么用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆