Translate/encode Haskell's `data Obj = forall a. (Show a) => Obj a` 在 Scala 中
Translate/encode Haskell's `data Obj = forall a. (Show a) => Obj a` in Scala
我一直想不出如何在 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] }
这在类型系统级别是否可能,或者我是否需要 "capture" 类型 class 实例使用类似这样的东西:
class Obj[T](val x: T)(implicit val: Show[T]) // ...or similar
如有任何见解,我们将不胜感激!
你几乎答对了:
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 我想在 apply
中使用 T
和 show
;不是 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
syntax will be eliminated in favour of val pair: ({ type λ[T] = Tuple2[T, Show[T]] })#λ[_] }
, which works already too. I hope there will be some syntax support for type lambdas as well. kind-projector doesn't help in this situation (repeated use of T
). Maybe something like in Typelevel scalac
中:val pair: ([T] => Tuple2[T, Show[T])[_])
。
另一个根本性的变化是:
A single fundamental concept – type members – can give a precise meaning to generics, existential types, wildcards, and higher-kinded types.
所以从编译器的角度来看,这两种形式是等价的(以前我们解包元组)。 我不是 100% 确定目前有什么区别,如果有的话。
P.S。 The Troubles with Types 帮助我理解了 scala 当前类型系统的怪癖。
我已经 "packaged" 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]
我一直想不出如何在 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] }
这在类型系统级别是否可能,或者我是否需要 "capture" 类型 class 实例使用类似这样的东西:
class Obj[T](val x: T)(implicit val: Show[T]) // ...or similar
如有任何见解,我们将不胜感激!
你几乎答对了:
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 我想在 apply
中使用 T
和 show
;不是 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
syntax will be eliminated in favour of val pair: ({ type λ[T] = Tuple2[T, Show[T]] })#λ[_] }
, which works already too. I hope there will be some syntax support for type lambdas as well. kind-projector doesn't help in this situation (repeated use of T
). Maybe something like in Typelevel scalac
中:val pair: ([T] => Tuple2[T, Show[T])[_])
。
另一个根本性的变化是:
A single fundamental concept – type members – can give a precise meaning to generics, existential types, wildcards, and higher-kinded types.
所以从编译器的角度来看,这两种形式是等价的(以前我们解包元组)。 我不是 100% 确定目前有什么区别,如果有的话。
P.S。 The Troubles with Types 帮助我理解了 scala 当前类型系统的怪癖。
我已经 "packaged" 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]