翻译/编码 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,whereTrue 不会突出显示不被认为是 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 中使用Tshow;不是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};”我很抱歉,愚蠢的编码器

Scala中的Haskell“forall”翻译

将“为啥函数式编程很重要”翻译成 Haskell

如何在 Haskell 中序列化/反序列化通过网络发送的对象?

将定点运算符翻译成 Haskell 语言

从 Haskell 翻译的 Python 中,Count 懒惰地运行