Scala 中较高类型类型 class 实例中的两个参数函数,如何将这个简单的 Haskell 代码转换为 Scala?
Two parameter functions in type class instances of higher kinded types in Scala, how to translate this simple Haskell code to 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?
尝试将实例创建为 object
s 不是正确的方法。只创建实现类型 class.
的匿名 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 }
的糖)。为了解决这个问题,我们需要引入一个通用参数(在 whole 实例上进行量化)。放置它的自然位置是 object
,但这是第二个问题:对象不接受通用参数。
为什么要用implicit def
implicit def
(不带参数)非常适合制作类型 class 实例。您可以:
- 引入类型变量作为方法的泛型参数(正如我在上面所做的
B
)
引入超级class 约束作为这些泛型的界限。例如,
// 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")))
returns [[hiworld]]
.
以下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?
尝试将实例创建为 object
s 不是正确的方法。只创建实现类型 class.
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 }
的糖)。为了解决这个问题,我们需要引入一个通用参数(在 whole 实例上进行量化)。放置它的自然位置是 object
,但这是第二个问题:对象不接受通用参数。
为什么要用implicit def
implicit def
(不带参数)非常适合制作类型 class 实例。您可以:
- 引入类型变量作为方法的泛型参数(正如我在上面所做的
B
) 引入超级class 约束作为这些泛型的界限。例如,
// 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")))
returns[[hiworld]]
.