Indirectly reference specific AND unspecific objects in Haskell without monads - haskell

I want to store a bunch of elements of different "sorts" in a container datastructure (list, set,..) and indirectly reference them from somewhere else. Normally, you would probably use a sum type for the elements and probably a list as container or similar:
data Element = Sort1 | Sort2 String | ...
type ElementList = List Element
Now I want to use (and save) some sort of references to the elements of the list (e.g. using an index to its position in the list - let's imagine for now that the list does not change and that this is thus a good idea). I want to to be able to reference elements where I don't care about the "sort" AND here's the catch: I also want to be able to reference elements and tell in the type that it's from some specific sort. This rules out the simple sum type solution above (because the sort is not in the type!). I tried a solution with GADTs:
{-#LANGUAGE GADTs, EmptyDataDecls, RankNTypes, ScopedTypeVariables #-}
data Sort1
data Sort2
data Element t where
Sort1Element :: Element Sort1
Sort2Element :: String -> Element Sort2
newtype ElementRef a = ElementRef Int
type UnspecificElementRefs = [forall t. ElementRef (Element t)]
type OneSpecificSort1ElementRef = ElementRef (Element Sort1)
main = do
let unspecificElementRefs :: UnspecificElementRefs = [ElementRef 1, ElementRef 2]
let oneSpecificElementRef :: OneSpecificSort1ElementRef = ElementRef 1
putStrLn "hello"
But this gives me the error:
- Illegal polymorphic type: forall t. ElementRef (Element t) - GHC doesn't yet support impredicative polymorphism
- In the type synonym declaration for ‘UnspecificElementRefs’
|
11 | type UnspecificElementRefs = [forall t. ElementRef (Element t)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How can I solve this? I'm not looking for a solution to this specific error (I guess this is a dead end?) or specifically with GADTs or even using an int index for referencing or so, I simply want a solution which:
solves the basic problem of indirectly referencing something unspecific and also something specific
does not use STRef or similar so that my whole program needs to be a monad (since this is a quite central datastructure)

“Impredicative polymorphism” means you have a ∀ that is wrapped in a type constructor other than ->. In this case, in []. As the error message tell you, GHC Haskell does not support this (it's not that it isn't in principle sensible, but as far as I understand it makes type checking quite a nightmare).
This can be solved though by wrapping the ∀ in something that forms a “type checker barrier”: in a newtype.
newtype UnspecificElementRef = UnspecificElementRef (∀ t. ElementRef (Element t))
type UnspecificElementRefs = [UnspecificElementRef]
In fact, this can be simplified seeing as ElementRef is itself just a newtype wrapper with a phantom type argument:
newtype UnspecificElementRef = UnspecificElementRef Int

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".

Overload built in function in Haskell

In Haskell, how can one overload a built in function such as !!?
I originally was trying to figure out how to overload the built in function !! to support by own data types. Specifically, !! is of the type:
[a] -> Int -> a
and I want to preserve it's existing functionality, but also be able to call it where its type signature looks more like
MyType1 -> MyType2 -> MyType3
I originally wanted to do this because MyType1 is like a list, and I wanted to use the !! operator because my operation is very similar to selecting an item from a list.
If I was overloading something like + I could just add an instance of my function to the applicable type class, but I don't think that is an option here.
I'm not convinced I actually even want to overload this function anymore, but I am still interested in how it would be done. Actually, comments on if overloading an operator such as !! is even a good idea would be appreciated as well.
In Haskell, nearly all operators are library-defined. Many of the ones you use the most are defined in the 'standard library' of the Prelude module that is imported by default. Gabriel's answer shows how to avoid importing some of those definitions so you can make your own.
That's not overloading though, because the operator still just means one thing; the new meaning you define for it. The primary method that Haskell provides for overloading, i.e. using an operator in such a way that it has different implementations for different types, is the type class mechanism.
A type class identifies a group of types that support some common functions. When you use those functions with a type, Haskell figures out the correct instance of the type class that applies to your usage and makes sure the correct implementation of the functions is used. Most type classes have just a few functions, some just one or two, that need to be implemented to make a new instance. Many of them offer a lot of secondary functions implemented in terms of the core ones as well, and you can use all of them with a type you make an instance of the class.
It so happens that others have made types that behave quite a bit like lists, and so there's already a type class called ListLike. I'm not sure exactly how close your type is to a list, so it may not be a perfect fit for ListLike, but you should look at it as it will give you a lot of capability if you can make your type a ListLike instance.
You can't actually overload an existing non-typeclass function in Haskell.
What you can do is define a new function in a new type class, which is general enough to encompass both the original function and the new definition you want as an overload. You can give it the same name as the standard function, and avoid importing the standard one. That means in your module you can use the name !! to get both the functionality of your new definition, and the original definition (the resolution will be directed by the types).
Example:
{-# LANGUAGE TypeFamilies #-}
import Prelude hiding ((!!))
import qualified Prelude
class Indexable a where
type Index a
type Elem a
(!!) :: a -> Index a -> Elem a
instance Indexable [a] where
type Index [a] = Int
type Elem [a] = a
(!!) = (Prelude.!!)
newtype MyType1 = MyType1 String
deriving Show
newtype MyType2 = MyType2 Int
deriving Show
newtype MyType3 = MyType3 Char
deriving Show
instance Indexable MyType1 where
type Index MyType1 = MyType2
type Elem MyType1 = MyType3
MyType1 cs !! MyType2 i = MyType3 $ cs !! i
(I've used type families to imply that for a given type that can be indexed, the type of the indices and the type of the elements automatically follows; this could of course be done differently, but going into that in more detail is getting side-tracked from the overload question)
Then:
*Main> :t (!!)
(!!) :: Indexable a => a -> Index a -> Elem a
*Main> :t ([] !!)
([] !!) :: Int -> a
*Main> :t (MyType1 "" !!)
(MyType1 "" !!) :: MyType2 -> MyType3
*Main> [0, 1, 2, 3, 4] !! 2
2
*Main> MyType1 "abcdefg" !! MyType2 3
MyType3 'd'
It should be emphasised that this has done absolutely nothing to the existing !! function defined in the prelude, nor to any other module that uses it. The !! defined here is a new and entirely unrelated function, which just happens to have the same name and to delegate to Prelude.!! in one particular instance. No existing code will be able to start using !! on MyType1 without modification (though other modules you can change can of course import your new !! to get this functionality). Any code that imports this module will either have to module-qualify all uses of !! or else use the same import Prelude hiding ((!!)) line to hide the original one.
Hide the Prelude's (!!) operator and you can define your own (!!) operator:
import Prelude hiding ((!!))
(!!) :: MyType1 -> MyType2 -> MyType3
x !! i = ... -- Go wild!
You can even make a type class for your new (!!) operator if you prefer.

Haskell Ambiguous type error

I have the following definitions
{-# LANGUAGE MultiParamTypeClasses,
FunctionalDependencies,
FlexibleInstances,
FlexibleContexts #-}
import qualified Data.Map as M
class Graph g n e | g -> n e where
empty :: g -- returns an empty graph
type Matrix a = [[a]]
data MxGraph a b = MxGraph { nodeMap :: M.Map a Int, edgeMatrix :: Matrix (Maybe b) } deriving Show
instance (Ord n) => Graph (MxGraph n e) n e where
empty = MxGraph M.empty [[]]
When I try to call empty I get an ambiguous type error
*Main> empty
Ambiguous type variables `g0', `n0', `e0' in the constraint: ...
Why do I get this error? How can I fix it?
You are seeing this type error because Haskell is not provided with sufficient information to know the type of empty.
Any attempt to evaluate an expression though requires the type. The type is not defined yet because the instance cannot be selected yet. That is, as the functional dependency says, the instance can only be selected if type parameter g is known. Simply, it is not known because you do not specify it in any way (such as with a type annotation).
The type-class system makes an open world assumption. This means that there could be many instances for the type class in question and hence the type system is conservative in selecting an instance (even if currently there is only one instance that makes sense to you, but there could be more some other day and the system doesn't want to change its mind just because some other instances get into scope).

Is there a way to define an existentially quantified newtype in GHC Haskell?

Is it possible in (GHC) Haskell to define an existentially-quantified newtype? I understand that if type classes are involved it can't be done in a dictionary-passing implementation, but for my purposes type-classes are not needed. What I'd really like to define is this:
newtype Key t where Key :: t a -> Key t
But GHC does not seem to like it. Currently I'm using data Key t where Key :: !(t a) -> Key t. Is there any way (perhaps just using -funbox-strict-fields?) to define a type with the same semantics and overhead as the newtype version above? My understanding is that even with strict fields unboxed there will still be an extra tag word, though I could be totally wrong there.
This is not something that's causing me any noticeable performance issues. It just surprised me that the newtype was not allowed. I'm a naturally curious person, so I can't help wondering whether the version I have is being compiled to the same representation or whether any equivalent type could be defined which would be.
No, according to GHC:
A newtype constructor cannot have an existential context
However, data is just fine:
{-# LANGUAGE ExistentialQuantification #-}
data E = forall a. Show a => E a
test = [ E "foo"
, E (7 :: Int)
, E 'x'
]
main = mapM_ (\(E e) -> print e) test
E.g.
*Main> main
"foo"
7
'x'
Logically, you do need the dictionary (or tag) allocated somewhere. And that doesn't make sense if you erase the constructor.
Note: You can't unbox functions though, as you seem to be hinting at, nor polymorphic fields.
Is there any way (perhaps just using -funbox-strict-fields?) to define a type with the same semantics and overhead as the newtype version above?
Removing the -XGADTs helps me think about this:
{-# LANGUAGE ExistentialQuantification #-}
data Key t = forall a. Key !(t a)
As in, Key (Just 'x') :: Key Maybe
So you want to guarantee the Key constructor is erased.
Here's the code in GHC for type checking the constraints on newtype:
-- Checks for the data constructor of a newtype
checkNewDataCon con
= do { checkTc (isSingleton arg_tys) (newtypeFieldErr con (length arg_tys))
-- One argument
; checkTc (null eq_spec) (newtypePredError con)
-- Return type is (T a b c)
; checkTc (null ex_tvs && null eq_theta && null dict_theta) (newtypeExError con)
-- No existentials
; checkTc (not (any isBanged (dataConStrictMarks con)))
(newtypeStrictError con)
-- No strictness
We can see why ! won't have any effect on the representation, since it contains polymorphic components, so needs to use the universal representation. And unlifted newtype doesn't make sense, nor non-singleton constructors.
The only thing I can think of is that, like for record accessors for existentials, the opaque type variable will escape if the newtype is exposed.
I don't see any reason it couldn't be made to work, but perhaps ghc has some internal representation issues with it.

List of existentially quantified values in Haskell

I'm wondering why this piece of code doesn't type-check:
{-# LANGUAGE ScopedTypeVariables, Rank2Types, RankNTypes #-}
{-# OPTIONS -fglasgow-exts #-}
module Main where
foo :: [forall a. a]
foo = [1]
ghc complains:
Could not deduce (Num a) from the context ()
arising from the literal `1' at exist5.hs:7:7
Given that:
Prelude> :t 1
1 :: (Num t) => t
Prelude>
it seems that the (Num t) context can't match the () context of arg. The point I can't understand is that since () is more general than (Num t), the latter should and inclusion of the former. Has this anything to do with lack of Haskell support for sub-typing?
Thank you for any comment on this.
You're not using existential quantification here. You're using rank N types.
Here [forall a. a] means that every element must have every possible type (not any, every). So [undefined, undefined] would be a valid list of that type and that's basically it.
To expand on that a bit: if a list has type [forall a. a] that means that all the elements have type forall a. a. That means that any function that takes any kind of argument, can take an element of that list as argument. This is no longer true if you put in an element which has a more specific type than forall a. a, so you can't.
To get a list which can contain any type, you need to define your own list type with existential quantification. Like so:
data MyList = Nil | forall a. Cons a MyList
foo :: MyList
foo = Cons 1 Nil
Of course unless you restrain element types to at least instantiate Show, you can't do anything with a list of that type.
First, your example doesn't even get that far with me for the current GHC, because you need to enable ImpredecativeTypes as well. Doing so results in a warning that ImpredicativeTypes will be simplified or removed in the next GHC. So we're not in good territory here. Nonetheless, adding the proper Num constraint (foo :: [forall a. Num a => a]) does allow your example to compile.
Let's leave aside impredicative types and look at a simpler example:
data Foo = Foo (forall a. a)
foo = Foo 1
This also doesn't compile with the error Could not deduce (Num a) from the context ().
Why? Well, the type promises that you're going to give the Foo constructor something with the quality that for any type a, it produces an a. The only thing that satisfies this is bottom. An integer literal, on the other hand, promises that for any type a that is of class Num it produces an a. So the types are clearly incompatible. We can however pull the forall a bit further out, to get what you probably want:
data Foo = forall a. Foo a
foo = Foo 1
So that compiles. But what can we do with it? Well, let's try to define an extractor function:
unFoo (Foo x) = x
Oops! Quantified type variable 'a' escapes. So we can define that, but we can't do much interesting with it. If we gave a class context, then we could at least use some of the class functions on it.
There is a time and place for existentials, including ones without class context, but its fairly rare, especially when you're getting started. When you do end up using them, often it will be in the context of GADTs, which are a superset of existential types, but in which the way that existentials arise feels quite natural.
Because the declaration [forall a. a] is (in meaning) the equivalent of saying, "I have a list, and if you (i.e. the computer) pick a type, I guarantee that the elements of said list will be that type."
The compiler is "calling your bluff", so-to-speak, by complaining, "I 'know' that if you give me a 1, that its type is in the Num class, but you said that I could pick any type I wanted to for that list."
Basically, you're trying to use the value of a universal type as if it were the type of a universal value. Those aren't the same thing, though.

Resources