As an exercise I'm trying to recreate Lisp's apply in Haskell. I do not intend to use this for any practical purpose, I just think it's a nice opportunity to get more familiar with Haskell's type system and type systems in general. (So I am also not looking for other people's implementations.)
My idea is the following: I can use GADTs to "tag" a list with the type of the function it can be applied to. So, I redefine Nil and Cons in a similar way that we would encode list length in the type using a Nat definition, but instead of using Peano numbers the length is in a way encoded in the tagging function type (i.e. length corresponds to the number of arguments to the function).
Here is the code I have so far:
{-# LANGUAGE GADTs #-}
-- n represents structure of the function I apply to
-- o represents output type of the function
-- a represents argument type of the function (all arguments same type)
data FList n o a where
-- with Nil the function is the output
Nil :: FList o o a
-- with Cons the corresponding function takes one more argument
Cons :: a -> FList f o a -> FList (a -> f) o a
args0 = Nil :: FList Int Int Int -- will not apply an argument
args1 = Cons 1 args0 -- :: FList (Int -> Int) Int Int
args2 = Cons 2 args1 -- :: FList (Int -> Int -> Int) Int Int
args3 = Cons 3 args2 -- :: FList (Int -> Int -> Int -> Int) Int Int
listApply :: (n -> o) -> FList (n -> o) o a -> o
-- I match on (Cons p Nil) because I always want fun to be a function (n -> o)
listApply fun (Cons p Nil) = fun p
listApply fun (Cons p l) = listApply (fun p) l
main = print $ listApply (+) args2
In the last line, my idea would be that (+) will be of type Int -> Int -> Int, where Int -> Int corresponds to the n in (n -> o) and o corresponds to the last Int (the output) [1]. As far as I can tell, this type seems to work out with the type of my argsN definitions.
However, I get two errors, of which I will state the component that seems relevant to me:
test.hs:19:43:
Could not deduce (f ~ (n0 -> f))
from the context ((n -> o) ~ (a -> f))
bound by a pattern with constructor
Cons :: forall o a f. a -> FList f o a -> FList (a -> f) o a,
in an equation for ‘listApply’
and
test.hs:21:34:
Couldn't match type ‘Int’ with ‘Int -> Int’
Expected type: FList (Int -> Int -> Int) (Int -> Int) Int
Actual type: FList (Int -> Int -> Int) Int Int
In the second argument of ‘listApply’, namely ‘args2’
I'm not sure how to interpret the first error. The second error is confusing me since it does not match with my interpretation stated marked with [1] earlier.
Any insights into what is going wrong?
P.S: I'm more than willing to learn about new extensions if that would make this work.
You got it almost right. Recursion should follow the structure of GADT:
{-# LANGUAGE GADTs #-}
-- n represents structure of the function I apply to
-- o represents output type of the function
-- a represents argument type of the function (all arguments same type)
data FList n o a where
-- with Nil the function is the output
Nil :: FList o o a
-- with Cons the corresponding function takes one more argument
Cons :: a -> FList f o a -> FList (a -> f) o a
args0 = Nil :: FList Int Int Int -- will not apply an argument
args1 = Cons 1 args0 -- :: FList (Int -> Int) Int Int
args2 = Cons 2 args1 -- :: FList (Int -> Int -> Int) Int Int
args3 = Cons 3 args2 -- :: FList (Int -> Int -> Int -> Int) Int Int
-- n, not (n -> o)
listApply :: n -> FList n o a -> o
listApply fun Nil = fun
listApply fun (Cons p l) = listApply (fun p) l
main = print $ listApply (+) args2
three :: Int
three = listApply (+) (Cons 2 (Cons 1 Nil))
oof :: String
oof = listApply reverse (Cons "foo" Nil)
true :: Bool
true = listApply True Nil -- True
-- The return type can be different than the arguments:
showplus :: Int -> Int -> String
showplus x y = show (x + y)
zero :: String
zero = listApply showplus (Cons 2 (Cons 1 Nil))
Must say, that this looks quite elegant!
Even OP doesn't ask for other's people implementation. You can approach problem a bit differently, resulting in a different looking but neat API:
{-# LANGUAGE KindSignatures #-}
{-# LANGuAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
import Data.Proxy
data N = O | S N
p0 :: Proxy O
p1 :: Proxy (S O)
p2 :: Proxy (S (S O))
p0 = Proxy
p1 = Proxy
p2 = Proxy
type family ArityNFun (n :: N) (a :: *) (b :: *) where
ArityNFun O a b = b
ArityNFun (S n) a b = a -> ArityNFun n a b
listApply :: Proxy n -> ArityNFun n a b -> ArityNFun n a b
listApply _ = id
three :: Int
three = listApply p2 (+) 2 1
oof :: String
oof = listApply p1 reverse "foo"
true :: Bool
true = listApply p0 True
showplus :: Int -> Int -> String
showplus x y = show (x + y)
zero :: String
zero = listApply p2 showplus 0 0
Here we could use Nat from GHC.TypeLits, but then we'd need UndecidableInstances. The added sugar is not worth the trouble in this example.
If you want to make polymorphic version, that's also possible, but then index is not (n :: Nat) (a :: *) but (as :: [*]). Also making plusN could be a nice exercise, for both encodings.
Not the same thing, but I suspect you'll be interested in the free applicative functor, which the free library provides. It goes something like this (based on the implementation in free, but using a :<**> constructor instead of Ap):
data Ap f a where
Pure :: a -> Ap f a
(:<**>) :: f x -> Ap f (x -> a) -> Ap f a
You can think of these as a heterogeneously-typed list with elements of types f x0, ..., f xn, terminated by Pure (f :: x0 -> ... -> xn -> a). This is like a "syntax tree" for applicative computations, allowing you to use the regular applicative methods to build up a "tree" that can be separately run by interpreter functions.
Exercise: implement the following instances:
instance Functor f => Functor (Ap f) where ...
instance Functor f => Applicative (Ap f) where ...
Hint: the Applicative laws provide a recipe that you can use to implement these.
Related
I was given a puzzle to do the following in Haskell,
f takes two functions, function a and function b. Function a takes na inputs and returns a Num type and function b takes nb inputs and returns a Num type. f returns a new function of arity na+nb that applies a to the first na arguments, nb to the rest of the arguments and returns their sum.
In mathematics I would write this as:
My first naïve attempt at this in Haskell was:
f a b = flip ((+) . a) . b
But this only works if a is a unary function.
After this I thought about the puzzle for a long while without being able to come up with even an idea for how I might do this. This is the first time in a long time I have been this utterly stumped in Haskell.
How might I solve this puzzle? Is there a solution to this puzzle? (I was given this puzzle by a friend and I don't believe they had a actual solution in mind at the time)
Here's a pretty simple approach using type families that works monomorphically in the numeric type (e.g., specialized to Int). We'll need a few extensions:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
The function f will be defined in a type class:
class VarArgs r s where
type F r s
f :: r -> s -> F r s
and we'll handle the following cases. If the type of the first function is of form a :: Int -> r, we'll use the following instance to gobble an argument x and feed it to a:
instance VarArgs r s => VarArgs (Int -> r) s where
type F (Int -> r) s = Int -> F r s
f :: (Int -> r) -> s -> Int -> F r s
f a b x = f (a x) b
This has the effect of recursing on the type of a until it's of the form Int. Then, we'll use a similar instance to recurse on the type b :: Int -> s:
instance VarArgs Int s => VarArgs Int (Int -> s) where
type F Int (Int -> s) = Int -> F Int s
f :: Int -> (Int -> s) -> Int -> F Int s
f a b x = f a (b x)
Ultimately, both functions will be reduced to 0-ary functions of type a, b :: Int, and we can use the terminal instance:
instance VarArgs Int Int where
type F Int Int = Int
f :: Int -> Int -> Int
f a b = a + b
Here's a little test to prove it works:
times2 :: Int -> Int -> Int
times2 x y = x * y
times3 :: Int -> Int -> Int -> Int
times3 x y z = x * y * z
foo :: [Int]
foo = [ f times2 times2 1 2 3 4
, f times2 times3 1 2 3 4 5
, f times3 times2 1 2 3 4 5
, f times3 times3 1 2 3 4 5 6]
and loading this into GHCi gives:
> foo
[14,62,26,126]
>
Generalizing this to be polymorphic in any Num type doesn't seem to be straightforward. Replacing the Int type with a constrained Num n type leads to errors regarding conflicting family instance declarations.
This is easy and simple - much simpler than #K.A.Buhr's type family approach, in my opinion - if you tweak your representation of an n-ary function, instead using a unary function of an n-dimensional vector.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
import Prelude hiding (splitAt)
import Data.Bifunctor
The usual suspects: (type-level) natural numbers, their (value-level) singletons, type-level addition, and vectors.
data Nat = Z | S Nat
data Natty n where
Zy :: Natty Z
Sy :: Natty n -> Natty (S n)
type family n + m where
Z + m = m
S n + m = S (n + m)
data Vec n a where
Nil :: Vec Z a
(:>) :: a -> Vec n a -> Vec (S n) a
splitAt takes a runtime Natty - it needs to know at runtime where to split the vector - and a vector that is at least as long as the Natty.
splitAt :: Natty n -> Vec (n + m) a -> (Vec n a, Vec m a)
splitAt Zy xs = (Nil, xs)
splitAt (Sy n) (x :> xs) =
let (ys, zs) = splitAt n xs
in (x :> ys, zs)
Then your f, which I'm calling splitApply, is a straightforward application of splitAt.
splitApply :: Natty n -> (Vec n a -> b) -> (Vec m a -> c) -> Vec (n + m) a -> (b, c)
splitApply at f g xs = bimap f g $ splitAt at xs
(I haven't bothered to show the "add the results" part, because it's so simple that I bored myself writing it. You could argue that, since Hask is a monoidal category, (,) represents a sort of addition anyway.)
How would I use pattern matching in order to exclude certain types of inputs? For instance given the following:
f list k =
if null list
then []
else head list + k : f (tail list) k
How can I use pattern matching to make f s/t it only allows Int and Integer but not Double or Float?
As suchtgott explained, you should not actually try to limit your function to exactly Int and Integer; you probably want to use an Integral constraint.
Suppose, for fun, that you really did want to limit it just like that. The way to do this in Haskell 98 is a bit weird (jump down to the break to see how this is done in GHC Haskell:
class Integral a => IntOrInteger a where
intOrInteger :: Either (f a -> f Int) (f a -> f Integer)
instance IntOrInteger Int where
intOrInteger = Left id
instance IntOrInteger Integer where
intOrInteger = Right id
How do you use such a thing? Well, to start off with
intOrIntegerSimple :: IntOrInteger a => Either (a -> Int) (a -> Integer)
intOrIntegerSimple = case intOrInteger of
Left f -> Left (runIdentity . f . Identity)
Right f -> Right (runIdentity . f . Identity)
But how do you flip it around, and turn an Int or Integer back to an instance of IntOrInteger?
newtype Switch f a i = Switch {runSwitch :: f i -> f a}
intOrInteger' :: IntOrInteger a => Either (f Int -> f a) (f Integer -> f a)
intOrInteger' = case intOrInteger of
Left f -> Left (runSwitch (f (Switch id)))
Right f -> Right (runSwitch (f (Switch id)))
intOrIntegerSimple' :: IntOrInteger a => Either (Int -> a) (Integer -> a)
intOrIntegerSimple' = case intOrInteger' of
Left f -> Left (runIdentity . f . Identity)
Right f -> Right (runIdentity . f . Identity)
When you don't really care whether you have an Int or an Integer, but want to be sure you really have one of them, you have to watch out for invalid instances. What might an invalid instance look like? This is one option:
instance IntOrInteger Word where
intOrInteger = Left (const undefined)
To just test that the instance is valid, you can use this (importing Data.Proxy):
ensureIntOrInteger :: IntOrInteger a => Proxy a -> ()
ensureIntOrInteger p = case intOrInteger of
Left f -> f p `seq` ()
Right f -> f p `seq` ()
The result of ensureIntOrInteger will be defined if and only if the type a is actually an Int or an Integer.
Nice; it works. But in practice it's pretty nasty to use. You can do much better with a few GHC extensions:
{-# LANGUAGE GADTs, TypeFamilies, TypeOperators, ConstraintKinds,
UndecidableInstances, UndecidableSuperClasses, DataKinds #-}
-- In 8.0 and later, Constraint is also available from Data.Kind
import GHC.Exts (Constraint)
import Data.Type.Equality ((:~:)(..))
import GHC.TypeLits (TypeError, ErrorMessage (..))
type family IntOrIntegerC a :: Constraint where
IntOrIntegerC Int = ()
IntOrIntegerC Integer = ()
IntOrIntegerC t = TypeError ('ShowType t :<>:
'Text " is not an Int or an Integer.")
class (Integral a, IntOrIntegerC a) => IntOrInteger a where
intOrInteger :: Either (a :~: Int) (a :~: Integer)
instance IntOrInteger Int where
intOrInteger = Left Refl
instance IntOrInteger Integer where
intOrInteger = Right Refl
With this formulation, the IntOrIntegerC constraint family blocks out any invalid types without your needing to do anything, giving a useful error message if someone tries to write a bogus instance. And if you actually do need to use the equality evidence, it's simply a matter of pattern matching on intOrInteger or using the various handy functions in Data.Type.Equality.
A point of style: using head and tail is generally discouraged in Haskell. We prefer to pattern match instead. Your function could be written
f [] _ = []
f (x : xs) k = x + k : f xs k
f/mapAdd implements a map. map is
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x : xs) = f x : map f xs
and can be used to formulate mapAdd:
Prelude> mapAdd n = map (+ n)
Prelude> mapAdd 3 [1,2,3,4]
[4,5,6,7]
GHCi's :type command tells you the automatically inferred type signature of mapAdd:
Prelude> :type mapAdd
mapAdd :: Num b => b -> [b] -> [b]
Here, mapAdd's bs are constrained to the general numerical type class Num. You can explicitly constrain to the type class Integral, which (basically) exclusively contains the data types Int, and Integer. Integral is a subclass of Num.
Prelude> :{
Prelude| mapAdd :: Integral a => a -> [a] -> [a]
Prelude| mapAdd n = map (+ n)
Prelude| :}
Prelude> :t mapAdd
mapAdd :: Integral a => a -> [a] -> [a]
mapAdd n = map (+ n) is pointfree for mapAdd n lst = map (+ n) lst.
You can create a dumb type class with instances only for Int and Integer and then use a type constraint:
class (Num a) => IntOrInteger a
instance IntOrInteger Int
instance IntOrInteger Integer
f :: (IntOrInteger a) => [a] -> a -> [a]
f list k =
if null list
then []
else head list + k : f (tail list) k
Then if you use f with Int, it will compile:
> f [1,2,3] 1
[2,3,4]
But it will not compile with Double:
> f [1,2,3] (1::Double)
<interactive>:19:1: error:
* No instance for (IntOrInteger Double) arising from a use of `f'
* In the expression: f [1, 2, 3] (1 :: Double)
In an equation for `it': it = f [1, 2, 3] (1 :: Double)
There are a lot of ways to constrain types, the most direct is just with type families.
type family Elem x xs :: Constraint where
Elem x (x ': xs) = ()
Elem x (y ': xs) = Elem x xs
Elem x '[] = TypeError ('ShowType x :<>: 'Text " is not a permitted type.")
type a ~~ b = Elem a b
function :: (a ~~ [Int, Integer], Num a) => [a] -> [a]
This allows you to white list a set of types. You won't know which one in particular you have though, that's more complicated.
However, you said you wanted to exclude certain types, so perhaps you want a black list. We simply flip the first and last case:
type family NotElem x xs :: Constraint where
NotElem x (x ': xs) = TypeError ('ShowType x :<>: 'Text " is a forbidden type.")
NotElem x (y ': xs) = NotElem x xs
NotElem x '[] = ()
type a !~~ b = NotElem a b
function :: (a !~~ [Double, Float], Num a) => [a] -> [a]
function will now accept any Num type that is not a Double or Float.
However, there's no reason to actually do any of this for your example function. You lose nothing at all by allowing it to work on the full range of Num types. In fact, these hijinks will at the least cost you a tiny smidgen more time on type checking, or if you go further and do reflection based things, possibly run time overhead as well.
I am an intermediate schemer, but only a haskell beginner. Here is my problem:
Suppose you have an associative binary operation, says (>>=). Is there a polyvariadic function p such that p (>>=) h g f e = h >>= g >>= f >>= e?
I am asking this question because this question says it is possible if the binary operation takes inputs of the same type. I wonder if this can be generalized.
EDIT-1: I try to modify the code in http://okmij.org/ftp/Haskell/vararg-fn.lhs (the section of Variable number of variably typed arguments) with little progress.
EDIT-2: Simplify the code a bit.
{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}
module Main where
class Lfold f a b | b -> a where
lfold :: (a -> (f a) -> (f a)) -> (f a) -> a -> b
instance Lfold f a (f a) where
lfold op rid x = op x rid
instance Lfold f a b => Lfold f a (a -> b) where
lfold op rid x y = lfold op (op x rid) y
test :: [String]
test = lfold (:) [] "a" "b" "c"
main :: IO ()
main = putStrLn $ show test
Yes, you can create such a function. It is very ugly however, and you will need to explicitly type every argument you are going to pass to make the compiler find the correct instance.
Starting from the polyvariadic function template you linked, I arrived at
{-# LANGUAGE FlexibleInstances, InstanceSigs, MultiParamTypeClasses #-}
class ImplicitChain m a r where
p :: m a -> r
instance Monad m => ImplicitChain m a (m a) where
p :: m a -> m a
p x = x
instance (Monad m, ImplicitChain m b r) => ImplicitChain m a ((a -> m b) -> r) where
p :: m a -> (a -> m b) -> r
p x f = p (x >>= f)
h :: Int -> [Int]
h = replicate 2
g :: Int -> [Int]
g = (:[])
f :: Int -> [Int]
f = flip enumFromTo 2
test :: [Int]
test = p [1::Int] h g f
But you were asking whether we can do more generic, so that the binary operation is an argument as well. Yes:
{-# LANGUAGE FlexibleInstances, InstanceSigs, MultiParamTypeClasses, UndecidableInstances #-}
class ImplicitVariadic a b r where
p :: (a -> b -> a) -> r
instance ImplicitVariadic a b (a -> a) where
p :: (a -> b -> a) -> a -> a
p _ x = x
instance (ImplicitVariadic a b (a -> r)) => ImplicitVariadic a b (a -> b -> r) where
p :: (a -> b -> a) -> a -> b -> r
p f x y = p f (f x y)
You can't (at least, not easily), because you need to know how many arguments you are getting ahead of time. Because all functions in Haskell are automatically curried, every function takes exactly one argument and returns one value. Even a simple binary operator takes one argument (the first operand) and returns a function that takes one argument (the second operand) and returns a result. That is,
a + b == (+) a b
== ((+) a) b
There is no way for your imaginary function p to know from its first argument how many other arguments are going to be given. That is, what should the type of p be?
p :: (a -> a -> a) -> a -- zero arguments?
p :: (a -> a -> a) -> a -> a -- one argument?
p :: (a -> a -> a) -> a -> a -> a -- two arguments?
p :: (a -> a -> a) -> a -> a -> a -> a -- three arguments?
Instead, the best you can do is use a fold, which takes an operation and a list of operands.
foldr (+) 0 [h, g, f, e] == h + g + f + e + 0 -- explicit first argument of 0
foldr1 (+) [h, g, f, e] == h + g + f + e -- assumes a list of at least one value
To see what I mean by "not easily", look at the implementation of printf in the Text.Printf module. Even that is not a good example, because the first argument carries information (the number of placeholders in the format string) that a binary operation alone does not.
Let's imagine I have an existential type T
T = ∃X { a :: X, f :: X -> Int}
Of which I produce a value
v :: T
v = pack {Int, { a = 0, f x = 0 } } as T
So :
users of this value are forbidden to know which type X is actually used in the implementation. In order to consume this value, their code has to be polymorphic in X
the implementor, on the other hand, is in full knowledge that X is actually an Int and can use the capacities of the underlying type as he wishes
I would like to know if there are variant of this mechanism which do not destroy evidence :
w, v = pack {Int, { a = 0, f x = 0 } } as T
s = unpack w v -- recovers type information
where w would be a value level proof of the type equation tying X to int. the idea would be to selectively reuse the implementation in another part of the code, and have non polymorphic code. to have the usual existential behaviour, we can just ignore the w returned.
I guess one could cast X to Int and abandon type safety, but that's another story: If I know the secret about v, wouldn't it make sense for me to be able to tell the secret to someone else and have the compiler verify that the secret only get used by code it has been given to.
Has it been tried / what's the most wrong part of this?
Use singletons
-- singleton for some types we are interested in
data S a where
Sint :: S Int
Sbool :: S Bool
-- existential type, with a singleton inside
data T where
T :: S a -> a -> (a -> Int) -> T
-- producer
t :: T
t = T Sint 3 succ
-- consumer
foo :: T -> Int
foo (T Sint n f) = f (n + 10)
foo (T Sbool True f) = 23
foo (T Sbool False f) = f 3
If you need to go full monty, use Typeable.
data T where
T :: Typeable a => a -> (a -> Int) -> T
-- consumer
foo :: T -> Int
foo (T x f) = case cast x of
Just n -> f ((n :: Int) + 10)
Nothing -> 12 -- more casts can be attempted here
Pack up a GADT which gives you a way to learn by pattern-matching what the existentially quantified type was. This is a way to emulate a dependent pair type.
data Ty a where
IntTy :: Ty Int
CharTy :: Ty Char
data T = forall a. T {
ty :: Ty a,
x :: a,
f :: a -> Int
}
consumeT :: T -> Int
consumeT (T IntTy x _) = {-# GHC knows (x :: Int) in this branch #-} x + 3
consumeT (T CharTy x f) = {-# GHC knows (x :: Char) in this branch #-} f x + 3
I'm learning about existential quantification, phantom types, and GADTs at the moment. How do I go about creating a heterogeneous list of a data type with a phantom variable? For example:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ExistentialQuantification #-}
data Toy a where
TBool :: Bool -> Toy Bool
TInt :: Int -> Toy Int
instance Show (Toy a) where
show (TBool b) = "TBool " ++ show b
show (TInt i) = "TInt " ++ show i
bools :: [Toy Bool]
bools = [TBool False, TBool True]
ints :: [Toy Int]
ints = map TInt [0..9]
Having functions like below are OK:
isBool :: Toy a -> Bool
isBool (TBool _) = True
isBool (TInt _) = False
addOne :: Toy Int -> Toy Int
addOne (TInt a) = TInt $ a + 1
However, I would like to be able to declare a heterogeneous list like so:
zeros :: [Toy a]
zeros = [TBool False, TInt 0]
I tried using an empty type class to restrict the type on a by:
class Unify a
instance Unify Bool
instance Unify Int
zeros :: Unify a => [Toy a]
zeros = [TBool False, TInt 0]
But the above would fail to compile. I was able to use existential quantification to do get the following:
data T = forall a. (Forget a, Show a) => T a
instance Show T where
show (T a) = show a
class (Show a) => Forget a
instance Forget (Toy a)
instance Forget T
zeros :: [T]
zeros = [T (TBool False), T (TInt 0)]
But this way, I cannot apply a function that was based on the specific type of a in Toy a to T e.g. addOne above.
In conclusion, what are some ways I can create a heterogeneous list without forgetting/losing the phantom variable?
Start with the Toy type:
data Toy a where
TBool :: Bool -> Toy Bool
TInt :: Int -> Toy Int
Now you can wrap it up in an existential without over-generalizing with the class system:
data WrappedToy where
Wrap :: Toy a -> WrappedToy
Since the wrapper only holds Toys, we can unwrap them and get Toys back:
incIfInt :: WrappedToy -> WrappedToy
incIfInt (Wrap (TInt n)) = Wrap (TInt (n+1))
incIfInt w = w
And now you can distinguish things within the list:
incIntToys :: [WrappedToy] -> [WrappedToy]
incIntToys = map incIfInt
Edit
As Cirdec points out, the different pieces can be teased apart a bit:
onInt :: (Toy Int -> WrappedToy) -> WrappedToy -> WrappedToy
onInt f (Wrap t#(TInt _)) = f t
onInt _ w = w
mapInt :: (Int -> Int) -> Toy Int -> Toy Int
mapInt f (TInt x) = TInt (f x)
incIntToys :: [WrappedToy] -> [WrappedToy]
incIntToys = map $ onInt (Wrap . mapInt (+1))
I should also note that nothing here so far really justifies the Toy GADT. bheklilr's simpler approach of using a plain algebraic datatype should work just fine.
There was a very similar question a few days ago.
In your case it would be
{-# LANGUAGE GADTs, PolyKinds, Rank2Types #-}
data Exists :: (k -> *) -> * where
This :: p x -> Exists p
type Toys = [Exists Toy]
zeros :: Toys
zeros = [This (TBool False), This (TInt 0)]
It's easy to eliminate an existential:
recEx :: (forall x. p x -> c) -> Exists p -> c
recEx f (This x) = f x
Then if you have a recursor for the Toy datatype
recToy :: (Toy Bool -> c) -> (Toy Int -> c) -> Toy a -> c
recToy f g x#(TBool _) = f x
recToy f g x#(TInt _) = g x
you can map a wrapped toy:
mapToyEx :: (Toy Bool -> p x) -> (Toy Int -> p y) -> Exists Toy -> Exists p
mapToyEx f g = recEx (recToy (This . f) (This . g))
For example
non_zeros :: Toys
non_zeros = map (mapToyEx (const (TBool True)) addOne) zeros
This approach is similar to one in #dfeuer's answer, but it's less ad hoc.
The ordinary heterogeneous list indexed by a list of the types of its elements is
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE GADTs #-}
data HList l where
HNil :: HList '[]
HCons :: a -> HList l -> HList (a ': l)
We can modify this to hold values inside some f :: * -> *.
data HList1 f l where
HNil1 :: HList1 f '[]
HCons1 :: f a -> HList1 f l -> HList1 f (a ': l)
Which you can use to write zeros without forgetting the type variables.
zeros :: HList1 Toy [Bool, Int]
zeros = HCons1 (TBool False) $ HCons1 (TInt 0) $ HNil1
Have you played with Data.Typeable? A Typeable constraint allows you to make guesses at the type hidden by the existential, and cast to that type when you guess right.
Not your example, but some example code I have lying around:
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeOperators #-}
import Data.Typeable
data Showable where
-- Note that this is an existential defined in GADT form
Showable :: (Typeable a, Show a) => a -> Showable
instance Show Showable where
show (Showable value) = "Showable " ++ show value
-- Example of casting Showable to Integer
castToInteger :: Showable -> Maybe Integer
castToInteger (Showable (value :: a)) =
case eqT :: Maybe (a :~: Integer) of
Just Refl -> Just value
Nothing -> Nothing
example1 = [Showable "foo", Showable 5]
example2 = map castToInteger example1