翻译/编码 Haskell 的 `data Obj = forall a. (显示 a)=> Scala 中的 Obj a`
Posted
技术标签:
【中文标题】翻译/编码 Haskell 的 `data Obj = forall a. (显示 a)=> Scala 中的 Obj a`【英文标题】:Translate/encode Haskell's `data Obj = forall a. (Show a) => Obj a` in Scala 【发布时间】:2015-01-25 14:49:54 【问题描述】:我还没想出如何在 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
任何见解将不胜感激!
【问题讨论】:
您回滚我的编辑是否有原因,所以 Haskell 代码及其输出现在像 Scala 一样突出显示? 对不起,我不是故意冒犯...之前的文本输出实际上更容易理解(我认为如果第一个 sn-p,where
和 True
不会突出显示不被认为是 Haskell,不是吗?)
我再次更改它以突出显示 Haskell 右侧,但单独保留输出。
只是好奇:你认为它像以前一样自动突出显示 Haskell sn-p 是什么?
它似乎将其突出显示为 Scala。
【参考方案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 我想在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
语法将被取消,以支持val pair: ( type λ[T] = Tuple2[T, Show[T]] )#λ[_]
,它也已经工作了。我希望type lambdas 也会有一些语法支持。 kind-projector 在这种情况下没有帮助(重复使用 T
)。可能类似于Typelevel scalac
:val pair: ([T] => Tuple2[T, Show[T])[_])
。
另一个根本性的变化是:
一个基本概念——类型成员——可以为泛型、存在类型、通配符和更高种类的类型赋予精确的含义。
所以从编译器的角度来看,这两种形式是等价的(以前我们解包元组)。 我不能 100% 确定目前有什么不同,如果有的话。
附: The Troubles with Types 帮助我了解了 scala 当前的类型系统怪癖。
【讨论】:
谢谢!只是好奇:为什么不能直接使用forSome
?
关于你的问题:def apply[T](x: T)(implicit show: Show[T]) = type T0 = T; val x0 = x; val show0 = show; new Obj type T = T0; val x = x0; val show = show0
@ErikAllik,谢谢!但我不确定哪个变种更丑:)
是的,内部结构更笨重,但外部世界看到了更好的界面:)
那么type ObjE = (T, Show[T]) forSome type T
怎么样?那么我该如何构造ObjE
的值呢?【参考方案2】:
我已将 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]
【讨论】:
以上是关于翻译/编码 Haskell 的 `data Obj = forall a. (显示 a)=> Scala 中的 Obj a`的主要内容,如果未能解决你的问题,请参考以下文章
什么是“从'grasshopper.data'导入{obj,string};”我很抱歉,愚蠢的编码器