I create my own type parameters as follow:
data Node a = Node a
data Cost = Int | Float
data Edge Node Cost = Edge ((Node,Node),Cost)
data Graph Edge = Graph [Edge]
And get an error:
Unexpected type Node' where type variable expectedEdge Node Cost’
In the declaration of
How can I fix it?
Type Constructors vs Data Constructors
You have to tag the types in a union type in haskell:
should say
Notice that this is because
IntandFloatare types. Example data would beI 5orF 5.6. We need data constructors too.IandFare data constructors here.I :: Int -> CostandF :: Float -> Cost. They’re functions that turn Ints or Floats into Costs. You can have a constructor that doesn’t take an argument, for example, as in your comment,Here True and False are constructors, not types. Example data would be just
TrueorFalse. You do have to have constructors every time, which is why we need to tag the typesIntandFloatThe definition
is a bit confusing, because on the left hand side,
Nodeis a sort of type function we call a type constructor, and has kind* -> *, but on the right hand sideNodeis a data constructor of typea -> Node a. Example data:Node "hello"of typeNode String. This would be less confusing if we wroteSo
Nodeis the type constructor andNis the data constructor. This gives sample dataN "Hello"of typeNode String. For this sort of definition, we haven’t made a lot of difference, so we tend to saybecause the compiler can optimise it away in most cases, but we get type safety at the source code end.
Type Constructors need types
You also need
because
Nodeis a type constructor (it has kind* -> *) so you have to always give it a type to work on. I’ve given itaso you can make your node out of anything.However, you don’t need the brackets, and a union of Int and Float is probably not as useful as allowing any cost type, by using lower case
costinstead of the fixed typeCost(If you want to make sure no-one ever makes an edge out of any cost that is non-numerical, you can say
data Num cost => Edge a cost = Edge (Node a) (Node a) cost. In my view that’s a much better compromise between the awkwardness of tagging Int and Float and allowing arbitrary costs, but you don’t need it – you can quite happily add the restriction just exactly when you need it on a function that combines costs with+.)Your whole definitions would then be
Again, you need to write
Graph [Edge a c]becauseEdgetakes two types, so has kind* -> * -> *.