翻译/编码Haskell的`数据Obj = forall a。 (显示a)=>在斯卡拉的Obj a`

时间:2015-01-25 14:49:55

标签: scala haskell typeclass implicit existential-type

我无法想出如何在Scala中编码Obj

{-# LANGUAGE ExistentialQuantification #-}

data Obj = forall a. (Show a) => Obj a

instance Show Obj where show (Obj a) = "Obj " ++ show a

main = print $ show [Obj "hello", Obj 3, Obj True]

运行时,上面会产生以下输出:

[Obj "hello",Obj 3,Obj True]

然而,在Scala中,似乎没有编译:

forSome { type T; implicit val ev: Show[T] }

,这也不是:

forSome { type T : Show[T] }

这是否可以在类型系统级别,或者我需要"捕获"使用类似这样的类型类实例:

class Obj[T](val x: T)(implicit val: Show[T])  // ...or similar

任何见解都将受到赞赏!

2 个答案:

答案 0 :(得分:1)

你几乎是对的:

import scalaz._
import scalaz.Scalaz._

trait Obj {
  type T // existential type
  val x: T
  implicit val show: Show[T]
}

implicit val objSow: Show[Obj] = Show.shows[Obj] { (x: Obj) =>
  x.show.shows(x.x)
}

object Obj {
  /* "constructor" */
  def apply[U](_x: U)(implicit _show: Show[U]): Obj = new Obj {
    type T = U
    val x = _x
    val show = _show
  }
}

val test: List[Obj] = List(Obj(1), Obj(true), Obj("foo"))

/*
scala> test.shows
res0: String = [1,true,"foo"]
*/

P.S我想在T中使用showapply;不是U_show。如果有人知道如何避免阴影,我会很感激!


或者您可以使用forSome

import scala.language.existentials

trait ObjE {
  val pair: Tuple2[T, Show[T]] forSome { type T }
}

/* And to define Show instance we have to help compiler unify `T` in pair components. */
def showDepPair[T] = Show.shows[Tuple2[T, Show[T]]] { x => x._2.shows(x._1) }
implicit val showObjE = Show.shows[ObjE] { x => showDepPair.shows(x.pair) }

这里我们必须使用Tuple2(或其他辅助类型)来捕获Show。我更喜欢上一个版本。对我来说,围绕一个类型成员更容易。

同样在Scala "Don Giovanni" forSome中,语法将被取消,而val pair: ({ type λ[T] = Tuple2[T, Show[T]] })#λ[_] }也会有效。我希望type lambdas也会有一些语法支持。 kind-projector在这种情况下无效(重复使用T)。可能类似于Typelevel scalacval pair: ([T] => Tuple2[T, Show[T])[_])

另一个基本变化是:

  

单个基本概念 - 类型成员 - 可以为泛型,存在类型,通配符和更高级别的类型提供精确的含义。

因此,从编译器的角度来看,这两种形式都是等价的(以前我们解压缩元组)。 我不能100%确定当前有什么差异,如果有

P.S。 The Troubles with Types帮助我理解了scala当前的类型系统怪癖。

答案 1 :(得分:0)

我"包装" Oleg回答了这个通用和(看似)可重用的结构:

import scala.language.{ higherKinds, implicitConversions }

trait AnyWithTC[TC[_]] { type T; val x: T; implicit val ev: TC[T] }

// don't like the 'implicit' here; suggestions welcome
implicit def AnyWithTC[T, TC[_]](x: T)(implicit ev: TC[T]) = {
  type T0 = T; val x0 = x; val ev0 = ev
  new AnyWithTC[TC] { type T = T0; val x = x0; val ev = ev0 }
}

然后,data Obj = forall a. (Show a) => Obj a可以像这样实现:

type Obj = AnyWithTC[Show]
implicit val objShow = Show.shows[Obj] { x => "Obj " + x.show.shows(x.x)   }
val xs: List[Obj] = List(1, true, "hello")
println(xs.shows) // prints [Obj 1,Obj true, Obj hello]