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
Related
I'm playing with Rank-N-type and trying to type x x. But I find it counter intuitive that these two functions can be typed in the same way.
f :: (forall a b. a -> b) -> c
f x = x x
g :: (forall a b. a -> b) -> c
g x = x x x x x
I have also noticed that something like f x = x x ... x x (many xs) still has the same type.
Can anyone explain why it is the case?
The key is that x :: a -> b is a function that can provide a value of any type, no matter what argument is given. That means x can be applied to itself, and the result can be applied to x again, and so on and so on.
At least, that's what it promises the type checker it can do. The type checker isn't concerned about whether or not any such value exists, only that the types align. Neither f nor g can actually be called, because no such value of type a -> b exists (ignoring bottom and unsafeCoerce).
A simpler example
This is a phenomenon that can be observed whenever we use a variable which has a polymorphic type (like your x). The identity function id is perhaps the most famous example.
id :: forall a . a -> a
Here, all these expressions type check, and have type Int -> Int:
id :: Int -> Int
id id :: Int -> Int
id id id :: Int -> Int
id id id id :: Int -> Int
...
How is that possible? Well, the crux is that each time we write id we are actually meaning "the identity function on some unknown type a that should be inferred from the context". Crucially, each use of id has its own a.
Let's write id #T to mean the specific identity function on type T.
Writing
id :: Int -> Int
actually means
id #Int :: Int -> Int
which is straightforward. Instead, writing
id id :: Int -> Int
actually means
id #(Int -> Int) (id #Int) :: Int -> Int
where the first id now refers to the function space Int -> Int! And, of course,
id id id :: Int -> Int
means
(id #((Int -> Int) -> (Int -> Int))) (id #(Int -> Int)) (id #Int) :: Int -> Int
And so on. We do not realize that types get that messy since Haskell infers those for us.
The specific case
In your specific case,
g :: (forall a b. a -> b) -> c
g x = x x x x x
we can make that type check in many ways. A possible way is to define A ~ Int, B ~ Bool, T ~ (A -> B) and then infer:
g x = x #T #(T -> T -> T -> c) (x #A #B) (x #A #B) (x #A #B) (x #A #B)
I suggest to spend some time to realize that everything type checks. (Moreover our choices of A and B are completely arbitrary, and we could use any other types there. We could even use distinct As and Bs for each x, as long as the first x is suitably instantiated!)
It is then obvious that such inference is also possible even when x x x ... is a longer sequence.
This shouldn't really be any more surprising than the fact that
m :: (∀ a . a) -> (∀ a . a) -> (Int, Bool)
m p q = (p, q)
has the same type as
n :: (∀ a . a) -> (∀ a . a) -> (Int, Bool)
n p q = (q, p)
Much like in your example, this works because the universally-quantified argument can be used in lots of different way, with the compiler in each case choosing an appropriate type and enforcing x to act as having that type.
This is actually a rather contrived situation because types like ∀ a . a or ∀ a b . a->b are uninhabited (modulo ⊥), so you would never actually be able to use a RankN function with such an argument; pragmatically you wouldn't even write it either then!
Practically useful RankN functions usually impose some extra structure or typeclass constraint in their arguments, like
foo :: (∀ a . [a] -> [a]) -> ...
or
qua :: (∀ n . Num n => Int -> n -> n) -> ...
I have a very simple continuation function (avoided using Monads for simplicity sake):
data C a = C {unwrap :: (a -> a) -> a}
Essentially, I'm trying to perform different implementations based on input type, something similar to (sudo-code):
data Gadt a where
AString :: String -> Gadt Bool
AInt :: Int -> Gadt Bool
data C a = C {unwrap :: (a -> Gadt a) -> a}
example :: a -> C a
example v = C $ \f -> | (v :: Int) == True = f (AInt v)
| (v :: String) == True = f (AString v)
cont :: Gadt a -> a
cont (AInt v) = ...
cont (AString v) = ...
Am I overlooking a basic solution here? I'm new to continuations so I may of just overlooked something simple.
First you cannot use :: as a predicate to test the runtime type (as far as I know). Second your a parameter of Gadt is entirely phantom. Is that intended? example can either be polymorphic by treating different types uniformly or you'd need to use class (parametric vs ad-hoc polymorphism). You might have wanted something like
data Gadt where
AInt :: Int -> Gadt
AString :: String -> Gadt
data C a = C { unwrap :: (a -> Gadt) -> Gadt }
class Ex a where
example :: a -> C a
instance Ex Int where
example v = C ...
instance Ex String where
example v = C ...
This is still pseudo-code, as it makes little sense but at least type-checks for me.
I've come across a potential solution, following advice from here:
newtype C r a = C {runC :: (a -> r) -> r}
data Hole = Hole1 Int | Hole2 String | Hole3 Bool
example :: String -> C Bool a
example s = C $ \f -> do
x <- f (Hole1 22)
y <- f (Hole2 "string")
k (Hole3 False)
cont :: Hole -> Bool
cont (Hole1 x) = ...
cont (Hole2 x) = ...
cont (Hole3 x) = ...
This enables specific implementations based on type by wrapping the input type inside the Hole data structure.
I have a datatype F with a special-case for Int:
{-# LANGUAGE GADTs, RankNTypes #-}
data F a where
FGen :: a -> F a
FInt :: F Int
Without exposing the details of this datatype to callers - the real datatype is more complicated containing internal implementation details - I want to provide an API for using it:
transform :: (a -> b) -> b -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i
If I'm going to call transform on a F Int, clearly both of the first two arguments are important:
transformInt :: F Int -> Int
transformInt = transform (+1) 5
But if I'm going to call it on a F Char, the second argument is unnecessary as the value can't be a FInt:
transformChar :: F Char -> Char
transformChar = transform id (error "unreachable code")
Is there a way I can express this in the type of transform?
I tried
transform :: (a -> b) -> (a ~ Int => b) -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i
but then transformChar doesn't compile with
Couldn't match type ‘Char’ with ‘Int’
Inaccessible code in
a type expected by the context: (Char ~ Int) => Char
In the second argument of ‘transform’, namely
‘(error "unreachable code")’
In the expression: transform id (error "unreachable code")
In an equation for ‘transformChar’:
transformChar = transform id (error "unreachable code")
and anyway I'd still want absurd value I could use instead of the error to properly express that the compiler should be able to prove the code will never be used.
We can use the propositional equality type in Data.Type.Equality and we can also express inaccessibility of code from GHC 7.8, using empty case expressions:
{-# LANGUAGE GADTs, RankNTypes, EmptyCase, TypeOperators #-}
import Data.Type.Equality
data F a where
FGen :: a -> F a
FInt :: F Int
transform :: (a -> b) -> ((a :~: Int) -> b) -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i Refl
transformChar :: F Char -> Char
transformChar = transform id (\p -> case p of {})
-- or (\case {}) with LambdaCase
transformInt :: F Int -> Int
transformInt = transform (+1) (const 5)
I like the answer with a GADT for the type equality proof better. This answer explains how to do the same thing with TypeFamilies. With closed type families we can write functions from types to the unit () and zero Void of the type system to represent prepositional truth and false.
{-# LANGUAGE TypeFamilies #-}
import Data.Void
type family IsInt a where
IsInt Int = ()
IsInt a = Void
The second argument to transform is () -> b when IsInt a and Void -> b (the type of absurd) when a isn't an integer.
transform :: (a -> b) -> (IsInt a -> b) -> F a -> b
transform f i (FGen v) = f v
transform f i FInt = i ()
transformChar can be written in terms of absurd and transformInt must pass in b as a constant function.
transformChar :: F Char -> Char
transformChar = transform id absurd
transformInt :: F Int -> Int
transformInt = transform (+1) (const 5)
More Reusable
At András Kovács suggestion, we can make this more reusable with a type family for type equality (==) that returns lifted Bools.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
type family (==) a b :: Bool where
(==) a a = True
(==) a b = False
We could provide another type family to convert True to () and False to Void. For this specific problem it reads better to go all the way from True or False and some type b to () -> b or Void -> b.
type family When p b where
When True b = () -> b
When False b = Void -> b
The type of transform then reads.
transform :: (a -> b) -> When (a == Int) b -> F a -> b
I have a record with fields of different types, and a function that is applicable to all of those types. As a small (silly) example:
data Rec = Rec { flnum :: Float, intnum :: Int } deriving (Show)
Say, I want to define a function that adds two records per-field:
addR :: Rec -> Rec -> Rec
addR a b = Rec { flnum = (flnum a) + (flnum b), intnum = (intnum a) + (intnum b) }
Is there a way to express this without repeating the operation for every field (there may be many fields in the record)?
In reality, I have a record comprised exclusively of Maybe fields, and I want to combine the actual data with a record containing default values for some of the fields, to be used when the actual data was Nothing.
(I guess it should be possible with template haskell, but I am more interested in a "portable" implementation.)
Yet another way is to use GHC.Generics:
{-# LANGUAGE FlexibleInstances, FlexibleContexts,
UndecidableInstances, DeriveGeneric, TypeOperators #-}
import GHC.Generics
class AddR a where
addR :: a -> a -> a
instance (Generic a, GAddR (Rep a)) => AddR a where
addR a b = to (from a `gaddR` from b)
class GAddR f where
gaddR :: f a -> f a -> f a
instance GAddR a => GAddR (M1 i c a) where
M1 a `gaddR` M1 b = M1 (a `gaddR` b)
instance (GAddR a, GAddR b) => GAddR (a :*: b) where
(al :*: bl) `gaddR` (ar :*: br) = gaddR al ar :*: gaddR bl br
instance Num a => GAddR (K1 i a) where
K1 a `gaddR` K1 b = K1 (a + b)
-- Usage
data Rec = Rec { flnum :: Float, intnum :: Int } deriving (Show, Generic)
t1 = Rec 1.0 2 `addR` Rec 3.0 4
You can use gzipWithT for that.
I'm not an expert, so my version it a bit silly. It should be possible to call gzipWithT only once, e.g. using extQ and extT, but I failed to find the way to do that. Anyway, here is my version:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Generics
data Test = Test {
test1 :: Int,
test2 :: Float,
test3 :: Int,
test4 :: String,
test5 :: String
}
deriving (Typeable, Data, Eq, Show)
t1 :: Test
t1 = Test 1 1.1 2 "t1" "t11"
t2 :: Test
t2 = Test 3 2.2 4 "t2" "t22"
merge :: Test -> Test -> Test
merge a b = let b' = gzipWithT mergeFloat a b
b'' = gzipWithT mergeInt a b'
in gzipWithT mergeString a b''
mergeInt :: (Data a, Data b) => a -> b -> b
mergeInt = mkQ (mkT (id :: Int -> Int)) (\a -> mkT (\b -> a + b :: Int))
mergeFloat :: (Data a, Data b) => a -> b -> b
mergeFloat = mkQ (mkT (id :: Float -> Float)) (\a -> mkT (\b -> a + b :: Float))
mergeString :: (Data a, Data b) => a -> b -> b
mergeString = mkQ (mkT (id :: String -> String)) (\a -> mkT (\b -> a ++ b :: String))
main :: IO ()
main = print $ merge t1 t2
Output:
Test {test1 = 4, test2 = 3.3000002, test3 = 6, test4 = "t1t2", test5 = "t11t22"}
The code is obscure, but the idea is simple, gzipWithT applies the specified generic function (mergeInt, mergeString, etc) to pair of corresponding fields.
with vinyl (an "extensible records" package):
import Data.Vinyl
-- `vinyl` exports `Rec`
type Nums = Rec Identity [Float, Int]
which is equivalent to
data Nums' = Nums' (Identity Float) (Identity Int)
which is itself equivalent to
data Nums'' = Nums'' Float Int
then addR is simply
-- vinyl defines `recAdd`
addR :: Nums -> Nums -> Nums
addR = recAdd
and if you add a new field
type Nums = Rec Identity [Float, Int, Word]
you don't need to touch addR.
btw, recAdd is easy to define yourself, if you want to "lift" your own custom numeric operations, it's just
-- the `RecAll f rs Num` constraint means "each field satisfies `Num`"
recAdd :: RecAll f rs Num => Rec f rs -> Rec f rs -> Rec f rs
recAdd RNil RNil = RNil
recAdd (a :& as) (b :& bs) = (a + b) :& recAdd as bs
For convenience, you can define your own constructor:
nums :: Float -> Int -> Num
nums a b = Identity a :& Identity b :& RNil
and even a pattern for both constructing and matching values:
-- with `-XPatternSynonyms`
pattern Nums :: Float -> Int -> Num
pattern Nums a b = Identity a :& Identity b :& RNil
usage:
main = do
let r1 = nums 1 2
let r2 = nums 3 4
print $ r1 `addR` r2
let (Nums a1 _) = r1
print $ a1
let r3 = i 5 :& i 6 :& i 7 :& z -- inferred
print $ r1 `addR` (rcast r3) -- drop the last field
Since r3 is inferred as
(Num a, Num b, Num c) => Rec Identity [a, b, c]
you can (safely) upcast it to
rcast r3 :: (Num a, Num b) => Rec Identity [a, b]
you then specialize it
rcast r3 :: Nums
https://hackage.haskell.org/package/vinyl-0.5.2/docs/Data-Vinyl-Class-Method.html#v:recAdd
https://hackage.haskell.org/package/vinyl-0.5.2/docs/Data-Vinyl-Tutorial-Overview.html
I don't think there's any way to do this, as to get the values from the fields, you need to specify their names, or pattern match on them - and similarly to set the fields, you specify their names, or use the regular constructor syntax to set them - where the syntax order matters.
Perhaps a slight simplification would be to use the regular constructor syntax and add a closure for the operation
addR' :: Rec -> Rec -> Rec
addR' a b = Rec (doAdd flnum) (doAdd intnum)
where doAdd f = (f a) + (f b)
doAdd has the type (Num a) => (Rec -> a) -> a.
Additionally, if you plan on doing more than one operation on the record - for example, a subR, which does almost the same but subtracts - you can abstract away the behavior into a function by using RankNTypes.
{-# LANGUAGE RankNTypes #-}
data Rec = Rec { flnum :: Float, intnum :: Int } deriving (Show)
opRecFields :: (forall a. (Num a) => a -> a -> a) -> Rec -> Rec -> Rec
opRecFields op a b = Rec (performOp flnum) (performOp intnum)
where performOp f = (f a) `op` (f b)
addR = opRecFields (+)
subR = opRecFields (-)
I want to make a special smart constructor for Data.Map with a certain constraint on the types of key/value pair relationships. This is the constraint I tried to express:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, DataKinds #-}
data Field = Speed | Name | ID
data Value = VFloat Float | VString ByteString | VInt Int
class Pair f b | f -> b where
toPair :: f -> b -> (f, b)
toPair = (,)
instance Pair Speed (VFloat f)
instance Pair ID (VInt i)
for each field, there is only one type of value that it should be associated with. In my case, it does not make sense for a Speed field to map to a ByteString. A Speed field should uniquely map to a Float
But I get the following type error:
Kind mis-match
The first argument of `Pair' should have kind `*',
but `VInt' has kind `Value'
In the instance declaration for `Pair Speed (VFloat f)'
using -XKindSignatures:
class Pair (f :: Field) (b :: Value) | f -> b where
toPair :: f -> b -> (f, b)
toPair = (,)
Kind mis-match
Expected kind `OpenKind', but `f' has kind `Field'
In the type `f -> b -> (f, b)'
In the class declaration for `Pair'
I understand why I get the Kind mis-match, but how can I express this constraint so that it is a compile time type-checker error to use toPair on an non-matching Field and Value.
It was suggested to me by #haskell to use a GADT, but I havent been able to figure it out yet.
The goal of this is to be able to write
type Record = Map Field Value
mkRecord :: [Field] -> [Value] -> Record
mkRecord = (fromList .) . zipWith toPair
so that I can make safe Maps where the key/value invariants are respected.
So this should type-check
test1 = mkRecord [Speed, ID] [VFloat 1.0, VInt 2]
but this should be a compile time error
test2 = mkRecord [Speed] [VInt 1]
EDIT:
I'm beginning to think that my specific requirements aren't possible. Using my original example
data Foo = FooInt | FooFloat
data Bar = BarInt Int | BarFloat Float
In order to enforce the constraint on Foo and Bar, there must be some way to differentiate between a FooInt and FooFloat at the type level and similarly for Bar. Thus I instead need two GADTs
data Foo :: * -> * where
FooInt :: Foo Int
FooFloat :: Foo Float
data Bar :: * -> * where
BarInt :: Int -> Bar Int
BarFloat :: Float -> Bar Float
now I can write an instance for Pair that only holds when the Foo and Bar are both tagged with the same type
instance Pair (Foo a) (Bar a)
and I have the properties I want
test1 = toPair FooInt (BarInt 1) -- type-checks
test2 = toPair FooInt (BarFloat 1) -- no instance for Pair (Foo Int) (Bar Float)
but I lose the ability to write xs = [FooInt, FooFloat] because that would require a heterogeneous list. Furthermore if I try to make the Map synonym type FooBar = Map (Foo ?) (Bar ?) I'm stuck with a Map of either only Int types or only Float types, which isnt what I want. It's looking rather hopeless, unless theres some powerful type class wizardry I'm not aware of.
You could use a GADT like so,
data Bar :: * -> * where
BarInt :: Int -> Bar Int
BarFloat :: Float -> Bar Float
now you have 2 distinct types of Bar available (Bar Int) and (Bar Float).You could then just split Foo into 2 types unless there is a reason not to.
data FooInt
data FooFloat
class Pair f b c| f b -> c where
toPair :: f -> b -> c
instance Pair FooInt (Bar Int) (FooInt,Int) where
toPair a (BarInt b)= (a,b)
This is sort of a clumsy example but it shows how you can specialize the type using a GADT. The idea is that they carry a "phantom type" along. It is described pretty well on this page and with DataKinds on this page.
EDIT:
If we make both Foo and Bar GADT's we can use a type or data family as described here. So, this combination allows us to set the type of Map based on the key type. Still feels like there are other possibly simpler ways to accomplish this, but it does showcase 2 great GHC extensions!
data Foo :: * -> * where
FooInt :: Int -> Foo Int
FooFloat :: Float -> Foo Float
data Bar :: * -> * where
BarInt :: Int -> Bar Int
BarFloat :: Float -> Bar Float
class Pair f b c| f b -> c where
toPair :: f -> b -> c
instance Pair (Foo Int) (Bar Int) ((Foo Int),Int) where
toPair a (BarInt b)= (a,b)
type family FooMap k :: *
type instance FooMap (Foo Int) = Map (Foo Int) (Bar Int)
An oldschool version using Dynamic and Typeable and FunDeps. To keep it safe, you just need to not export the abstraction-breaking things like the SM constructor and the SMKey typeclass.
{-# LANGUAGE DeriveDataTypeable, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}
module Main where
import qualified Data.Map as M
import Data.Dynamic
import Data.Typeable
data SpecialMap = SM (M.Map String Dynamic)
emptySM = SM (M.empty)
class (Typeable a, Typeable b) => SMKey a b | a -> b
data Speed = Speed deriving Typeable
data Name = Name deriving Typeable
data ID = ID deriving Typeable
instance SMKey Speed Float
instance SMKey Name String
instance SMKey ID Int
insertSM :: SMKey k v => k -> v -> SpecialMap -> SpecialMap
insertSM k v (SM m) = SM (M.insert (show $ typeOf k) (toDyn v) m)
lookupSM :: SMKey k v => k -> SpecialMap -> Maybe v
lookupSM k (SM m) = fromDynamic =<< M.lookup (show $ typeOf k) m
-- and now lists
newtype SMPair = SMPair {unSMPair :: (String, Dynamic)}
toSMPair :: SMKey k v => k -> v -> SMPair
toSMPair k v = SMPair (show $ typeOf k, toDyn v)
fromPairList :: [SMPair] -> SpecialMap
fromPairList = SM . M.fromList . map unSMPair
{-
*Main> let x = fromPairList [toSMPair Speed 1.2, toSMPair ID 34]
*Main> lookupSM Speed x
Just 1.2
-}
When I first read this I attempted to solve the problem of forcing compile errors in the required cases, but something seemed wrong. I then tried an approach with multiple maps and a lifting function, but something was still nagging me. However, when I realised that essentially what you are trying to do is create some form of extensible record, it reminded me of a very cool package I had become aware of a few months ago: the Vinyl package (available on Hackage). This may or may not be exactly the effects you were after, and it does require GHC 7.6, but here is an example adapted from the readme:
{-# LANGUAGE DataKinds, TypeOperators #-}
{-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}
import Data.Vinyl
speed = Field :: "speed" ::: Float
name = Field :: "name" ::: String
iD = Field :: "id" ::: Int
Now a record can be made containing any number of these fields:
test1 = speed =: 0.2
test2 = speed =: 0.2
<+> name =: "Ted"
<+> iD =: 1
These are of different types, so an attempt to pass the wrong amount of information in a given function will cause a compile error. A type synonym can make this easier to use, but type annotations are not required.
type Entity = Rec ["speed" ::: Float, "name" ::: String, "id" ::: Int]
test2 :: Entity
The library provides automatic lenses on these types without the need for Template Haskell, and a casting function that allows for subtypes to be handled with ease. For example:
test2Casted :: Rec '["speed" ::: Float]
test2Casted = cast test2
(The extra tick is required to get the kind right for the single field record).
This doesn't allow the exact type for mkRecord you were after, but it does seem to capture the requirements of static checking of extensible records. If this doesn't work for you, you might nevertheless be able to use of the clever type techniques found in the Vinyl source to get where you want to go.
I would make an opaque datatype with some getters and setters.
module Rec (Rec, getSpeed, getName, getID, setSpeed, setName, setID, blank) where
data Rec = R { speed :: Maybe Double; name :: Maybe String; id :: Maybe Int }
getSpeed :: Rec -> Maybe Double
getSpeed = speed
setSpeed :: Double -> Rec -> Rec
setSpeed s r = r { speed = s }
blank = R { speed = Nothing, name = Nothing, id = Nothing }