1

I've not been able to come up with how to encode Obj in Scala:

{-# 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:

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!

dfeuer
  • 48,079
  • 5
  • 63
  • 167
Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
  • Is there a reason you rolled back my edits, so the Haskell code and its output are now highlighted as though they were Scala? – dfeuer Jan 25 '15 at 17:10
  • sorry, didn't mean to offend... the text output was actually easier to comprehend before (and I think `where` and `True` wouldn't be highlighted if the first snippet weren't recognized as Haskell, no?) – Erik Kaplun Jan 25 '15 at 17:29
  • 1
    I changed it again to highlight the Haskell right, but left the output alone. – dfeuer Jan 25 '15 at 17:52
  • just curious: what do you think it was automatically highlighting the Haskell snippet as before? – Erik Kaplun Jan 25 '15 at 18:25
  • It was highlighting it as Scala, it seems. – dfeuer Jan 25 '15 at 18:34
  • but `where`, `True`, `data` and `instance` are not keywords in Scala, yet it was highlighting them... odd. – Erik Kaplun Jan 25 '15 at 19:27
  • I don't even know Scala. I just saw that it was highlighting `Obj` and `Show` the same in each. `Show` is a Prelude class in Haskell, which a highlighter could theoretically be stupid enough to care about, but `Obj` means nothing. – dfeuer Jan 25 '15 at 20:19
  • possible duplicate of [forall in Scala](http://stackoverflow.com/questions/7213676/forall-in-scala) – Erik Kaplun Feb 09 '15 at 13:05

2 Answers2

1

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

P.S I'd like to use T and show in apply; not U and _show. If someone knows how to avoid shadowing, I'll appreciate!


Alternatively you could use 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. 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. 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])[_]).

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.

P.S. The Troubles with Types helped me understand scala's current type system quirks.

Community
  • 1
  • 1
phadej
  • 11,947
  • 41
  • 78
  • thanks! just curious though: why is this not possible with `forSome` directly? – Erik Kaplun Jan 25 '15 at 15:03
  • as to your question: `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 } }` – Erik Kaplun Jan 25 '15 at 15:17
  • @ErikAllik, thanks! yet I'm not sure which variant is uglier :) – phadej Jan 25 '15 at 15:20
  • yes, the internals are clunkier but the outside world sees a nicer interface :) – Erik Kaplun Jan 25 '15 at 15:21
  • how about just `type ObjE = (T, Show[T]) forSome { type T }` then? and then how do I construct values of `ObjE` anyway? – Erik Kaplun Jan 25 '15 at 15:45
  • @ErikAllik, for that you cannot define `Show` instance (implicit val) easily, as there is `tuple2Show[A1, A2](implicit A1: Show[A1], A2: Show[A2]): Show[(A1, A2)]`. I'm sure that without wrapper (in Haskell type vs. newtype) around, you'll run in other troubles sooner or later as well. – phadej Jan 25 '15 at 15:52
  • just figured the same thing out on my own :) however, how do I define a `Show` for `ObjE` then? this doesn't work: `implicit val showObjE = Show.shows[ObjE] { x => x.pair._2.shows(x.pair._1) }`. – Erik Kaplun Jan 25 '15 at 15:55
  • @ErikAllik seems that you have to make an immediate value. Amended the answer with `showObjE` – phadej Jan 25 '15 at 16:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69554/discussion-between-oleg-grenrus-and-erik-allik). – phadej Jan 25 '15 at 16:10
0

I've "packaged" Oleg's answer into this generic and (seemingly) reusable structure:

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 can be implemented like this:

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]
Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111