Haskell newbie here -- I ran into this issue yesterday that I just can't wrap my head around.
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.)
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 :(
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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With