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

标签 scala haskell typeclass implicit

以下 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
}

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

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

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

总之,如何将上述 Haskell 代码转换为 Scala ?

最佳答案

尝试将实例作为对象并不是正确的方法。最好只创建实现类型类的匿名 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 的糖) { 输入 x })。为了解决这个问题,我们需要引入一个通用参数(在整个实例上进行量化)。放置它的自然位置是在对象上,但这是第二个问题:对象不接受通用参数。

为什么使用隐式def

隐式 def(不带参数)非常适合创建类型类实例。您可以:

  • 引入类型变量作为方法的通用参数(就像我上面对 B 所做的那样)
  • 引入父类(super 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
    }
    

    这样,隐式地[C[A[A[String]]]].toStr(A(A("hi")))(A(A("world"))) 返回[[hiworld]]

关于scala - Scala 中高级类型的类型类实例中的两个参数函数,如何将这个简单的 Haskell 代码转换为 Scala?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43193602/

相关文章:

scala - 在gradle中使用sbt Avrohugger插件

java - Scala 集合标准实践

haskell - 如何使用randomRIO生成无限的随机数列表?

类型变量条件下的 Haskell 实例

Scala 流性能

mysql - 如果第二列值出现在第一列中,则 Spark Sql 查询从两列中选择值

haskell - 卡在 Haskell Wiki 中的 State Monad 示例中

Haskell 不在范围内 : Type constructor or class `PushInt'

haskell - 双向加法约束

haskell - 如何在 Haskell 中的类型之间建立排序