Rigid / skolem type variable: fine as parameter but escaping scope with local where/let statement - haskell

Per What are skolems?, this works:
{-# LANGUAGE ExistentialQuantification #-}
data AnyEq = forall a. Eq a => AE a
reflexive :: AnyEq -> Bool
reflexive (AE x) = x == x
But why doesn't this:
reflexive2 :: AnyEq -> Bool
reflexive2 ae = x == x
where
AE x = ae
(or the similar version with let). It produces the errors including:
Couldn't match expected type ‘p’ with actual type ‘a’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor: AE :: forall a. Eq a => a -> AnyEq,
in a pattern binding
at Skolem.hs:74:4-7
Is it possible to make it work by adding some type declaration (a bit like the s :: forall a. I a -> String solution to the withContext example in that question). I feel I want to add an Eq x somewhere.
My (possibly naïve) understanding of how reflexive works is as follows:
it takes a value of type AnyEq. This has embedded within it a value of any type provided it is an instance of Eq. This inner type is not apparent in the type signature of reflexive and is unknown when reflexive is compiled.
The binding (AE x) = ae makes x a value of that unknown type, but known to be an instance of Eq. (So just like the variables x and y in myEq :: Eq a => a -> a -> Bool; myEq x y = x == y)
the == operator is happy based on the implied class constraint.
I can't think why reflexive2 doesn't do the same, except for things like the "monomorphism restriction" or "mono local binds", which sometimes make things weird. I've tried compiling with all combinations of NoMonomorphismRestriction and NoMonoLocalBinds, but to no avail.
Thanks.

So I think I found the answer in the documentation (of all places!). This states:
You can’t pattern-match on an existentially quantified constructor in a let or where group of bindings
The reason for this restriction is really an implementation one
We’ll see how annoying it is
There's also a request to lift the restriction (though it seems a bit challenging).
Personally, now I think I understand it, it's not that annoying. But I do think the error message generated is misleading (since I don't think the problem is scope leakage), so will request it is changed. (It would also be good if the generated error message had a reference back to the documentation, so will push my luck by asking for that too.)
Thanks all for your comments, and please let me know if you think I've got some of this wrong. David.

Related

Can we tweak "a -> a" function in Haskell?

In Haskell id function is defined on type level as id :: a -> a and implemented as just returning its argument without any modification, but if we have some type introspection with TypeApplications we can try to modify values without breaking type signature:
{-# LANGUAGE AllowAmbiguousTypes, ScopedTypeVariables, TypeApplications #-}
module Main where
class TypeOf a where
typeOf :: String
instance TypeOf Bool where
typeOf = "Bool"
instance TypeOf Char where
typeOf = "Char"
instance TypeOf Int where
typeOf = "Int"
tweakId :: forall a. TypeOf a => a -> a
tweakId x
| typeOf #a == "Bool" = not x
| typeOf #a == "Int" = x+1
| typeOf #a == "Char" = x
| otherwise = x
This fail with error:
"Couldn't match expected type ‘a’ with actual type ‘Bool’"
But I don't see any problems here (type signature satisfied):
My question is:
How can we do such a thing in a Haskell?
If we can't, that is theoretical\philosophical etc reasons for this?
If this implementation of tweak_id is not "original id", what are theoretical roots that id function must not to do any modifications on term level. Or can we have many implementations of id :: a -> a function (I see that in practice we can, I can implement such a function in Python for example, but what the theory behind Haskell says to this?)
You need GADTs for that.
{-# LANGUAGE ScopedTypeVariables, TypeApplications, GADTs #-}
import Data.Typeable
import Data.Type.Equality
tweakId :: forall a. Typeable a => a -> a
tweakId x
| Just Refl <- eqT #a #Int = x + 1
-- etc. etc.
| otherwise = x
Here we use eqT #type1 #type2 to check whether the two types are equal. If they are, the result is Just Refl and pattern matching on that Refl is enough to convince the type checker that the two types are indeed equal, so we can use x + 1 since x is now no longer only of type a but also of type Int.
This check requires runtime type information, which we usually do not have due to Haskell's type erasure property. The information is provided by the Typeable type class.
This can also be achieved using a user-defined class like your TypeOf if we make it provide a custom GADT value. This can work well if we want to encode some constraint like "type a is either an Int, a Bool, or a String" where we statically know what types to allow (we can even recursively define a set of allowed types in this way). However, to allow any type, including ones that have not yet been defined, we need something like Typeable. That is also very convenient since any user-defined type is automatically made an instance of Typeable.
This fail with error: "Couldn't match expected type ‘a’ with actual type ‘Bool’"But I don't see any problems here
Well, what if I add this instance:
instance TypeOf Float where
typeOf = "Bool"
Do you see the problem now? Nothing prevents somebody from adding such an instance, no matter how silly it is. And so the compiler can't possibly make the assumption that having checked typeOf #a == "Bool" is sufficient to actually use x as being of type Bool.
You can squelch the error if you are confident that nobody will add malicious instances, by using unsafe coercions.
import Unsafe.Coerce
tweakId :: forall a. TypeOf a => a -> a
tweakId x
| typeOf #a == "Bool" = unsafeCoerce (not $ unsafeCoerce x)
| typeOf #a == "Int" = unsafeCoerce (unsafeCoerce x+1 :: Int)
| typeOf #a == "Char" = unsafeCoerce (unsafeCoerce x :: Char)
| otherwise = x
but I would not recommend this. The correct way is to not use strings as a poor man's type representation, but instead the standard Typeable class which is actually tamper-proof and comes with suitable GADTs so you don't need manual unsafe coercions. See chi's answer.
As an alternative, you could also use type-level strings and a functional dependency to make the unsafe coercions safe:
{-# LANGUAGE DataKinds, FunctionalDependencies
, ScopedTypeVariables, UnicodeSyntax, TypeApplications #-}
import GHC.TypeLits (KnownSymbol, symbolVal)
import Data.Proxy (Proxy(..))
import Unsafe.Coerce
class KnownSymbol t => TypeOf a t | a->t, t->a
instance TypeOf Bool "Bool"
instance TypeOf Int "Int"
tweakId :: ∀ a t . TypeOf a t => a -> a
tweakId x = case symbolVal #t Proxy of
"Bool" -> unsafeCoerce (not $ unsafeCoerce x)
"Int" -> unsafeCoerce (unsafeCoerce x + 1 :: Int)
_ -> x
The trick is that the fundep t->a makes writing another instance like
instance TypeOf Float "Bool"
a compile error right there.
Of course, really the most sensible approach is probably to not bother with any kind of manual type equality at all, but simply use the class right away for the behaviour changes you need:
class Tweakable a where
tweak :: a -> a
instance Tweakable Bool where
tweak = not
instance Tweakable Int where
tweak = (+1)
instance Tweakable Char where
tweak = id
The other answers are both very good for covering the ways you can do something like this in Haskell. But I thought it was worth adding something speaking more to this part of the question:
If we can't, that is theoretical\philosophical etc reasons for this?
Actually Haskellers do generally rely quite strongly on the theory that forbids something like your tweakId from existing with type forall a. a -> a. (Even though there are ways to cheat, using things like unsafeCoerce; this is usually considered bad style if you haven't done something like in leftaroundabout's answer, where a class with functional dependencies ensures the unsafe coerce is always valid)
Haskell uses parametric polymorphism1. That means we can write code that works on multiple types because it will treat them all the same; the code only uses operations that will work regardless of the specific type it is invoked on. This is expressed in Haskell types by using type variables; a function with a variable in its type can be used with any type at all substituted for the variable, because every single operation in the function definition will work regardless of what type is chosen.
About the simplest example is indeed the function id, which might be defined like this:
id :: forall a. a -> a
id x = x
Because it's parametrically polymorphic, we can simply choose any type at all we like and use id as if it was defined on that type. For example as if it were any of the following:
id :: Bool -> Bool
id x = x
id :: Int -> Int
id x = x
id :: Maybe (Int -> [IO Bool]) -> Maybe (Int -> [IO Bool])
id x = x
But to ensure that the definition does work for any type, the compiler has to check a very strong restriction. Our id function can only use operations that don't depend on any property of any specific type at all. We can't call not x because the x might not be a Bool, we can't call x + 1 because the x might not be a number, can't check whether x is equal to anything because it might not be a type that supports equality, etc, etc. In fact there is almost nothing you can do with x in the body of id. We can't even ignore x and return some other value of type a; this would require us to write an expression for a value that can be of any type at all and the only things that can do that are things like undefined that don't evaluate to a value at all (because they throw exceptions). It's often said that in fact there is only one valid function with type forall a. a -> a (and that is id)2.
This restriction on what you can do with values whose type contains variables isn't just a restriction for the sake of being picky, it's actually a huge part of what makes Haskell types useful. It means that just looking at the type of a function can often tell you quite a bit about what it can possibly do, and once you get used to it Haskellers rely on this kind of thinking all the time. For example, consider this function signature:
map :: forall a b. (a -> b) -> [a] -> [b]
Just from this type (and the assumption that the code doesn't do anything dumb like add in extra undefined elements of the list) I can tell:
All of the items in the resulting list come are results of the function input; map will have no other way of producing values of type b to put in the list (except undefined, etc).
All of the items in the resulting list correspond to something in the input list mapped through the function; map will have no way of getting any a values to feed to the function (except undefined, etc)
If any items of the input list are dropped or re-ordered, it will be done in a "blind" way that isn't considering the elements at all, only their position in the list; map ultimately has no way of testing any property of the a and b values to decide which order they should go in. For example it might leave out the third element, or swap the 2nd and 76th elements if there are at least 100 elements, etc. But if it applies rules like that it will have to always apply them, regardless of the actual items in the list. It cannot e.g. drop the 4th element if it is less than the 5th element, or only keep outputs from the function that are "truthy", etc.
None of this would be true if Haskell allowed parametrically polymorphic types to have Python-like definitions that check the type of their arguments and then run different code. Such a definition for map could check if the function is supposed to return integers and if so return [1, 2, 3, 4] regardless of the input list, etc. So the type checker would be enforcing a lot less (and thus catching fewer mistakes) if it worked this way.
This kind of reasoning is formalised in the concept of free theorems; it's literally possible to derive formal proofs about a piece of code from its type (and thus get theorems for free). You can google this if you're interested in further reading, but Haskellers generally use this concept informally rather doing real proofs.
Sometimes we do need non-parametric polymorphism. The main tool Haskell provides for that is type classes. If a type variable has a class constraint, then there will be an interface of class methods provided by that constraint. For example the Eq a constraint allows (==) :: a -> a -> Bool to be used, and your own TypeOf a constraint allows typeOf #a to be used. Type class methods do allow you to run different code for different types, so this breaks parametricity. Even just adding Eq a to the type of map means I can no longer assume property 3 from above.
map :: forall a b. Eq a => (a -> b) -> [a] -> [b]
Now map can tell whether some of the items in the original list are equal to each other, so it can use that to decide whether to include them in the result, and in what order. Likewise Monoid a or Monoid b would allow map to break the first two properties by using mempty :: a to produce new values that weren't in the list originally or didn't come from the function. If I add Typeable constraints I can't assume anything, because the function could do all of the Python-style checking of types to apply special-case logic, make use of existing values it knows about if a or b happen to be those types, etc.
So something like your tweakId cannot be given the type forall a. a -> a, for theoretical reasons that are also extremely practically important. But if you need a function that behaves like your tweakId adding a class constraint was the right thing to do to break out of the constraints of parametricity. However simply being able to get a String for each type isn't enough; typeOf #a == "Int" doesn't tell the type checker that a can be used in operations requiring an Int. It knows that in that branch the equality check returned True, but that's just a Bool; the type checker isn't able to reason backwards to why this particular Bool is True and deduce that it could only have happened if a were the type Int. But there are alternative constructs using GADTs that do give the type checker additional knowledge within certain code branches, allowing you to check types at runtime and use different code for each type. The class Typeable is specifically designed for this, but it's a hammer that completely bypasses parametricity; I think most Haskellers would prefer to keep more type-based reasoning intact where possible.
1 Parametric polymorphism is in contrast to class-based polymorphism you may have seen in OO languages (where each class says how a method is implemented for objects of that specific class), or ad-hoc polymophism (as seen in C++) where you simply define multiple definitions with the same name but different types and the types at each application determine which definition is used. I'm not covering those in detail, but the key distinction is both of them allow the definition to have different code for each supported type, rather than guaranteeing the same code will process all supported types.
2 It's not 100% true that there's only one valid function with type forall a. a -> a unless you hide some caveats in "valid". But if you don't use any unsafe features (like unsafeCoerce or the foreign language interface), then a function with type forall a. a -> a will either always throw an exception or it will return its argument unchanged.
The "always throws an exception" isn't terribly useful so we usually assume an unknown function with that type isn't going to do that, and thus ignore this possibility.
There are multiple ways to implement "returns its argument unchanged", like id x = head . head . head $ [[[x]]], but they can only differ from the normal id in being slower by building up some structure around x and then immediately tearing it down again. A caller that's only worrying about correctness (rather than performance) can treat them all the same.
Thus, ignoring the "always undefined" possibility and treating all of the dumb elaborations of id x = x the same, we come to the perspective where we can say "there's only one function with forall a. a -> a".

Significance of scoped type variables standing for type variables and not types

In the GHC documentation for the ScopedTypeVariables extension, the overview states the following as a design principle:
A scoped type variable stands for a type variable, and not for a type. (This is a change from GHC’s earlier design.)
I know the general purpose of the scoped type variables extension, but I don't know the implications of the distinction made here between standing for type variables and standing for types. What is the significance of the difference, from the perspective of users of the language?
The comment above alludes to two designs which approached this decision differently and made different tradeoffs. What was the alternative design, and how does it compare to the one currently implemented?
tl;dr: The documentation says what it says because the old implementation of scoped typed variables in GHC was different, and the new documentation (over)emphasizes the contrast between the old behavior and the new behavior. In fact, the scoped typed variables you use with the ScopedTypeVariables extension in place are just plain old (rigid) type variables, and these are the same type variables you've been using in regular Haskell type signatures without scoping (even if you didn't realize they were "rigid"). It's true that scoped type variables don't simply "stand for types", but regular unscoped type variables don't simply "stand for types", either.
Longer answer:
First, setting aside the issue of scoped type variables, consider the following:
pluralize :: [a] -> [a]
pluralize x = x ++ "s"
If a, as a type variable, simply "stood for a type", this would be fine. GHC would determine that a stood for the type Char, and the resulting signature [Char] -> [Char] would be determined to be the correct type of pluralize, so there'd be no problem. In fact, if we were inferring the type of:
pluralize x = x ++ "s"
in a plain old Hindley-Milner (HM) type system, this is probably exactly what would happen. As an intermediate step while typing the (++) application, the type checker would assign x the type [a] for a "fresh" HM type variable a, and it would assign pluralize the type [a] -> [a] before unifying [a] with the type of "s" :: [Char] to unify a and Char.
Instead, this is rejected by the GHC type checker because a in this type signature is not an HM-style type variable and so does not simply stand for a type. Instead, it is a rigid (i.e., user-specified) Haskell type variable, and the type checker doesn't permit such a variable to unify with anything other than itself while defining pluralize.
Similarly, the following is rejected:
pairlist :: a -> b -> [a]
pairlist x y = [x,y]
even though, if a and b just stood for types, this would be fine (as it works for any a and b of kind * provided only that a and b are the same type). Instead, it is rejected by the type checker because two rigid Haskell type variables a and b can't unify.
Now, you might try to make the case that the issue is not that type variables are "rigid" and can't unify with concrete types (like Char) or with each other, but rather that there is an implicit quantification in Haskell type signatures, so that the signature for pluralize is actually:
pluralize :: forall a . [a] -> [a]
and so when a is determined to "stand for" Char, it is the contradiction with this forall a quantification that triggers the error. The problem with this argument is that both explanations are actually more or less equivalent. It is because Haskell type variables are rigid (i.e., because type signatures in Haskell are implicitly universally quantified) that the types cannot unify (i.e., that the unification contradicts the quantification). However, it turns out that the "rigid type variables" explanation is closer to what's actually happening in the GHC type checker than the "implicit quantification" explanation. That's why the error messages generated by the above definitions refer to inability to match rigid type variables rather than to contradictions with universal type variable quantifications.
Now, let's turn back to the question of scoped type variables. In the olden days, GHC's -fscoped-type-variables extension was implemented quite differently. In particular, for pattern type signatures, you were permitted to write things like the following (taken from the documentation for GHC 6.0):
f :: [Int] -> Int -> Int
f (xs::[a]) (y::a) = (head xs + y) :: a
and the documentation went on to say:
The pattern type signatures on the left hand side of f express the fact that xs must be a list of things of some type a; and that y must have this same type. The type signature on the expression (head xs) [sic] specifies that this expression must have the same type a. There is no requirement that the type named by "a" is in fact a type variable. Indeed, in this case, the type named by "a" is Int. (This is a slight liberalisation from the original rather complex rules, which specified that a pattern-bound type variable should be universally quantified.)
It went on to give some additional examples of use of scoped type variables, such as:
g (x::a) (y::b) = [x,y] -- a unifies with b
k (x::a) True = ... -- a unifies with Int
k (x::Int) False = ...
In 2006, Simon Peyton-Jones made a big commit (ac10f840) to add impredicativity to the type system which also ended up substantially changing the implementation of lexically scoped type variables. The commit text contains a detailed explanation of the change including the requirements for the new design.
A key design choice was that lexically scoped type variables now named rigid (i.e., user-specified polymorphic) Haskell type variables, rather than being more like the HM-style variables that simply stood for a type and were subject to unification.
That made the above examples (f, g, and k) illegal, because scoped type variables in pattern matches now behaved more like regular rigid type variables.
Soooo... the old design was probably a weird hack that made scoped type variables more like HM type variables and so quite different from "normal" Haskell type variables, and the new system brought them more into line with how unscoped type variables behaved.
However, complicating things further, #duplode's link in the comments references a proposal to partially "undo" this "restriction" in the context of signatures in pattern matches. I think it would be fair to say that the old design, which treated scoped type variables more like a special case, was inferior to the new design which better unified the treatment of scoped and unscoped type variables, and there is no desire to go back to the old implementation. However, the new, simpler implementation had the side effect of being unnecessarily restrictive for pattern signatures which perhaps ought to be treated as a special case where non-rigid type variables are permitted.
I'm adding this answer (to my own question) in order to expand on duplode's reference in the comments. ScopedTypeVariables is currently being changed to allow scoped type variables to stand for types instead of only type variables. The discussion for this change the motivation for the new and old designs. This does not, however, address the even earlier design mentioned in the question and in K. A. Buhr's answer.
In the current state, before the forthcoming change, the definition
prefix :: a -> [[a]] -> [[a]]
prefix (x :: b) yss = map xcons yss
where xcons ys = x : ys
is valid (with ScopedTypeVariables), in which b is a newly introduced type variable that stands for the same thing as a. On the other hand, if prefix is specialized to
prefix :: Int -> [[Int]] -> [[Int]]
prefix (x :: b) yss = map xcons yss
where xcons ys = x : ys
then the program is rejected: b is forbidden from standing for Int since Int is not a type variable. Simon Peyton Jones remarked on why it was designed so that b could not stand for Int:
At the time I was worried that it'd be confusing to have a type
variable that was just an alias for Int; that is not a type variable
at all. But in these days of GADTs and type equalities we are all used
to that. We'd make a different choice today.
In the current consensus of the GHC maintainers, the limitation against b standing for Int is viewed as unnatural, especially in light of the possibility of type equalities (a ~ Int) => .... The presence of such constraints blur the lines of what being "bound to a type variable" really means. Should the examples
f1 :: (a ~ Int) => Maybe a -> Int
f1 (Just (x :: b)) = ...
f2 :: (a ~ Int) => Maybe Int -> Int
f2 (Just (x :: a)) = ...
be permitted? Under the new proposal, all four examples above are allowed.
In my own view, the tension ultimately comes from the coexistence of two very different type annotation systems. One of them has the effect of preventing you from giving different names to the same type (for instance, you cannot write (\x -> x) :: a -> b or (\x -> x) :: Int -> b and expect b to be unified with a or Int). The other enables and encourages you to give new names to things (pattern type signatures like foo (x :: b) = ...), a feature which exists to enable you to name types that would otherwise be un-nameable. The leftover question is whether pattern type signatures should allow you to alias types that are already nameable. The answer at its core depends on which of the two precedents you find more compelling.
References:
Joachim Breitner "nomeata" (April-August 2018). Feature request ticket "ScopedTypeVariables could allow more programs", https://ghc.haskell.org/trac/ghc/ticket/15050
nomeata (April-August 2018). Pull request "Allow ScopedTypeVariables to refer to types", https://github.com/ghc-proposals/ghc-proposals/pull/128
Richard A. Eisenberg, Joachim Breitner, and Simon Peyton Jones (June 2018). "Type variables in patterns", https://www.microsoft.com/en-us/research/uploads/prod/2018/06/tyvars-in-pats-haskell18-preprint.pdf, especially sections 3.5 and 4.3
nomeata (August 2018). GHC proposal "Allow ScopedTypeVariables to refer to types", https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0029-scoped-type-variables-types.rst

Haskell type inference for lambda functions (in map) [duplicate]

This question already has an answer here:
What is the monomorphism restriction?
(1 answer)
Closed 6 years ago.
Example 1
Following definition without the type declaration will throw an error:
f :: Eq t => (t,t) -> Bool -- omiting this line will result in an error
f = \(x,y) -> x==y
(I know this function can be written shorter, but this is not the point here.)
Example 2
On the other hand using the same lambda function in a function using map does work without producing an error:
g l = map (\(x,y) -> x==y) l
(Just as an illustration: g [(3,4),(5,5),(7,6)] will produce [False,True,False]
Example 3
Also following code is perfectly fine and it seems to do exactly the same as the original f from above. Here the type inference seems to work.
f' (x,y) = x==y
Question
So my question is: Why do we need a type declaration in the first case, but not in the second and in the third?
If you use:
{-# LANGUAGE NoMonomorphismRestriction #-}
f = \(x,y) -> x==y
you won't get the error.
Update
The Haskell Wiki page on Monomorphism Restriction (link) offers some details on why these definitions are treated differently:
f1 x = show x
f2 = \x -> show x
The difference between the first and second version is that the first version binds x via a "function binding" (see section 4.4.3 of the Haskell 2010 Report), and is therefore unrestricted, but the second version does not. The reason why one is allowed and the other is not is that it's considered clear that sharing f1 will not share any computation, and less clear that sharing f2 will have the same effect. If this seems arbitrary, that's because it is. It is difficult to design an objective rule which disallows subjective unexpected behaviour. Some people are going to fall foul of the rule even though they're doing quite reasonable things.
As #ErikR notes in the comments, this is due to the Monomorphism restriction. We also see this in the error message:
No instance for (Eq a0) arising from a use of '=='
The type variable 'a0' is ambiguous
Possible cause: the monomorphism restriction applied to the following:
f :: (a0, a0) -> Bool
(bound at ...
Note: there are several potential instances:
instance Eq a => Eq (GHC.Real.Ratio a) -- Defined in 'GHC.Real'
instance Eq () -- Defined in 'GHC.Classes'
instane (Eq a, Eq b) => Eq (a,b) -- Defined in 'GHC.Classes'
..plus 22 others
The monomorphism restriction implies that the compiler tries to instantiate an ambiguous type into a non-ambiguous type. (Source: What is the monomorphism restriction?).
So, Haskell wants to put a single instance, but it can't - it finds several, and doesn't know which to choose.
This explains why adding the type solves the problem: now the compiler knows what to choose.
The "monomorphism restriction" is a counter-intuitive rule in Haskell type inference. If you forget to provide a type signature, sometimes this rule will fill the free type variables with specific types using "type defaulting" rules.

Heterogeneous Data.Map in Haskell

Is it possible to do heterogeneous Data.Map in Haskell with GADT instead of Dynamic? I tried to model heterogeneous collection as laid out in this answer:
{-# LANGUAGE GADTs #-}
class Contract a where
toString :: a -> String
data Encapsulated where
Encapsulate :: Contract a => a -> Encapsulated
getTypedObject :: Encapsulated -> a
getTypedObject (Encapsulate x) = x
The idea being that Encapsulated could be used to store different objects of TypeClass a, and then extracted at run-time for specific type.
I get error about type of x not matching Contract a. Perhaps I need to specify some kind of class constraints to tell GHC that type of x in Encapsulate x is same as a in Contract a?
T.hs:10:34:
Couldn't match expected type ‘a’ with actual type ‘a1’
‘a1’ is a rigid type variable bound by
a pattern with constructor
Encapsulate :: forall a. Contract a => a -> Encapsulated,
in an equation for ‘getTypedObject’
at T.hs:10:17
‘a’ is a rigid type variable bound by
the type signature for getTypedObject :: Encapsulated -> a
at T.hs:9:19
Relevant bindings include
x :: a1 (bound at T.hs:10:29)
getTypedObject :: Encapsulated -> a (bound at T.hs:10:1)
In the expression: x
In an equation for ‘getTypedObject’:
getTypedObject (Encapsulate x) = x
I am trying this approach because I have JSON objects of different types, and depending on the type that is decoded at run-time over the wire, we want to retrieve appropriate type-specific builder from Map (loaded at run-time IO in main from configuration files, and passed to the function) and pass it decoded JSON data of the same type.
Dynamic library would work here. However, I am interested in finding out if there are other possible approaches such as GADTs or datafamilies.
your problem is that you push the a out again (which will not work) - what you can do is using the contract internally like this:
useEncapsulateContract :: Encapsulated -> String
useEncapsulateContract (Encapsulate x) = toString x
basically the compiler is telling you everything you need to know: inside you have a forall a. Contract a (so basically a constraint a to be a Contract)
On getTypedObject :: Encapsulated -> a you don't have this constraint - you are telling the compiler: "look this works for every a I'll demand"
To get it there you would have to parametrize Encapsulated to Encapsulated a which you obviously don't want.
The second version (the internal I gave) works because you have the constraint on the data-constructor and so you can use it there
to extent this a little:
this
getTypedObject :: Contract a => Encapsulated -> a
getTypedObject (Encapsulate x) = x
wouldn't work either as now the you would have Contract a but still it could be two different types which just share this class.
And to give hints to the compiler that both should be the same you would have to parametrize Encapsulate again ....
right now by doing this:
Encapsulate :: Contract a => a -> Encapsulated
you erase that information
#Carsten answer is obviously right, but my two cents that helped me understand that before.
When you write:
getTypedObject :: Encapsulated -> a
What you are "saying" is:
getTypedObject is a function that can take a value of the Encapsulated type and its result can be used whenever any type whatsoever is needed.
You can't obviously satisfy that, and the compiler won't allow you to try. You can only use the knowledge about the value inside of Encapsulated to bring out something meaningful based on the Contract. In other words, if the Contract wasn't there, there'd be no way for you to do anything meaningful with that value.
The concept here can be succintly described as type erasure and is also present in other languages, C++ being one I know of. Hence the value is in erasing every information about the type except the things you want to preserve via the contract they satisfy. The downside is that getting the original types back requires runtime inspection.
As a bonus, here's how a dynamic approach might work:
{-# LANGUAGE GADTs #-}
import Unsafe.Coerce
data Encapsulated where
Encapsulate :: Show a => a -> Encapsulated
getTypedObject :: Encapsulated -> a
getTypedObject (Encapsulate x) = unsafeCoerce x
printString :: String -> IO ()
printString = print
x = Encapsulate "xyz"
y = getTypedObject x
main = printString y
But it's very easy to see how that could break, right? :)

How are variable names chosen in type signatures inferred by GHC?

When I play with checking types of functions in Haskell with :t, for example like those in my previous question, I tend to get results such as:
Eq a => a -> [a] -> Bool
(Ord a, Num a, Ord a1, Num a1) => a -> a1 -> a
(Num t2, Num t1, Num t, Enum t2, Enum t1, Enum t) => [(t, t1, t2)]
It seems that this is not such a trivial question - how does the Haskell interpreter pick literals to symbolize typeclasses? When would it choose a rather than t? When would it choose a1 rather than b? Is it important from the programmer's point of view?
The names of the type variables aren't significant. The type:
Eq element => element -> [element] -> Bool
Is exactly the same as:
Eq a => a -> [a] -> Bool
Some names are simply easier to read/remember.
Now, how can an inferencer choose the best names for types?
Disclaimer: I'm absolutely not a GHC developer. However I'm working on a type-inferencer for Haskell in my bachelor thesis.
During inferencing the names chosen for the variables aren't probably that readable. In fact they are almost surely something along the lines of _N with N a number or aN with N a number.
This is due to the fact that you often have to "refresh" type variables in order to complete inferencing, so you need a fast way to create new names. And using numbered variables is pretty straightforward for this purpose.
The names displayed when inference is completed can be "pretty printed". The inferencer can rename the variables to use a, b, c and so on instead of _1, _2 etc.
The trick is that most operations have explicit type signatures. Some definitions require to quantify some type variables (class, data and instance for example).
All these names that the user explicitly provides can be used to display the type in a better way.
When inferencing you can somehow keep track of where the fresh type variables came from, in order to be able to rename them with something more sensible when displaying them to the user.
An other option is to refresh variables by adding a number to them. For example a fresh type of return could be Monad m0 => a0 -> m0 a0 (Here we know to use m and a simply because the class definition for Monad uses those names). When inferencing is finished you can get rid of the numbers and obtain the pretty names.
In general the inferencer will try to use names that were explicitly provided through signatures. If such a name was already used it might decide to add a number instead of using a different name (e.g. use b1 instead of c if b was already bound).
There are probably some other ad hoc rules. For example the fact that tuple elements have like t, t1, t2, t3 etc. is probably something done with a custom rule. In fact t doesn't appear in the signature for (,,) for example.
How does GHCi pick names for type variables? explains how many of these variable names come about. As Ganesh Sittampalam pointed out in a comment, something strange seems to be happening with arithmetic sequences. Both the Haskell 98 report and the Haskell 2010 report indicate that
[e1..] = enumFrom e1
GHCi, however, gives the following:
Prelude> :t [undefined..]
[undefined..] :: Enum t => [t]
Prelude> :t enumFrom undefined
enumFrom undefined :: Enum a => [a]
This makes it clear that the weird behavior has nothing to do with the Enum class itself, but rather comes in from some stage in translating the syntactic sequence to the enumFrom form. I wondered if maybe GHC wasn't really using that translation, but it really is:
{-# LANGUAGE NoMonomorphismRestriction #-}
module X (aoeu,htns) where
aoeu = [undefined..]
htns = enumFrom undefined
compiled using ghc -ddump-simpl enumlit.hs gives
X.htns :: forall a_aiD. GHC.Enum.Enum a_aiD => [a_aiD]
[GblId, Arity=1]
X.htns =
\ (# a_aiG) ($dEnum_aiH :: GHC.Enum.Enum a_aiG) ->
GHC.Enum.enumFrom # a_aiG $dEnum_aiH (GHC.Err.undefined # a_aiG)
X.aoeu :: forall t_aiS. GHC.Enum.Enum t_aiS => [t_aiS]
[GblId, Arity=1]
X.aoeu =
\ (# t_aiV) ($dEnum_aiW :: GHC.Enum.Enum t_aiV) ->
GHC.Enum.enumFrom # t_aiV $dEnum_aiW (GHC.Err.undefined # t_aiV)
so the only difference between these two representations is the assigned type variable name. I don't know enough about how GHC works to know where that t comes from, but at least I've narrowed it down!
Ørjan Johansen has noted in a comment that something similar seems to happen with function definitions and lambda abstractions.
Prelude> :t \x -> x
\x -> x :: t -> t
but
Prelude> :t map (\x->x) $ undefined
map (\x->x) $ undefined :: [b]
In the latter case, the type b comes from an explicit type signature given to map.
Are you familiar with the concepts of alpha equivalence and alpha substitution? This captures the notion that, for example, both of the following are completely equivalent and interconvertible (in certain circumstances) even though they differ:
\x -> (x, x)
\y -> (y, y)
The same concept can be extended to the level of types and type variables (see "System F" for further reading). Haskell in fact has a notion of "lambdas at the type level" for binding type variables, but it's hard to see because they're implicit by default. However, you can make them explicit by using the ExplicitForAll extension, and play around with explicitly binding your type variables:
ghci> :set -XExplicitForAll
ghci> let f x = x; f :: forall a. a -> a
In the second line, I use the forall keyword to introduce a new type variable, which is then used in a type.
In other words, it doesn't matter whether you choose a or t in your example, as long as the type expressions satisfy alpha-equivalence. Choosing type variable names so as to maximize human convenience is an entirely different topic, and probably far more complicated!

Resources