Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composing type constructors like functions

Tags:

haskell

I recently came across a situation where I wanted to be able to compose type constructors in an instance declaration. I would have liked to do this:

instance (SomeClass t, SomeClass t') => SomeClass (t . t') where

with (t . t') defined such that (t . t') a = t (t' a) (so t and t' have kind * -> *. We can partially apply type constructors, like functions, so what is the reason we cannot compose them? Also, is there perhaps a workaround for what I was trying to achieve? Perhaps with equality constraints?

(I do know that Control.Compose exists, but it simply creates a newtype wrapper - I would like a type synonym).

like image 811
Alec Avatar asked Jun 24 '15 05:06

Alec


People also ask

What do you mean by type constructor?

In the area of mathematical logic and computer science known as type theory, a type constructor is a feature of a typed formal language that builds new types from old ones. Basic types are considered to be built using nullary type constructors.

What is type constructor in DBMS?

Object and Object/Relational Databases Complex objects within the database must be constructed of other objects found within the database. Type constructors are the mechanism for this purpose. The simplest constructors are base or atomic, tuple, and set.

What is a type constructor in Haskell?

In a data declaration, a type constructor is the thing on the left hand side of the equals sign. The data constructor(s) are the things on the right hand side of the equals sign. You use type constructors where a type is expected, and you use data constructors where a value is expected.

How do you create a datatype in Haskell?

Making your own data type in HaskellNew data types are created via the data keyword. To create a Point data type, we need to provide a type constructor (the name of our type) and a data constructor (used to construct new instances of the type), followed by the types our type will contain.


1 Answers

(I do know that Control.Compose exists, but it simply creates a newtype wrapper - I would like a type synonym).

This is not allowed in Haskell. A type synonym must be fully applied: you can't write Compose t t', only Compose t t' a.

Allowing partially applied type synonyms would lead to type-level lambdas, which makes type inference undecidable, hence the lack of support for it in Haskell.


For instance, (enabling all the relevant GHC extensions)

type Compose t t' a = t (t' a)
data Proxy (k :: * -> *) = Proxy

pr :: Proxy (Compose [] [])
pr = Proxy

results in:

 Type synonym ‘Compose’ should have 3 arguments, but has been given 2
    In the type signature for ‘pr’: pr :: Proxy (Compose [] [])

Similarly,

class C k where f :: k Int -> Int
instance C (Compose [] []) where f _ = 6

yields:

Type synonym ‘Compose’ should have 3 arguments, but has been given 2
    In the instance declaration for ‘C (Compose [] [])’

Here's an example where type synonym partial application is allowed, instead (enabling LiberalTypeSynonyms):

type T k = k Int
type S = T (Compose [] [])

bar :: S -> S
bar = map (map succ)

Note however that this works only because after synonym expansion we get a fully applied type [] ([] Int) (i.e., [[Int]]). Roughly, this feature does not allow to do anything which one could have done without it, manually expanding the synonyms.

like image 173
chi Avatar answered Sep 30 '22 04:09

chi