Scala 后面定义的多类型参数
Scala Multiple type parameter that are defined later
我正在尝试将 Haskell 的通用库移植到 Scala。然而,我目前对我在 Scala 中解决通用 Crush 函数的方式并不满意。
我定义了以下处理来处理 Crush 函数。
trait FRep[G[_],F[_]]{
def frep[A](g1 : G[A]) : G[F[A]]
}
trait Crush[B,A]{
def selCrush : Assoc => A => B => B
}
接下来,我想定义crush函数,但是这里我运行遇到了问题。问题是我需要这个 FRep 特征来表示 Crush 函数,但是 frep 中的 G(Generic) 只允许 1 个参数。我使用 lambda 类型解决了这个问题,但我在定义函数时仍然遇到一些问题。这是我想要工作的方法:
def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]): B = {
def fCrush = new Crush[B,A]{
override def selCrush= _ => f
}
return(rep frep(fCrush).selCrush(asc)(x)(z))
}
这显然出错了,因为 crush 函数中的 A 参数与隐式 rep 变量中的 A lambda 类型不同,后者需要相同才能使用 Crush 函数。这是我收到的错误:
<pastie>:677: error: type mismatch;
found : x.type (with underlying type F[A])
required: A
return(rep frep(fCrush).selCrush(asc)(x)(z))
所以,我想到的解决方案是将 crush 函数拆分为更多部分,这样我就可以为 crush 函数使用相同的 A。这是当前编译的解决方案:
class CrushFunction[B,F[_]](asc : Assoc)(z : B)(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]){
def crush[A](f : A => B => B)(x : F[A]) : B = {
val crushVal = new Crush[B,A]{
override def selCrush: Assoc => A => B => B = _ => f
}
return(rep.frep(crushVal).selCrush(asc)(x)(z))
}
}
所以,我的问题是:有没有更好的方法来解决这个问题?
实际上,您的第一个解决方案唯一的错误是您遗漏了 rep
和 frep
之间的点。我还建议您不要显式使用 return
,也不要隐藏类型参数的名称 (A
):
def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[X] = Crush[B,X]})#AB,F]): B = {
def fCrush = new Crush[B,A]{
override def selCrush: Assoc => A => B => B = _ => f
}
rep.frep(fCrush).selCrush(asc)(x)(z)
}
现在您可能会问自己:如果所有错误都是缺少点,为什么会显示此错误消息?好吧,scala 支持中缀表示法。它将 a b c d e
解析为 a.b(c).d(e)
。但是你写了这样的东西:a b(c).d(e)
。这会使解析器感到困惑。您可以看到当您将 //print
附加到 REPL(我认为是 2.11.8 或更高版本)中的代码并按 TAB 键时会发生什么。
我为你过滤掉了所有的垃圾。 rep frep(fCrush).selCrush(asc)(x)(z)
被解析为:
rep.frep[A](fCrush.selCrush(asc)(x)(z))
在该表达式中 x
确实需要是类型 A
而不是 F[A]
。
老实说:对我来说,这有点像 scalac 设法解析你的无点代码的错误,完全忽略了过程中的括号。
让我们称之为不幸的语法怪癖:-)
我正在尝试将 Haskell 的通用库移植到 Scala。然而,我目前对我在 Scala 中解决通用 Crush 函数的方式并不满意。
我定义了以下处理来处理 Crush 函数。
trait FRep[G[_],F[_]]{
def frep[A](g1 : G[A]) : G[F[A]]
}
trait Crush[B,A]{
def selCrush : Assoc => A => B => B
}
接下来,我想定义crush函数,但是这里我运行遇到了问题。问题是我需要这个 FRep 特征来表示 Crush 函数,但是 frep 中的 G(Generic) 只允许 1 个参数。我使用 lambda 类型解决了这个问题,但我在定义函数时仍然遇到一些问题。这是我想要工作的方法:
def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]): B = {
def fCrush = new Crush[B,A]{
override def selCrush= _ => f
}
return(rep frep(fCrush).selCrush(asc)(x)(z))
}
这显然出错了,因为 crush 函数中的 A 参数与隐式 rep 变量中的 A lambda 类型不同,后者需要相同才能使用 Crush 函数。这是我收到的错误:
<pastie>:677: error: type mismatch;
found : x.type (with underlying type F[A])
required: A
return(rep frep(fCrush).selCrush(asc)(x)(z))
所以,我想到的解决方案是将 crush 函数拆分为更多部分,这样我就可以为 crush 函数使用相同的 A。这是当前编译的解决方案:
class CrushFunction[B,F[_]](asc : Assoc)(z : B)(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]){
def crush[A](f : A => B => B)(x : F[A]) : B = {
val crushVal = new Crush[B,A]{
override def selCrush: Assoc => A => B => B = _ => f
}
return(rep.frep(crushVal).selCrush(asc)(x)(z))
}
}
所以,我的问题是:有没有更好的方法来解决这个问题?
实际上,您的第一个解决方案唯一的错误是您遗漏了 rep
和 frep
之间的点。我还建议您不要显式使用 return
,也不要隐藏类型参数的名称 (A
):
def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[X] = Crush[B,X]})#AB,F]): B = {
def fCrush = new Crush[B,A]{
override def selCrush: Assoc => A => B => B = _ => f
}
rep.frep(fCrush).selCrush(asc)(x)(z)
}
现在您可能会问自己:如果所有错误都是缺少点,为什么会显示此错误消息?好吧,scala 支持中缀表示法。它将 a b c d e
解析为 a.b(c).d(e)
。但是你写了这样的东西:a b(c).d(e)
。这会使解析器感到困惑。您可以看到当您将 //print
附加到 REPL(我认为是 2.11.8 或更高版本)中的代码并按 TAB 键时会发生什么。
我为你过滤掉了所有的垃圾。 rep frep(fCrush).selCrush(asc)(x)(z)
被解析为:
rep.frep[A](fCrush.selCrush(asc)(x)(z))
在该表达式中 x
确实需要是类型 A
而不是 F[A]
。
老实说:对我来说,这有点像 scalac 设法解析你的无点代码的错误,完全忽略了过程中的括号。
让我们称之为不幸的语法怪癖:-)