0

I am trying to do this

data Foo a = Foo a
data FooWrapper = FooWrapper (forall a. Foo a)

foo = [FooWrapper (Foo 0), FooWrapper (Foo "")]

But there is an error

Could not match type

Int

with type

a0
ais
  • 2,514
  • 2
  • 17
  • 24
  • What is it you're trying to do? I ask because an array with elements of different types isn't going to be very useful without some sort of constraint on the element types. This is usually considered to be an anti-pattern in Haskell. – Phil Freeman Mar 14 '16 at 17:15
  • `data Foo a b = Foo a b` `foo1 :: Foo Int String` `foo2 :: Foo Int Int` I what to create a function that could work with array of Foo even if their second parameters have the different types `doSomething [foo1, foo2]` because the function only use first parameter. – ais Mar 14 '16 at 17:40

2 Answers2

1

Existential types don't quite work the same in PureScript as they do in Haskell, so usually we use the purescript-exists library for this kind of thing.

The equivalent using Exists would be:

import Data.Exists (Exists(), mkExists)

data Foo a = Foo a
data FooWrapper = FooWrapper (Exists Foo)

foo = [FooWrapper (mkExists (Foo 0)), FooWrapper (mkExists (Foo ""))]

I suppose in this case you probably don't need FooWrapper at all and could just have an array of Exists Foo.

gb.
  • 4,629
  • 1
  • 20
  • 19
  • Is it possible to use type class constrains with `Exists`? `data FooWrapper = FooWrapper (forall a. Show a => Foo a)` For example, how can I get `["0", ""] :: Array String` from `[(mkExists (Foo 0)), (mkExists (Foo ""))]`? – ais Mar 14 '16 at 18:26
  • Yes, you need to add the dictionary into the wrapper type somehow. An alternative is to encode the existential type using `forall`, e.g. `type SomeShow = forall r. (forall a. Show a => a -> r) -> r`. – Phil Freeman Mar 14 '16 at 19:45
  • @PhilFreeman Could you show a full code of `getStrings` http://stackoverflow.com/questions/36006483/how-to-use-type-constrains-with-exists ? – ais Mar 15 '16 at 08:55
0

I wanted to know how Phil Freeman's suggested approach works, so I gave it a try. This is a working example of storing a type class instance with its value by using a rank-n type.

module Example where

import Prelude (class Show, Unit, discard, pure, show, unit, ($))

import Effect (Effect)
import Effect.Console (log)


newtype Showable = Showable (forall r. (forall a. Show a => a -> r) -> r)

instance showShowable :: Show Showable where
  show (Showable f) = f show

mkShowable :: forall s . Show s => s -> Showable
mkShowable s = Showable (\f -> f s)

showables :: Array Showable
showables = [mkShowable 1, mkShowable "a string", mkShowable { foo : "bar" } ]

main :: Effect Unit
main = do
  log $ show showables
  pure unit

The newtype is not really necessary for storing, but i wanted to create an instance of Show for the type itself .

frabbit
  • 33
  • 5