我正在尝试将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))
因此,我想出的解决方案是将破碎功能分成更多部分,这样我就可以使用相同的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))
}
}
所以,我的问题是:有没有更好的方法来解决这个问题?
答案 0 :(得分:2)
实际上,您的第一个解决方案唯一的问题是您遗漏了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设法解析你的无点代码,完全忽略了过程中的括号。
让我们称它为一个不幸的语法怪癖: - )