Scala稍后定义的多个类型参数

时间:2017-01-11 20:31:56

标签: scala generics type-conversion generic-programming

我正在尝试将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))
    }
}

所以,我的问题是:有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:2)

实际上,您的第一个解决方案唯一的问题是您遗漏了repfrep之间的点。我还建议你不要明确使用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设法解析你的无点代码,完全忽略了过程中的括号。 让我们称它为一个不幸的语法怪癖: - )