簡體   English   中英

翻譯/編碼Haskell的`data Obj = forall a。 (顯示a)=> Scala中的Obj a`

[英]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] }

這在類型系統級別甚至可能嗎,還是我需要使用類似以下方式“捕獲”類型類實例:

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"]
*/

PS我想用T並在apply 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]] })#λ[_] }也已經起作用。 我希望還將對lambda類型提供一些語法支持。 kind-projector在這種情況下無濟於事(重復使用T )。 也許類似於Typelevel scalacval pair: ([T] => Tuple2[T, Show[T])[_])

另一個基本變化將是:

一個單一的基本概念(類型成員)可以為泛型,存在性類型,通配符和種類較多的類型賦予精確的含義。

因此,從編譯器的角度來看,這兩種形式都是等效的(以前,我們對元組進行解壓縮)。 我不確定是否存在100%的當前差異

PS 帶類型的麻煩幫助我了解了scala當前的類型系統怪癖。

我已經將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 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM