Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type classes & instances: Pattern parameter becoming a list -- or not?

Haskell newbie here -- I ran into this issue yesterday that I just can't wrap my head around.

Minimum Working Example

It might not be so minimal, but it demonstrates my issue -- here goes:

data VectorFeatureSet feature = VFS [feature]

class FeatureSet fs where
    getFeatures :: fs fl -> fl
instance FeatureSet VectorFeatureSet where
    getFeatures (VFS fl) = fl              -- <- error occurs here

(Background info:) A short comment on what these types mean: a Feature is a geographical entity that has a shape and optionally some attributes. A FeatureSet is just a group of Features that belong together.

The error that the compiler throws on the last line of this code snippet:

Couldn't match expected type `fl' with actual type `[fl]'
  `fl' is a rigid type variable bound by
       the type signature for getFeatures :: VectorFeatureSet fl -> fl
       at (mentioned line)
In the expression: fl
In an equation for `getFeatures': getFeatures (VFS fl) = fl
In the instance declaration for `FeatureSet VectorFeatureSet'

If I change the function definition to

getFeatures (VFS [fl]) = fl

the compiler accepts it.

(Side note: I know that Haskell can create selector functions for me if I use named field notation, but I'm currently learning Haskell so I'm hand-writing these on purpose.)

Question

Now, the getFeatures function should serve simply to extract the list of features from the FeatureSet. My understanding of patterns is that if I don't need to access/process the contents of a list, I don't need to specify a pattern parameter with the list notation, but can just take the list from the pattern and return it in the function.

But here, Haskell wants me to use a function definition like fs -> [fl] -> fl to bind a signature like fs -> fl -> fl (at least, that's how I understand it).

So my question here is: Why is the type of the pattern parameter fl different on the left and right hand side of the equation of the function definition?

I feel like I'm missing some fundamental piece here, but I cannot figure out what part of the basics to go back to to get this straight :(

like image 969
Nevik Rehnel Avatar asked Dec 05 '25 15:12

Nevik Rehnel


1 Answers

Given the definition of VectorFeatureSet, the constructor VFS has type [fl] -> VectorFeatureSet fl, i.e. the value it "contains" will be a list of fl.

In your instance for FeatureSet, getFeatures should have type VectorFeatureSet fl -> fl.

So when you write getFeatures (VFS fl) = fl, you are returning a list of features, not a single feature, because the variable fl has type [fl] - note that types and variables live in different namespaces.

That's what the type error is telling you - the function was expected to return something of type fl but actually produced something of type [fl].

When you write getFeatures (VFS [fl]) = fl, you are actually pattern-matching for a single-element list, and so your function will fail if you try to call it with either VectorFeatureSet [] or VectorFeatureSet [x,y] etc.

Given the name of getFeatures and your description of it, it sounds like it should be defined as

class FeatureSet fs where
    getFeatures :: fs fl -> [fl]
like image 155
GS - Apologise to Monica Avatar answered Dec 07 '25 17:12

GS - Apologise to Monica