Vector containing GADT - haskell

I'm just learning everything I can about ExistentialQuantification and GADTs and KindSignatures, etc. And to do that I try to come up with some small programs which help me to understand everything better.
Now I have this small snippet (which actually compiles, so you can try it on your own, requires vector and mtl packages) and would like to know whether it is at all possible to do what I am trying to accomplish or guide me to how to make it work
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
import Control.Monad.State.Lazy
import qualified Data.Vector as V
data MenuItem = ListS | ActionS | SliderS
data MenuItemReference (a :: MenuItem) (n :: *) where
MenuListSReference :: Int -> MenuItemReference ListS Int
MenuActionSReference :: Int -> MenuItemReference ActionS Int
MenuSliderSReference :: Int -> MenuItemReference SliderS Int
data MyState = MyState { vec :: forall a. V.Vector (MenuItemReference a Int) }
newMyState :: MyState
newMyState = MyState { vec = V.empty }
listRef :: MenuItemReference ListS Int
listRef = MenuListSReference 5
actionRef :: MenuItemReference ActionS Int
actionRef = MenuActionSReference 3
myComputation :: State MyState ()
myComputation = do
addItem listRef
addItem actionRef
return ()
addItem :: forall a. MenuItemReference a Int -> State MyState ()
addItem menuItemRef = do
s <- get
put (s { vec = (vec s) `V.snoc` menuItemRef })
main :: IO ()
main = do
print $ evalState myComputation newMyState
As you can see I'm trying to get a Vector of MenuItemReferences in it... What is it that I'm doing wrong because with what I have at the moment I get the error:
Couldn't match type ‘a’ with ‘a1’
‘a’ is a rigid type variable bound by
the type signature for
addItem :: MenuItemReference a Int -> State MyState ()
at Main.hs:34:19
‘a1’ is a rigid type variable bound by
a type expected by the context: V.Vector (MenuItemReference a1 Int)
at Main.hs:37:10
Expected type: MenuItemReference a1 Int
Actual type: MenuItemReference a Int
Relevant bindings include
menuItemRef :: MenuItemReference a Int (bound at Main.hs:35:9)
addItem :: MenuItemReference a Int -> State MyState ()
(bound at Main.hs:35:1)
In the second argument of ‘V.snoc’, namely ‘menuItemRef’
In the ‘vec’ field of a record
Could someone explain what is the reason behind the error and how I could approach (if at all possible) the thing I am trying to accomplish.

Why not just
data MenuItemReference =
MenuListSReference Int |
MenuActionSReference Int |
MenuSliderSReference Int
then?
The constructor used already annotates the value. You don't need to inject the phantom type, because the information is already there.
Besides, doing so would require enabling GHC ({-# LANGUAGE ImpredicativeTypes #-}) to actually support impredicative polymorphism to construct Vector [forall a. MenuItemReference a Int] and use it polymorphically. While it does support that, the support has been described as "fragile at best and broken at worst".
As a side note this nice blog post explains how we can get rid of impredicative types, using newtypes and RankNTypes instead. This does require you to introduce a layer of newtype, however.

Related

Parameterized Types in Haskell

Why do types in Haskell have to be explicitly parameterized in the type constructor parameter?
For example:
data Maybe a = Nothing | Just a
Here a has to be specified with the type. Why can't it be specified only in the constructor?
data Maybe = Nothing | Just a
Why did they make this choice from a design point of view? Is one better than the other?
I do understand that first is more strongly typed than the second, but there isn't even an option for the second one.
Edit :
Example function
data Maybe = Just a | Nothing
div :: (Int -> Int -> Maybe)
div a b
| b == 0 = Nothing
| otherwise = Just (a / b)
It would probably clear things up to use GADT notation, since the standard notation kind of mangles together the type- and value-level languages.
The standard Maybe type looks thus as a GADT:
{-# LANGUAGE GADTs #-}
data Maybe a where
Nothing :: Maybe a
Just :: a -> Maybe a
The “un-parameterised” version is also possible:
data EMaybe where
ENothing :: EMaybe
EJust :: a -> EMaybe
(as Joseph Sible commented, this is called an existential type). And now you can define
foo :: Maybe Int
foo = Just 37
foo' :: EMaybe
foo' = EJust 37
Great, so why don't we just use EMaybe always?
Well, the problem is when you want to use such a value. With Maybe it's fine, you have full control of the contained type:
bhrar :: Maybe Int -> String
bhrar Nothing = "No number 😞"
bhrar (Just i)
| i<0 = "Negative 😖"
| otherwise = replicate i '😌'
But what can you do with a value of type EMaybe? Not much, it turns out, because EJust contains a value of some unknown type. So whatever you try to use the value for, will be a type error, because the compiler has no way to confirm it's actually the right type.
bhrar :: EMaybe -> String
bhrar' (EJust i) = replicate i '😌'
=====> Error couldn't match expected type Int with a
If a variable is not reflected in the return type it is considered existential. This is possible to define data ExMaybe = ExNothing | forall a. ExJust a but the argument to ExJust is completely useless. ExJust True and ExJust () both have type ExMaybe and are indistinguisable from the type system's perspective.
Here is the GADT syntax for both the original Maybe and the existential ExMaybe
{-# Language GADTs #-}
{-# Language LambdaCase #-}
{-# Language PolyKinds #-}
{-# Language ScopedTypeVariables #-}
{-# Language StandaloneKindSignatures #-}
{-# Language TypeApplications #-}
import Data.Kind (Type)
import Prelude hiding (Maybe(..))
type Maybe :: Type -> Type
data Maybe a where
Nothing :: Maybe a
Just :: a -> Maybe a
type ExMaybe :: Type
data ExMaybe where
ExNothing :: ExMaybe
ExJust :: a -> ExMaybe
You're question is like asking why a function f x = .. needs to specify its argument, there is the option of making the type argument invisible but this is very odd but the argument is still there even if invisible.
-- >> :t JUST
-- JUST :: a -> MAYBE
-- >> :t JUST 'a'
-- JUST 'a' :: MAYBE
type MAYBE :: forall (a :: Type). Type
data MAYBE where
NOTHING :: MAYBE #a
JUST :: a -> MAYBE #a
mAYBE :: b -> (a -> b) -> MAYBE #a -> b
mAYBE nOTHING jUST = \case
NOTHING -> nOTHING
JUST a -> jUST a
Having explicit type parameters makes it much more expressive. You lose so much information without it. For example, how would you write the type of map? Or functors in general?
map :: (a -> b) -> [a] -> [b]
This version says almost nothing about what’s going on
map :: (a -> b) -> [] -> []
Or even worse, head:
head :: [] -> a
Now we suddenly have access to unsafe coerce and zero type safety at all.
unsafeCoerce :: a -> b
unsafeCoerce x = head [x]
But we don’t just lose safety, we also lose the ability to do some things. For example if we want to read something into a list or Maybe, we can no longer specify what kind of list we want.
read :: Read a => a
example :: [Int] -> String
main = do
xs <- getLine
putStringLine (example xs)
This program would be impossible to write without lists having an explicit type parameter. (Or rather, read would be unable to have different implementations for different list types, since content type is now opaque)
It is however, as was mentioned by others, still possible to define a similar type by using the ExistentialQuantification extension. But in those cases you are very limited in how you can use those data types, since you cannot know what they contain.

Haskell: How to write a type of function from a specific type to any type?

In Scala, I could write the following trait:
trait Consumer[A] {
def apply(a: A): Unit
}
And scala would convert whatever I want to Unit, i.e., it would discard the type. Equivalently, I could have said that apply returns Any and ignore the result.
However, in Haskell, if I defined the type as type Consumer = a -> IO (), I wouldn't be able to pass an Int -> IO Int function, as Int isn't ().
There are two ways I know of solving this issue, but none are satisfactory:
Use Data.Functor.void at the call site to manual change IO a to IO (). This is annoying as an API user.
define type Consumer a b = a -> IO b, but then every time I would want to use Consumer in a signature, I would have to carry the useless type b.
Is there any way to define the Consumer type as a function from a to "IO Any"? As far as I know, Haskell does not support something like exists x. a -> IO x.
Using forall results in the opposite of what I want, e.g.,
type Consumer = forall b. a -> IO b
foo :: Int -> IO Int
foo = undefined
bar :: Consumer Int
bar = foo
results in the error:
• Couldn't match type ‘b’ with ‘Int’
‘b’ is a rigid type variable bound by
the type signature for:
bar :: Consumer Int
Expected type: Int -> IO b
Actual type: Int -> IO Int
• In the expression: foo
In an equation for ‘bar’: bar = foo
• Relevant bindings include
bar :: Int -> IO b
Note that I specifically want Consumer to a be type alias, and not a data constructor, as is described here: Haskell function returning existential type. I wouldn't mind if Consumer were a class if anyone knows how to make that work.
To get an existentially-quantified type in Haskell, you need to write down a data declaration (as opposed to a newtype declaration or a type alias declaration, like you used.).
Here's a Consumer type that fits your purposes:
{-# LANGUAGE ExistentialQuantification #-}
data Consumer input = forall output. Consumer { runDiscardingOutput :: input -> IO output }
And, analogously, here is what your example would look like with the new type:
f :: Int -> IO Int
f = undefined
g :: Consumer Int
g = Consumer f
This doesn't really avoid your concerns about client code needing an extra call, though. (I mean, this is no better than exporting a consumer = Data.Functor.void binding from your library.) Also, it complicates how clients will be able to use a consumer, too:
consumer :: Consumer Int
consumer = Consumer (\x -> return [x])
{- This doesn't typecheck -}
main1 :: IO ()
main1 = runIgnoringOutput consumer 4
{- This doesn't typecheck (!!!) -}
main2 :: IO ()
main2 = void (runIgnoringOutput consumer 4)
{- Only this typechecks :( -}
main3 :: IO ()
main3 =
case consumer of
Consumer f -> Data.Functor.void (f 4)
So it would probably make sense to have a apply function in your library that did the dirty work, just as there was an apply function in the Scala library.
apply :: Consumer a -> a -> IO ()
apply (Consumer f) x = void (f x)
I wouldn't mind if Consumer were a class if anyone knows how to make that work.
You can simulate existential types for classes with an associated type family.
But Haskell doesn't allow ambiguous types in classes without using something like a GADT existential wrapper, so you would still have the type information there somewhere.
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses #-}
class Consumer c a where
type Output c
consume :: c -> a -> IO (Output c)
c is necessary here to allow for the reconstruction of the type of Output c, so it is not strictly an existential. But you can now write
{-# LANGUAGE FlexibleInstances, InstanceSigs #-}
instance Consumer (a -> IO b) a where
type Output (a -> IO b) = b
consume :: (a -> IO b) -> a -> IO b
consume = id
This may not fit your use case, because there will not be a type signature that can express Consumer a in a truly existential way. But it is possible to write
... :: (Consumer c a) => c -> ...
(You could also make use of FunctionalDependencies here to clarify the class somewhat.)

Type families: top level vs. associated

I am just starting to learn type families. The GHC documentation states that top level and associated type families have the same functionality, but the code I am writing behaves differently in top level than it does when the families are associated. This compiles and runs fine:
{-# LANGUAGE TypeFamilies #-}
module Test where
-- type family R a
-- type instance R Maybe = Int
class C' a where
type R a
getInt' :: a Int
getBool' :: R a -> a Bool
instance C' Maybe where
type R Maybe = Int
getInt' = Just 3
getBool' i = Just $ i < 10
printer :: IO ()
printer = print $ (getBool' 5 :: Maybe Bool)
but this gives me a type error:
{-# LANGUAGE TypeFamilies #-}
module Test where
type family R a
type instance R Maybe = Int
class C' a where
-- type R a
getInt' :: a Int
getBool' :: R a -> a Bool
instance C' Maybe where
-- type R Maybe = Int
getInt' = Just 3
getBool' i = Just $ i < 10
printer :: IO ()
printer = print $ (getBool' 5 :: Maybe Bool)
These look identical to me; why is it that one compiles and the other doesn't?
The second one works if you annotate the kind:
type family R (a :: * -> *)
I don't think there's any reason why the right kind is only inferred for the associated type family.

Lenses and prisms with sum types

This code won't compile.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data A = A { _a1 :: B, _a2 :: Int }
makeLenses ''A
data B = B1 { _b1 :: Int } | B2
makeLenses ''B
The error is amy.hs:5:21: Not in scope: type constructor or class ‘B’. I have two questions.
Is there a way to do something like this, or do I need to write my own lenses for B?
Given an A, I would like to apply a function to the b1 field, if that field exists. I think this is a job for prisms, but I haven't figured out how to do it.
Rearrange your program as follows
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data A = A { _a1 :: B, _a2 :: Int }
data B = B1 { _b1 :: Int } | B2
makeLenses ''A
makeLenses ''B
The issue has to do with staging order of Template Haskell (and in this case it's possibly a bug).
Observe that makeLenses ''B creates a Traversal for the _b1 field because it only appears in one of the two constructors.
b1 :: Traversal' B Int
If you were to use Prisms, as well, you'd add
makePrisms ''B
which would produce
_B1 :: Prism' B Int
_B2 :: Prism' B ()

How can I use restricted constraints with GADTs?

I have the following code, and I would like this to fail type checking:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
import Control.Lens
data GADT e a where
One :: Greet e => String -> GADT e String
Two :: Increment e => Int -> GADT e Int
class Greet a where
_Greet :: Prism' a String
class Increment a where
_Increment :: Prism' a Int
instance Greet (Either String Int) where
_Greet = _Left
instance Increment (Either String Int) where
_Increment = _Right
run :: GADT e a -> Either String Int
run = go
where
go (One x) = review _Greet x
go (Two x) = review _Greet "Hello"
The idea is that each entry in the GADT has an associated error, which I'm modelling with a Prism into some larger structure. When I "interpret" this GADT, I provide a concrete type for e that has instances for all of these Prisms. However, for each individual case, I don't want to be able to use instances that weren't declared in the constructor's associated context.
The above code should be an error, because when I pattern match on Two I should learn that I can only use Increment e, but I'm using Greet. I can see why this works - Either String Int has an instance for Greet, so everything checks out.
I'm not sure what the best way to fix this is. Maybe I can use entailment from Data.Constraint, or perhaps there's a trick with higher rank types.
Any ideas?
The problem is you're fixing the final result type, so the instance exists and the type checker can find it.
Try something like:
run :: GADT e a -> e
Now the result type can't pick the instance for review and parametricity enforces your invariant.

Resources