Scala 中更高种类的类型类实例中的两个参数函数,如何将这个简单的 Haskell 代码转换为 Scala?



以下Haskell代码:

main = putStrLn $ "bla " ++ (toStr (A 1) (A 2))
--main2 = putStrLn $ "bla " ++ (toStr (A 1) (A "String")) -- does not compile, as it should
main3 = putStrLn $ "bla " ++ (toStr (A "String") (A "String"))
data A a = A a deriving Show -- (1) data type declaration 
class C a where -- (2) type class declaration
toStr :: a-> a->String
instance C (A a) where -- (3) instance declaration
toStr (A x) (A y) = "AA"

(大致)对应于以下 Scala 代码:

case class A[B](b:B) // (1) data type declaration
trait C[A] { // (2) type class declaration
def toStr: A =>A=> String
// this would correspond to "instance C (A a) where"
}

object Instance { 
implicit object Instance extends C[A[_]] { // (3) instance declaration
override def toStr: A[_] =>A[_] => String = x => x=> "AA"
//    override def toStr[T]: A[T] =>A[T] => String = x => x=> "AA" // this does not override anything, does not compile
}
}
object Main{
println(Instance.Instance.toStr(A(1))(A(2)))
println(Instance.Instance.toStr(A(1))(A("bla"))) // this compiles, but it should not
}

如何定义override def toStr: A[_] =>A[_] => String = x => x=> "AA",使println(Instance.Instance.toStr(A(1))(A("bla")))无法编译?

因为它(putStrLn $ "bla " ++ (toStr (A 1) (A "String")))不能在Haskell代码中编译?

我的尝试override def toStr[T]: A[T] =>A[T] => String = x => x=> "bla",但这不会编译,因为这不会覆盖C中的def toStr: A =>A=> String

综上所述,如何将上述 Haskell 代码翻译成 Scala?

尝试将实例设置为objects并不是正确的方法。几乎总是最好只制作实现类型类的匿名def

object Instance { 
// Corresponds to `instance C (A a)`
implicit def instance[T]: C[A[T]] = new C[A[T]] {
override def toStr: A[T] => A[T] => String = x => y => "AA"
}
}
object Main{
println(Instance.instance.toStr(A(1))(A(2)))
println(Instance.instance.toStr(A(1))(A("bla"))) // doesn't compile
}

那么你的方法有什么问题呢?问题的根源在于通配符_不需要相等 - 它们可以单独匹配不同的类型(回想一下,_只是x forSome { type x }的糖)。为了解决这个问题,我们需要引入一个通用参数(在整个实例上量化)。自然的地方是放在object上,但这是第二个问题:对象不接受泛型参数。

为什么要使用implicit def

implicit def(没有参数)非常适合创建类型类实例。您可以:

  • 在方法上引入类型变量作为泛型参数(就像我上面对B所做的那样)
  • 引入超类约束作为这些泛型的边界。例如

    // Corresponds to `instance C a => C (A a)`
    implicit def instance[T: C]: C[A[T]] = new C[A[T]] {
    override def toStr: A[T] => A[T] => String = x => y => (x,y) match {
    case (A(bx),A(by)) => "[" + implicitly[C[T]].toStr(bx)(by) + "]"
    }
    }
    // Corresponds to `instance C String`
    implicit val strInstance: C[String] = new C[String] {
    override def toStr: String => String => String = x => y => x + y
    }
    

    有了这个,implicitly[C[A[A[String]]]].toStr(A(A("hi")))(A(A("world")))返回[[hiworld]].

相关内容

  • 没有找到相关文章

最新更新