Search code examples
haskelltype-constructor

What does the parameters without arrows mean in type constructor?


In the expression

data Frank a b = Frank {frankField :: b a} deriving (Show)

What does {frankField :: b a} means?

Is {frankField :: b a} a type constructor? If so, should the parameters look like b->a instead b a?


Solution

  • Frank is a type of kind * -> (* -> *) -> *, that is, it takes a type a (of kind *) such as Int, Char, or String; and a unary type constructor b (of kind * -> *) such as Maybe or Either String. (You can check the kind of a type using the :kind or :k command in GHCi.)

    It has one constructor, also named Frank, which contains one field (not a constructor) of type b a called frankField—for example, the type of frankField in a value of type Frank Int Maybe is Maybe Int, since b = Maybe and a = Int, so b a = Maybe Int.

    This definition is using record notation to give a name to the field—you could also have written just data Frank a b = Frank (b a) to leave it anonymous, but the advantage of naming the field is that you can use explicit record syntax to construct a Frank value:

    frank1 :: Frank Int Maybe
    frank1 = Frank { frankField = Just 1 }
    

    Or to modify a value:

    frank2 :: Frank Int Maybe
    frank2 = frank1 { frankField = Nothing }
    

    Or access the field by name:

    value :: Maybe Int
    value = frankField frank1
    

    This is more convenient, and more common, when a constructor includes multiple fields; also, you’ll typically see newtype instead of data when a type wraps only a single value, since newtype has less overhead and slightly different laziness semantics.