使用部分函数来模拟Scala中的Set,例如type alias:Set = Int =>布尔

时间:2016-08-11 01:44:57

标签: scala type-alias

我试图理解类型别名是如何工作的,并且通过扩展,如何在Set上建模的简单type Set = Int => Boolean类型将被重写为具有部分函数的类。

背景:据我所知,我可以像上面一样创建一个类型别名,并将其用作简单的功能集数据类型:

type Set = Int => Boolean
def union(s: Set, t: Set): Set = (x => s(x) || t(x))
def contains(s: Set, n: Int): Boolean = s(n)
val s1 = Set(3)
val s2 = Set(7)
val u1 = union(s1, s2)
contains(u1, 3)                // res4: Boolean = true

一切都很好。需要一些思考,但我知道它是如何工作的; u1 基本上成为部分功能:

union(s: (Int => Boolean), t: (Int => Boolean)): Int => Boolean

所以如果我想把它变成一个类,我的第一次尝试就是这样:

case class Set(v: Int) {
    def apply(i: Int) = i == v
    def contains(n: Int): Boolean = this(n)
    def union(n: Set): Set = (x => n(x) || apply(x))  // Missing param
}

但这不起作用(union的定义有编译错误,x是缺少的参数)。

在摆弄了一段时间后,我不知道如何在不采用更强制性的方法(如实际创建基于集合的Set类)的情况下实现类似的类型。必须有一种方法以纯粹的功能方式做到这一点......

1 个答案:

答案 0 :(得分:1)

您需要包裹Int => Boolean,而不是Int。所以

case class Set(f: Int => Boolean) {
  def apply(i: Int) = f(i)
  def union(s: Set) = Set(x => this(x) || s(x))
  // or Set(union(f, s.f)) to use existing definition of union
}

对于您自己对Set的定义,apply使其成为单元素集,因此您无法定义union:两个单元素的并集也就不足为奇了集合可以有多个元素。

Scala具有值和类型的单独名称空间。 type Setclass Set仅定义类型 Set,而val Setobject Setvar Set定义值,并且case class定义了两者。现在,Set(3)需要一个名为Set;在您的第一个代码示例中没有这样的值,因此它使用scala.Predef中的一个,它是自动导入的。 scala.Predef.Set(3)会返回scala.collection.Set[Int],这恰好会扩展Int => Boolean,这就是union(s1, s2)编译的原因。 case class定义了类型的值;因此,上面的代码Set(3)无法编译,因为使用此值而不是scala.Predef.Set