在Scala中键入参数与成员类型

jpa*_*cek 10 types scala type-inference

我想知道成员类型如何在Scala中工作,以及如何关联类型.

一种方法是使关联类型成为类型参数.这种方法的优点是我可以规定类型的方差,我可以确定子类型不会改变类型.缺点是,我无法从函数中的类型推断出类型参数.

第二种方法是使关联类型成为第二种类型的成员,其问题是我不能在子类型的关联类型上规定边界,因此,我不能在函数参数中使用类型(当x: X,X#T可能与xT没有任何关系)

一个具体的例子是:

我有一个DAT特征(可能没有类型参数)

trait DFA[S] { /* S is the type of the symbols in the alphabet */
  trait State { def next(x : S); }
  /* final type Sigma = S */
}
Run Code Online (Sandbox Code Playgroud)

我想创建一个函数来在输入序列上运行这个DFA,我想要

  • 该函数必须采用任何<% Seq[alphabet-type-of-the-dfa]输入序列类型
  • 函数调用者不需要指定类型参数,所有必须推断
  • 我想用具体的DFA类型调用函数(但是如果有一个解决方案,函数没有DFA的类型参数,那就没关系)
  • 字母表类型必须是不受约束的(即,必须有Char的DFA以及未知的用户定义的类)
  • 具有不同字母类型的DFA不是子类型

我试过这个:

def runDFA[S, D <: DFA[S], SQ <% Seq[S]](d : D)(seq : SQ) = ....
Run Code Online (Sandbox Code Playgroud)

这是有效的,除了这里没有推断出类型S,所以我必须在每个调用站点上编写整个类型参数列表.

def runDFA[D <: DFA[S] forSome { type S }, SQ <% Seq[D#Sigma]]( ... same as above
Run Code Online (Sandbox Code Playgroud)

这不起作用(无效循环引用类型D ???(它是什么?))

我还删除了type参数,创建了一个抽象类型Sigma并尝试在具体类中绑定该类型.runDFA看起来像

def runDFA[D <: DFA, SQ <% Seq[D#Sigma]]( ... same as above
Run Code Online (Sandbox Code Playgroud)

但这不可避免地遇到像"类型不匹配:预期dfa.Sigma,得到D#Sigma"这样的问题

有任何想法吗?指针?

编辑:

由于答案表明没有简单的方法可以做到这一点,有人可以详细说明为什么这是不可能的,什么必须改变,所以它有效?

我想要runDFA ro成为自由函数(不是方法)的原因是我想要其他类似的函数,比如自动机最小化,常规语言操作,NFA到DFA转换,语言分解等等,并且所有这些都在一个类中几乎与任何OO设计原则相反.

DRM*_*ver 3

首先,您不需要参数化 SQ <% Seq[S]。将方法参数写入Seq[S]。如果 SQ <% Seq[S] 则它的任何实例都可以隐式转换为 Seq[S] (这就是 <% 的含义),因此当作为 Seq[S] 传递时,编译器将自动插入转换。

此外,Jorge 所说的有关 D 上的类型参数并使其成为 DFA 上的方法的内容。由于内部类在 Scala 中的工作方式,我强烈建议将 runDFA 放在 DFA 上。在路径依赖类型起作用之前,处理某些外部类的内部类可能会有点痛苦。

所以现在你有

trait DFA[S]{
  ...

  def runDFA(seq : Seq[S]) = ...
}
Run Code Online (Sandbox Code Playgroud)

runDFA 突然变得很容易推断其类型参数:它没有任何类型参数。