1
data Foo a = Foo a

I can create an array of Exists https://github.com/purescript/purescript-exists

[(mkExists (Foo 0)), (mkExists (Foo "x"))]

How can I use type classes? I want to get ["0", "x"]

getStrings :: Array (Exists Foo) -> Array String
getStrings list = map (runExists get) list
  where
  get :: forall a. Show a => Foo a -> String
  get (Foo a) = show a

No type class instance was found for

Prelude.Show _0

The instance head contains unknown type variables. Consider adding a type annotation.

ais
  • 2,514
  • 2
  • 17
  • 24

1 Answers1

3

One option is to bundle up the show function in your definition of Foo, something like this:

import Prelude
import Data.Exists

data Foo a = Foo a (a -> String)

type FooE = Exists Foo

mkFooE :: forall a. (Show a) => a -> FooE
mkFooE a = mkExists (Foo a show)

getStrings :: Array FooE -> Array String
getStrings = map (runExists get)
  where
  get :: forall a. Foo a -> String
  get (Foo a toString) = toString a

--

items :: Array FooE
items = [mkFooE 0, mkFooE 0.5, mkFooE "test"]

items' :: Array String
items' = getStrings items
gb.
  • 4,629
  • 1
  • 20
  • 19
  • What are the other options? – ais Mar 15 '16 at 13:45
  • See [Phil's comment on the other question](http://stackoverflow.com/questions/35990022/how-can-i-create-an-array-with-polymorphic-data#comment59645787_35991626) - it roughly ends up as the same thing. Since there is no evidence that the existential `a` can be `show`n it means you need to provide that evidence somehow along with the value. – gb. Mar 15 '16 at 14:15
  • Why cannot the evidence be provided like this `data Foo a = Foo (Show a) => a `? – ais Mar 15 '16 at 14:31
  • That's a whole other can of worms, but the short answer is "because the type system doesn't support it", I'm afraid. Phil would probably have to give the detailed explanation too, if you really want it ;) – gb. Mar 15 '16 at 17:23
  • It's not possible right now. If you wrote this in Haskell's GADT notation, it'd be `data Foo where Foo :: (Show a) => a -> Foo`. What you wrote is equivalent to `data Foo where Foo :: ((Show a) => a) -> Foo`, which is not the same. Really you want to pair a dictionary with a value, which might be written as `data Foo = Foo (Show a *> a)`. Supporting types like that is a possibility, but we would have to decide what the correct typing rules would be. This is a good discussion to have on the GitHub issue. – Phil Freeman Mar 18 '16 at 04:40