How to avoid ugly code resolving this problem in Haskell (LANGUAGE extentions)? - haskell

I'm trying to write a program that simulates several creatures in a world. Basically the word sends a message over a list of creatures, and each creature gives his response, which in turn modifies the world.
I simplified what I'm trying to write in the following skeleton:
module Structure0 where
type Message = String
class Creature a where
processInput :: a -> Message -> Message
class World a where
processAction :: a -> b -> Message -> a
getCreatures :: a -> [b]
---- USAGE EXAMPLE ----
data Parrot = Parrot Int deriving Show
instance Creature Parrot where
processInput p s = s
data ParrotWorld = ParrotWorld [Parrot]
instance World ParrotWorld where
processAction w p s = w
getCreatures (ParrotWorld ps) = ps
In this code, I would that the parameter b in World class definition could assume all the data value that belong to the Creature class, something like:
processAction :: (Creature b) => a -> b -> Message -> a
Of course this examples aren't actual haskell code, lo let's pass illustrating two solution i found: the first, involving ExistentialQuantification:
{-# LANGUAGE ExistentialQuantification #-}
module Structure1 where
type Message = String
class Creature_ a where
processInput :: a -> Message -> Message
data Creature = forall c. Creature_ c => Creature c
instance Creature_ Creature where
processInput (Creature c) = processInput c
class World a where
processAction :: a -> Creature -> Message -> a
getCreatures :: a -> [Creature]
---- USAGE EXAMPLE ----
data Parrot = Parrot Int deriving Show
instance Creature_ Parrot where
processInput u s = s
data ParrotWorld = ParrotWorld [Creature]
instance World ParrotWorld where
processAction w p s = w
getCreatures (ParrotWorld ps) = ps
and the second, suggested by a kind guy on #haskell, using TypeFamilies:
{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
module Structure2 where
type Message = String
class Creature a where
processInput :: a -> Message -> Message
class (Creature (WorldCreature a)) => World a where
type WorldCreature a :: *
processAction :: a -> WorldCreature a -> Message -> a
getCreatures :: a -> [WorldCreature a]
---- USAGE EXAMPLE ----
data Parrot = Parrot Int deriving Show
instance Creature Parrot where
processInput p s = s
data ParrotWorld = ParrotWorld [Parrot]
instance World ParrotWorld where
type WorldCreature ParrotWorld = Parrot
processAction w p s = w
getCreatures (ParrotWorld ps) = ps
The main objective of this exercise is writing nice, elegant code.
So, the questions:
1) Should I express Creature as a Class instead of a Data?
(I'm doing this because a Creature is just a thing that implement the processInput function, and the many actual Creature implementations vary a lot; expecially during prototyping, I'd like not to change constantly the way in which a Creature pattern-matches.
2) The first solution I provide it's a bit ugly due to the boilerplate of maintaing both Creature and Creature_ versions. It has the benefit, however, that I can write mixed list of type [Creature]; Problem is that I can't pattern match against an object, id est things like:
\(Creature (Parrot x)) -> x
will fail due to type system. Can I make this all right?
3) The second solution has a problem of extendibility: say I would to construct a World with two types of creatures, say Parrot1 and Parrot2: how could I write the code in that case?
4) Am I structuring the code from a wrong point of view? Can I get an elegant solution just using plain haskell?
Thank you all :)
Carlo

1 class vs. data
Creature should be a class -- it describes an interface. Data should be used when you think of actually communicating values, or when you need to introduce a new type, wrapping an existing object with new behavior. For example, the Identity monad needs to wrap its values in a new type, or else you'd see instance Monad a for all a, which would cause conflicts with making anything else a Monad instance. But, you may need to wrap it.
2 lists
There is a way to do it with Data.Dynamic, but every time I've thought about doing it that way, I've been able to think of a way to do it with regular typeclasses instead. That said, I haven't written that much Haskell, and many libraries certainly rely on Data.Dynamic. If you want to really unbox a type, then you probably need to use it.
3 extensionality
As before, if you can leave type-specific functionality in the classes, that is best. It'd be most helpful if you could post an example, showing why you can't add another function to Creature. I'll assume you want to count numParrots in the example below, and you really do need to unbox them.
4 general comments
There are always many solutions to a problem. Based on your description, I'd think that "different worlds should entail different types of messages", not that a world should be tied to a specific type of creature (e.g. ParrotWorld).
another solution
here's my solution, using Data.Typeable. As mentioned above, it's my first time using it, so there may be a cleaner way.
{-# LANGUAGE DeriveDataTypeable,
ImpredicativeTypes,
NoMonomorphismRestriction,
RankNTypes,
ScopedTypeVariables #-}
module Test where
import Data.Typeable
type Message = String
class Typeable α => Creature α where
processInput :: α -> Message -> Message
-- box a creature
type BoxedC = (Message -> Message, Typeable β => Maybe β)
boxC :: Creature α => α -> BoxedC
boxC x = (processInput x, cast x)
class World α where
-- from your description, I'd not have Creature as part of this.
processAction :: α -> Message -> α
getCreatures :: α -> [BoxedC]
data Parrot = Parrot { parrotMessage :: String } deriving Typeable
data Lizard = Lizard { lizardMessage :: String } deriving Typeable
instance Creature Parrot where processInput p _ = (parrotMessage p)
instance Creature Lizard where processInput l _ = (lizardMessage l)
-- NOTE: Keep it simple and use a single World instance
-- (i.e. no typeclass) unless you need it.
data BaseWorld = BaseWorld { creatureList :: [BoxedC] }
instance World BaseWorld where
processAction w _ = w
getCreatures = creatureList
w = BaseWorld [boxC $ Parrot "parrot1", boxC $ Lizard "Lizard1"]
numParrots :: [BoxedC] -> Int
numParrots lst = foldl (+) 0 (map (go . snd) lst) where
go :: (forall β. Typeable β => Maybe β) -> Int
go (Just x :: Maybe Parrot) = 1
go _ = 0
test = numParrots (getCreatures w)
The idea is similar to yours: we box creatures before we put them in a list. The boxed elements have enough data so that you can unbox the type if you need to. One final thing to mention, though it's maybe not what you want here, is that closures are powerful. You don't need to keep a list of creatures if you can express their results as function composition. For example, in pseudocode, you could have a function
bind_creature :: Creature -> World -> World
which adds a creature to a world, and World has a type which returns its next iteration,
data World = World { nextWorld :: World }
which you set to itself for the base, namely w = World w. For simplicity, let's assume that each creature has a function
transformWorld :: Creature -> World -> World
then you could implement bind_creature like,
bind_creature c w = World { nextWorld = transformWorld c (nextWorld w) }
hope it helps.

Related

Resolving ambiguity in MultiParameterTypeClass

Based on the feedback to this question, I've used a MultiParamTypeClass to represent a reinforcement learning environment Environment, using 3 type variables: e for the environment instance itself (e.g. a game like Nim, below), s for the state data type used by the specific game, and a for the action data type used by the specific game.
{-# LANGUAGE MultiParamTypeClasses #-}
class MultiAgentEnvironment e s a where
baseState :: e -> s
nextState :: e -> s -> a -> s
reward :: (Num r) => e -> s -> a -> [r]
data Game = Game { players :: Int
, initial_piles :: [Int]
} deriving (Show)
data State = State { player :: Int
, piles :: [Int]} deriving (Show)
data Action = Action { removed :: [Int]} deriving (Show)
instance MultiAgentEnvironment Game State Action where
baseState game = State{player=0, piles=initial_piles game}
nextState game state action = State{player=player state + 1 `mod` players game,
piles=zipWith (-) (piles state) (removed action)}
reward game state action = [0, 0]
newGame :: Int -> [Int] -> Game
newGame players piles = Game{players=players, initial_piles=piles}
main = do
print "Hello, world!"
let game = newGame 2 [3,4,5]
print game
As expected, I'm running into ambiguity issues already. See below, where the action type variable a is deemed ambiguous within the typeclass Environment.
(base) randm#soundgarden:~/Projects/games/src/Main$ ghc -o basic basic.hs
[1 of 1] Compiling Main ( basic.hs, basic.o )
basic.hs:4:5: error:
• Could not deduce (MultiAgentEnvironment e s a0)
from the context: MultiAgentEnvironment e s a
bound by the type signature for:
baseState :: forall e s a. MultiAgentEnvironment e s a => e -> s
at basic.hs:4:5-23
The type variable ‘a0’ is ambiguous
• In the ambiguity check for ‘baseState’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method:
baseState :: forall e s a. MultiAgentEnvironment e s a => e -> s
In the class declaration for ‘MultiAgentEnvironment’
|
4 | baseState :: e -> s
| ^^^^^^^^^^^^^^^^^^^
How do I resolve this ambiguity? Am I mistakenly using typeclasses to implement interfaces (i.e. baseState, nextState, reward)?
While you could turn on AllowAmbiguousTypes, that will only push your problem further down the road. That is, eventually, you'll try to call baseState, and GHC will need to know what a is. There are three good options you have:
Use functional dependencies,
Use associated type families, or
Don't use a class for this.
Let's look at each option in detail.
Functional Dependencies
The problem that GHC is having is that it knows which e and s you want to use when you call a function like baseState (it can determine those from the input and output of the baseState function), but it doesn't know which a to use. For all GHC knows, there may be multiple instantiations of MultiAgentEnvironment that could work for a given e and s. With functional dependencies, you can tell GHC that a given e and s totally define what the a should be. In plain English, by putting in a functional dependency on a, you're saying that for any given environment and state, there is only one possible action type that makes sense. If this is true, then you add them like so:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
class MultiAgentEnvironment e s a | e s -> a where
baseState :: e -> s
nextState :: e -> s -> a -> s
reward :: (Num r) => e -> s -> a -> [r]
Since each one of your functions have e and s in them, a is the only type parameter that could have been ambiguous, and with this fundep, it's not ambiguous anymore. That said, if you know that the environment type determines both the state and action unambiguously (that is, a given environment can only ever have one possible state and action type), then you can use two fundeps to lower the ambiguity even more, as in:
class MultiAgentEnvironment e s a | e -> s a where
Associated Type Families
Functional Dependencies have a bit of a bad reputation, and the more modern alternative is typically to use associated type families. In practice, for your purposes, they work very similarly. Once again, you have to be okay with the environment type determining the action type (and, perhaps, the state type). If so, you write it like this:
{-# LANGUAGE TypeFamilies #-}
class MultiAgentEnvironment e where
type EState e
type EAction e
baseState :: e -> EState e
nextState :: e -> EState e -> a -> EState e
reward :: (Num r) => e -> EState e -> EAction e -> [r]
Then, when you create your instance, it will look like:
instance MultiAgentEnvironment Game where
type EState Game = State
type EAction Game = Action
baseState game = State{player=0, piles=initial_piles game}
nextState game state action = ...
Use a Data Type Instead Of a Class
The last option is to forgo using a type class altogether. Instead, you can make the data explicit by just representing it as a data type. For instance, you can define:
{-# LANGUAGE RankNTypes #-}
data MultiAgentEnvironment e s a = MultiAgentEnvironment
{ baseState :: e -> s
, nextState :: e -> s -> a -> s
, reward :: forall r. (Num r) => e -> s -> a -> [r]
}
Instead of making an instance of the type class, you just make a value of the data type:
gameStateActionMAE :: MultiAgentEnvironment Game State Action
gameStateActionMAE = MultiAgentEnvironment
{ baseState = \game -> State{player=0, piles=initial_piles game}
, nextState = \game state action -> State{player=player state + 1 `mod` players game,
piles=zipWith (-) (piles state) (removed action)}
, reward = \game state action -> [0, 0]
}
One nice advantage of this method is that you can make multiple different MultiAgentEnvironments with the same types but that have different behaviors. Using them is pretty simple too: instead of having MultiAgentEnvironment e s a as a constraint, you now have it as just a regular old argument. In fact, if you turn on the RecordWildCards pragma, then any function that used to start with
foo :: MultiAgentEnvironment e s a => x -> y
foo x = ...
can now be written as
foo :: MultiAgentEnvironment e s a -> x -> y
foo mae#MultiAgentEnvironment{..} x = ...
and the body should be pretty much identical (well, unless the body calls a subfunction which requires the MultiAgentEnvironment, in which case you'll need to manually pass mae along).

Functions with higher kinds?

Suppose the following data types are defined:
data X a = X {getX :: a}
data Y a = Y {getY :: a}
data Z a = Z {getZ :: a}
Must there be three separate functions, getX, getY, and getZ? It seems to me that there could be a function defined something like this:
get :: forall (τ :: (* -> *)) (a :: *). τ a -> a
get (_ x) = x
Obviously this is not valid standard Haskell, but there are so many extensions to GHC that seem like they might have a solution (RankNTypes,ExistentialQuantification,DataKinds,etc.). Besides the simple reason of avoiding a tiny amount of typing, there is the benefit of avoiding the namespace pollution that the record solution creates. I suppose this is really just a more implicit solution than using a type class like this:
class Get f where
get :: f a -> a
However, it appears that defining a generic function would be more useful than a type class, because the fact that it is implicitly defined means it could be used in many more places, in the same way that ($) or (.) is used. So my question has three parts: is there a way to accomplish this, is it a good idea, and if not, what is a better way?
How about this type?
newtype Pred a = Pred (a -> Bool)
Or this one?
data Proxy a = Proxy
There's no way to get an a out of a Pred a. You can only put as in. Likewise, there's no way to get an a out of a Proxy a, because there aren't any as inside it.
So a function get :: forall f a. f a -> a can't exist in general. You need to use a type class to distinguish between those types f from which you can extract an a and those from which you can't.
Well, that unconstrained generic type of get certainly can't work. This would also allow you to extract, say, a Void value from Const () :: Const () Void.
You can however obtain a suitably constrained version of this function quite simply with generics. You still need a type class, but not need to define instances in the traditional sense. It ultimately looks like this:
{-# LANGUAGE TypeFamilies, DeriveGeneric, DeriveAnyClass #-}
import GHC.Generics
class Get τ where
get :: τ a -> a
data X a = X a deriving (Generic1, Get)
data Y a = Y a deriving (Generic1, Get)
data Z a = Z a deriving (Generic1, Get)
To actually get this to work, we only need two weird representation-type instances:
instance Get f => Get (M1 i t f) where get = get . unM1
instance Get Par1 where get = unPar1
Now the actual implementation for X, Y and Z can just use a default signature and reduce the extraction to the underlying type-representation. To this end, define the class thus:
{-# LANGUAGE DefaultSignatures #-}
class Get τ where
get :: τ a -> a
default get :: (Generic1 τ, Get (Rep1 τ)) => τ a -> a
get = get . from1

Binary instance for an existential

Given an existential data type, for example:
data Foo = forall a . (Typeable a, Binary a) => Foo a
I'd like to write instance Binary Foo. I can write the serialisation (serialise the TypeRep then serialise the value), but I can't figure out how to write the deserialisation. The basic problem is that given a TypeRep you need to map back to the type dictionary for that type - and I don't know if that can be done.
This question has been asked before on the haskell mailing list http://www.haskell.org/pipermail/haskell/2006-September/018522.html, but no answers were given.
You need some way that each Binary instance can register itself (just as in your witness version). You can do this by bundling each instance declaration with an exported foreign symbol, where the symbol name is derived from the TypeRep. Then when you want to deserialize you get the name from the TypeRep and look up that symbol dynamically (with dlsym() or something similar). The value exported by the foreign export can, e.g., be the deserializer function.
It's crazy ugly, but it works.
This can be solved in GHC 7.10 and onwards using the Static Pointers Language extension:
{-# LANGUAGE StaticPointers #-}
{-# LANGUAGE InstanceSigs #-}
data Foo = forall a . (StaticFoo a, Binary a, Show a) => Foo a
class StaticFoo a where
staticFoo :: a -> StaticPtr (Get Foo)
instance StaticFoo String where
staticFoo _ = static (Foo <$> (get :: Get String))
instance Binary Foo where
put (Foo x) = do
put $ staticKey $ staticFoo x
put x
get = do
ptr <- get
case unsafePerformIO (unsafeLookupStaticPtr ptr) of
Just value -> deRefStaticPtr value :: Get Foo
Nothing -> error "Binary Foo: unknown static pointer"
A full description of the solution can be found on this blog post, and a complete snippet here.
If you could do that, you would also be able to implement:
isValidRead :: TypeRep -> String -> Bool
This would be a function that changes its behavior due to someone defining a new type! Not very pure-ish.. I think (and hope) that one can't implement this in Haskell..
I have an answer that slightly works in some situations (not enough for my purposes), but may be the best that can be done. You can add a witness function to witness any types that you have, and then the deserialisation can lookup in the witness table. The rough idea is (untested):
witnesses :: IORef [Foo]
witnesses = unsafePerformIO $ newIORef []
witness :: (Typeable a, Binary a) => a -> IO ()
witness x = modifyIORef (Foo x :)
instance Binary Foo where
put (Foo x) = put (typeOf x) >> put x
get = do
ty <- get
wits <- unsafePerformIO $ readIORef witnesses
case [Foo x | Foo x <- wits, typeOf x == ty] of
Foo x:_ -> fmap Foo $ get `asTypeOf` return x
[] -> error $ "Could not find a witness for the type: " ++ show ty
The idea is that as you go through, you call witness on values of every type that you may plausibly encounter when deserialising. When you deserialise you search this list. The obvious problem is that if you fail to call witness before deserialisation you get a crash.

Haskell - How to avoid typing the same context over and over again?

I recently started a little hobby project, where I try to implement the trick-taking card-game Skat (for 3 players). To make it possible to have different kinds of players (like AI, network and local) playing together, I designed an interface using a typeclass Player:
class Monad m => Player p m | p -> m where
playerMessage :: Message answer -> p -> m (Either Error answer,p)
I use a StateT to wrap up those three players:
type PST a b c m x = StateT (Players a b c) m x
But now, I have to write a big pile of context in each type signature:
dealCards :: (Player a m, Player b m, Player c m, RandomGen g)
=> g -> PST a b c m (SomeOtherState,g)
How can I avoid writing this big context again and again?
The only thing you can observe from the player class is a function of type
playerMessage' :: Message answer -> m (Either Error answer, p)
Hence, you can eliminate the class entirely and use an ordinary data type
data Player m = Player { playerMessage'
:: Message answer -> m (Either Error answer, Player m) }
This is basically my previous answer.
An alternative solution is to move the context into the data type by using GADTs.
data PST a b c m x where
PST :: (Player a m, Player b m, Player c m)
=> StateT (Players a b c) m x -> PST a b c m x
In other words, the constraints become part of the data type.
The best solution is, in my opinion, to scrap the whole thing and redesign it along the lines of the TicTacToe example from my operational package. This design allows you to write each player (human, AI, replay,...) in a specialized monad and later inject everything into a common interpreter.
Update:
When I tried implementing dealCards I have realised that my solution decreases the type-safety by making the players interchangeable. This way you can easily use one player instead of the other which may be undesirable.
If you don't mind using ExistentialQuantification, I think it can (and should?) be used here. After all, the dealCards function should not care or know about a, b and c, right?
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
import Control.Monad.State
import System.Random
type Message answer = answer
type Error = String
class Monad m => Player p m | p -> m where
playerMessage :: Message answer -> p -> m (Either Error answer,p)
data SomePlayer m = forall p. Player p m => SomePlayer p
data Players m = Players (SomePlayer m) (SomePlayer m) (SomePlayer m)
type PST m x = StateT (Players m) m x
dealCards :: (RandomGen g, Monad m) => g -> PST m x
dealCards = undefined
I think it should be possible to eliminate the Monad constraint in a similar way.
Actually, in cases like this I feel like type classes are being overused. Maybe that's a Haskell novice speaking in me, but I'd write this instead:
data Player m = Player { playerMessage :: Message answer -> m (Either Error answer, Player m) }
Clearly the better answer is to have a design that doesn't need all those type parameters in the first place. However, if you really can't get rid of them, and to answer the question as posed, here's a trick I've played:
class (Storable.Storable (X, y), Y y) => Signal y
Now writing '(Signal y) => ...' will imply all the other typeclasses, and prevent implementation details like Storable from getting into every API. However, you have to declare instances for Signal. It's easy because it has no methods, but is probably mostly suitable for when you have few instances but many functions.

What does "exists" mean in Haskell type system?

I'm struggling to understand the exists keyword in relation to Haskell type system. As far as I know, there is no such keyword in Haskell by default, but:
There are extensions which add them, in declarations like these data Accum a = exists s. MkAccum s (a -> s -> s) (s -> a)
I've seen a paper about them, and (if I recall correctly) it stated that exists keyword is unnecessary for type system since it can be generalized by forall
But I can't even understand what exists means.
When I say, forall a . a -> Int, it means (in my understanding, the incorrect one, I guess) "for every (type) a, there is a function of a type a -> Int":
myF1 :: forall a . a -> Int
myF1 _ = 123
-- okay, that function (`a -> Int`) does exist for any `a`
-- because we have just defined it
When I say exists a . a -> Int, what can it even mean? "There is at least one type a for which there is a function of a type a -> Int"? Why one would write a statement like that? What the purpose? Semantics? Compiler behavior?
myF2 :: exists a . a -> Int
myF2 _ = 123
-- okay, there is at least one type `a` for which there is such function
-- because, in fact, we have just defined it for any type
-- and there is at least one type...
-- so these two lines are equivalent to the two lines above
Please note it's not intended to be a real code which can compile, just an example of what I'm imagining then I hear about these quantifiers.
P.S. I'm not exactly a total newbie in Haskell (maybe like a second grader), but my Math foundations of these things are lacking.
A use of existential types that I've run into is with my code for mediating a game of Clue.
My mediation code sort of acts like a dealer. It doesn't care what the types of the players are - all it cares about is that all the players implement the hooks given in the Player typeclass.
class Player p m where
-- deal them in to a particular game
dealIn :: TotalPlayers -> PlayerPosition -> [Card] -> StateT p m ()
-- let them know what another player does
notify :: Event -> StateT p m ()
-- ask them to make a suggestion
suggest :: StateT p m (Maybe Scenario)
-- ask them to make an accusation
accuse :: StateT p m (Maybe Scenario)
-- ask them to reveal a card to invalidate a suggestion
reveal :: (PlayerPosition, Scenario) -> StateT p m Card
Now, the dealer could keep a list of players of type Player p m => [p], but that would constrict
all the players to be of the same type.
That's overly constrictive. What if I want to have different kinds of players, each implemented
differently, and run them against each other?
So I use ExistentialTypes to create a wrapper for players:
-- wrapper for storing a player within a given monad
data WpPlayer m = forall p. Player p m => WpPlayer p
Now I can easily keep a heterogenous list of players. The dealer can still easily interact with the
players using the interface specified by the Player typeclass.
Consider the type of the constructor WpPlayer.
WpPlayer :: forall p. Player p m => p -> WpPlayer m
Other than the forall at the front, this is pretty standard haskell. For all types
p that satisfy the contract Player p m, the constructor WpPlayer maps a value of type p
to a value of type WpPlayer m.
The interesting bit comes with a deconstructor:
unWpPlayer (WpPlayer p) = p
What's the type of unWpPlayer? Does this work?
unWpPlayer :: forall p. Player p m => WpPlayer m -> p
No, not really. A bunch of different types p could satisfy the Player p m contract
with a particular type m. And we gave the WpPlayer constructor a particular
type p, so it should return that same type. So we can't use forall.
All we can really say is that there exists some type p, which satisfies the Player p m contract
with the type m.
unWpPlayer :: exists p. Player p m => WpPlayer m -> p
When I say, forall a . a -> Int, it
means (in my understanding, the
incorrect one, I guess) "for every
(type) a, there is a function of a
type a -> Int":
Close, but not quite. It means "for every type a, this function can be considered to have type a -> Int". So a can be specialized to any type of the caller's choosing.
In the "exists" case, we have: "there is some (specific, but unknown) type a such that this function has the type a -> Int". So a must be a specific type, but the caller doesn't know what.
Note that this means that this particular type (exists a. a -> Int) isn't all that interesting - there's no useful way to call that function except to pass a "bottom" value such as undefined or let x = x in x. A more useful signature might be exists a. Foo a => Int -> a. It says that the function returns a specific type a, but you don't get to know what type. But you do know that it is an instance of Foo - so you can do something useful with it despite not knowing its "true" type.
It means precisely "there exists a type a for which I can provide values of the following types in my constructor." Note that this is different from saying "the value of a is Int in my constructor"; in the latter case, I know what the type is, and I could use my own function that takes Ints as arguments to do something else to the values in the data type.
Thus, from the pragmatic perspective, existential types allow you to hide the underlying type in a data structure, forcing the programmer to only use the operations you have defined on it. It represents encapsulation.
It is for this reason that the following type isn't very useful:
data Useless = exists s. Useless s
Because there is nothing I can do to the value (not quite true; I could seq it); I know nothing about its type.
UHC implements the exists keyword. Here's an example from its documentation
x2 :: exists a . (a, a -> Int)
x2 = (3 :: Int, id)
xapp :: (exists b . (b,b -> a)) -> a
xapp (v,f) = f v
x2app = xapp x2
And another:
mkx :: Bool -> exists a . (a, a -> Int)
mkx b = if b then x2 else ('a',ord)
y1 = mkx True -- y1 :: (C_3_225_0_0,C_3_225_0_0 -> Int)
y2 = mkx False -- y2 :: (C_3_245_0_0,C_3_245_0_0 -> Int)
mixy = let (v1,f1) = y1
(v2,f2) = y2
in f1 v2
"mixy causes a type error. However, we can use y1 and y2 perfectly well:"
main :: IO ()
main = do putStrLn (show (xapp y1))
putStrLn (show (xapp y2))
ezyang also blogged well about this: http://blog.ezyang.com/2010/10/existential-type-curry/

Resources