[英]Translate/encode Haskell's `data Obj = forall a. (Show a) => Obj a` in Scala
I've not been able to come up with how to encode Obj
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]
when run, the above produces the following output: 运行时,上面的代码会产生以下输出:
[Obj "hello",Obj 3,Obj True]
In Scala, however, this does not seem to compile: 但是,在Scala中,这似乎无法编译:
forSome { type T; implicit val ev: Show[T] }
and neither does this: 而且也不是:
forSome { type T : Show[T] }
Is this even possible at the type system level, or do I need to "capture" the type class instance using something like this: 这在类型系统级别甚至可能吗,还是我需要使用类似以下方式“捕获”类型类实例:
class Obj[T](val x: T)(implicit val: Show[T]) // ...or similar
Any insight would be appreciated! 任何见识将不胜感激!
You got it almost right: 您几乎完全正确:
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"]
*/
PS I'd like to use T
and show
in apply
; PS我想用
T
并在apply
show
; not U
and _show
. 不是
U
和_show
。 If someone knows how to avoid shadowing, I'll appreciate! 如果有人知道如何避免阴影,我将不胜感激!
Alternatively you could use forSome
: 或者,您可以使用
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) }
Here we have to use Tuple2
(or other auxillary type) to capture Show
. 在这里,我们必须使用
Tuple2
(或其他辅助类型)来捕获Show
。 I like the previous variant more. 我更喜欢以前的变体。 For me it's easier to wrap a mind around a type member.
对我来说,将类型的成员缠起来更容易。
Also in Scala "Don Giovanni" forSome
syntax will be eliminated in favour of val pair: ({ type λ[T] = Tuple2[T, Show[T]] })#λ[_] }
, which works already too. 同样在Scala中,“ Don Giovanni”
forSome
语法将被取消,而使用val pair: ({ type λ[T] = Tuple2[T, Show[T]] })#λ[_] }
也已经起作用。 I hope there will be some syntax support for type lambdas as well. 我希望还将对lambda类型提供一些语法支持。 kind-projector doesn't help in this situation (repeated use of
T
). kind-projector在这种情况下无济于事(重复使用
T
)。 Maybe something like in Typelevel scalac
: val pair: ([T] => Tuple2[T, Show[T])[_])
. 也许类似于Typelevel
scalac
: val pair: ([T] => Tuple2[T, Show[T])[_])
。
Another foundational change will be: 另一个基本变化将是:
A single fundamental concept – type members – can give a precise meaning to generics, existential types, wildcards, and higher-kinded types.
一个单一的基本概念(类型成员)可以为泛型,存在性类型,通配符和种类较多的类型赋予精确的含义。
So the both forms will be equivalent from the point of view of the compiler (in former we unpack the tuple). 因此,从编译器的角度来看,这两种形式都是等效的(以前,我们对元组进行解压缩)。 I'm not 100% sure what are the differences currently, if there are any .
我不确定是否存在100%的当前差异 。
PS The Troubles with Types helped me understand scala's current type system quirks. PS 带类型的麻烦帮助我了解了scala当前的类型系统怪癖。
I've "packaged" Oleg's answer into this generic and (seemingly) reusable structure: 我已经将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 }
}
then, data Obj = forall a. (Show a) => Obj a
那么,
data Obj = forall a. (Show a) => Obj a
data Obj = forall a. (Show a) => Obj a
can be implemented like this: 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]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.