What does an apostrophe in front of a list ( '[Something] ) mean in Haskell? - haskell

I was reading the Servant documentation and came across this line:
type UserAPI = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
What is the ' doing to that list?

Quotes are used to distinguish type-level constructors vs. term-level constructors of promoted types.
For instance:
{-# LANGUAGE DataKinds #-}
data Which = One | Two
myPick :: Which -- Type
myPick = One
type MyPick :: Which -- Kind
type MyPick = 'One
By the way, the kind annotation type MyPick :: Which is not valid Haskell but it gives you an idea of the correspondence between the term and the type level. The closest you can get to this requires turning on another extension:
{-# LANGUAGE TypeFamilies #-}
type family MyPick :: Which where
MyPick = 'One

This is DataKinds in action, which:
lifts values at the type level, and
lifts types to the kind level
This however causes confusion at the type level. Now, in types, [X] might either be [X] :: *, the list-of-X type, or instead we might have [X] :: [T] due to the lifting -- that is the value [X] (list containing only the single value X), with X of type T, lifted at the type level.
To overcome this ambiguity, GHC requires a quote in front of lifted value constructors. So, we have [X] :: *, and '[X] :: [T].
Concretely, in your case, Get '[JSON] [User] involves both the list value [JSON] lifted to the type level, and the list type [User]. To better appreciate the difference, note that there are no terms of type '[JSON], since this is not a list type. We could even have Get '[JSON,JSON,JSON] [User] as a well-kinded expression, or even Get '[] [User]. Instead, we can't have Get '[JSON] [User,User] since [User,User] is not a type.
(The type Get '[JSON,JSON,JSON] [User], even if it is valid, could not be meaningfully used by the Servant library. I have no idea of what that lifted list is used for in Servant.)

Related

Indirectly reference specific AND unspecific objects in Haskell without monads

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

Where does '[] come from and where is it declared? [duplicate]

I was reading the Servant documentation and came across this line:
type UserAPI = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User]
What is the ' doing to that list?
Quotes are used to distinguish type-level constructors vs. term-level constructors of promoted types.
For instance:
{-# LANGUAGE DataKinds #-}
data Which = One | Two
myPick :: Which -- Type
myPick = One
type MyPick :: Which -- Kind
type MyPick = 'One
By the way, the kind annotation type MyPick :: Which is not valid Haskell but it gives you an idea of the correspondence between the term and the type level. The closest you can get to this requires turning on another extension:
{-# LANGUAGE TypeFamilies #-}
type family MyPick :: Which where
MyPick = 'One
This is DataKinds in action, which:
lifts values at the type level, and
lifts types to the kind level
This however causes confusion at the type level. Now, in types, [X] might either be [X] :: *, the list-of-X type, or instead we might have [X] :: [T] due to the lifting -- that is the value [X] (list containing only the single value X), with X of type T, lifted at the type level.
To overcome this ambiguity, GHC requires a quote in front of lifted value constructors. So, we have [X] :: *, and '[X] :: [T].
Concretely, in your case, Get '[JSON] [User] involves both the list value [JSON] lifted to the type level, and the list type [User]. To better appreciate the difference, note that there are no terms of type '[JSON], since this is not a list type. We could even have Get '[JSON,JSON,JSON] [User] as a well-kinded expression, or even Get '[] [User]. Instead, we can't have Get '[JSON] [User,User] since [User,User] is not a type.
(The type Get '[JSON,JSON,JSON] [User], even if it is valid, could not be meaningfully used by the Servant library. I have no idea of what that lifted list is used for in Servant.)

Type Family Equivalent of `Eq`?

Type Families with Class shows:
As I incompletely understand, this slide shows 2 ways of implementing Eq: via a type class or type family.
I'm familiar with type classes and thus implemented MyEq:
class MyEq a where
eq :: a -> a -> Bool
But, when I tried to define the type family version, it failed to compile:
data Defined = Yes | No
type family IsEq (a :: *) :: Defined
due to:
TypeEq.hs:30:30: error:
• Type constructor ‘Defined’ cannot be used here
(Perhaps you intended to use DataKinds)
• In the kind ‘Defined’
Please explain how to implement the type family version of the Eq type class.
Also, it'd be helpful, please, to show an implementation of such a type family instance (if that's even the right word).
This is kind of neat, glad to have stumbled across this. For the interested, here is the slide deck and here is the paper. This is a usual case of needing some language extensions.
{-# LANGUAGE DataKinds, TypeFamilies, TypeOperators, ConstraintKinds #-}
data Defined = Yes | No
type family IsEq (a :: *) :: Defined
type Eq a = IsEq a ~ Yes
Then, the "implementation" of this are instances like
type instance IsEq () = Yes -- '()' is an instance of 'Eq'
type instance IsEq Int = Yes -- 'Int' is an instance of 'Eq'
type instance IsEq [a] = IsEq a -- '[a]' is an instance of 'Eq' is 'a' is
You can "try" them out at GHCi:
ghci> :kind! IsEq [Int]
IsEq [Int] :: Defined
= Yes
But the paper and slide deck doesn't really worry too much about actually providing an equality function. (It mentions storing it in a field of Yes). So, why is this interesting if it isn't even ready to provide class methods? Because
it makes for a better mechanism than overlapping classes
backtracking search is easier than with typeclasses
it makes it possible to fail early with nice error message (encoded as a field in the No constructor)
Try adding DataKinds As a language extension (i.e. to the top of the file under a "language" pragma) as the error message suggests.
I haven't watched the talk, but iiuc, Defined is just Bool, where Yes is True. So if you enable DataKinds, you can just use IsEq a ~ 'True (and the apostrophe before True just means "this is a type").
Some background: what this extension does is "raise" every value of any algebraic datatypes (i.e. Declared with data, but not GADTs, iiuc) into its own type; and then raises each type into its own kind (a "kind" in Haskell is the "type of types"), i.e. not of "kind *" (pronounced "kind star"), which is the kind of normal Haskell values that exist at runtime.
btw:
[Bool] :: * means that "a list of liens is a type". and [] :: * -> * means that the type constructor for lists has kind "type to type", i.e. "once you give List a single type, you get back a type".

How can I find out which (concrete) types satisfy a set of typeclass constraints?

Given a number of typeclass constraints:
{-# LANGUAGE ConstraintKinds, MultiParamTypeClasses #-}
import Data.Array.Unboxed(Ix,IArray,UArray)
type IntLike a = (Ord a, Num a, Enum a, Show a, Ix a, IArray UArray a)
How can I find out which types satisfy IntLike, i.e. all the mentioned constraints jointly?
I can puzzle together the information needed from the output of ghci's :info command, and then doublecheck my work by calling (or having ghci typecheck)
isIntLike :: IntLike -> Bool
isIntLike = const True
at various types, e.g. isIntLike (3::Int).
Is there a way to get ghci to do this for me?
I'm currently interested in concrete types, but wouldn't mind having a more general solution which also does clever stuff with unifying contexts!
Community Wiki answer based on the comments:
You can do this using template haskell.
main = print $(reify ''Show >>= stringE . show).
This won't work for type synonyms - rather, reify returns the AST representing the type synonym itself, without expanding it. You can check for type synonyms which are constraints, extract the constraints of which that type synonym consists, and continue reifying those.

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

Resources