Reputation: 2948
I have a data type
data Pnt2d i v = Pnt2d {_p2id:: i, _v2:: V2 v}
and would like to construct a functor to apply to the second component (V2) as
instance Functor (Pnt2d i) where
fmap f (Pnt2d i v) = Pnt2d i (f v)
but I get an "occurs check". I understand that I can build Functors only on the second parameter of a multi-parameter data type - which is the case here. What is special and probably the cause of the error is that the second type parameter is a type parameter of the inner (V2) type. It seems related to Functor error when using a data inside a data: "cannot construct the infinite type" I checked the type of the functor when written separately and it seems correct. The answer in Having trouble writing my fmap suggests that two nested functors were necessary - is this the case here?
I do not see, how to construct the functor in this case. I tried with Lenses, but to no avail and would be interested to see what the solution is with/without using Lenses.
src/Uniform/Point2d.hs:119:35: error:
• Occurs check: cannot construct the infinite type: b ~ V2 b
• In the second argument of ‘Pnt2d’, namely ‘(f v)’
In the expression: Pnt2d i (f v)
In an equation for ‘fmap’: fmap f (Pnt2d i v) = Pnt2d i (f v)
• Relevant bindings include
f :: a -> b (bound at src/Uniform/Point2d.hs:119:10)
fmap :: (a -> b) -> Pnt2d i a -> Pnt2d i b
(bound at src/Uniform/Point2d.hs:119:5)
|
119 | fmap f (Pnt2d i v) = Pnt2d i (f v)
| ^^^
src/Uniform/Point2d.hs:119:37: error:
• Occurs check: cannot construct the infinite type: a ~ V2 a
• In the first argument of ‘f’, namely ‘v’
In the second argument of ‘Pnt2d’, namely ‘(f v)’
In the expression: Pnt2d i (f v)
• Relevant bindings include
v :: V2 a (bound at src/Uniform/Point2d.hs:119:21)
f :: a -> b (bound at src/Uniform/Point2d.hs:119:10)
fmap :: (a -> b) -> Pnt2d i a -> Pnt2d i b
(bound at src/Uniform/Point2d.hs:119:5)
|
119 | fmap f (Pnt2d i v) = Pnt2d i (f v)
Upvotes: 0
Views: 109
Reputation: 33496
In your instance, f
has type a -> b
, but you're using it as if it has type V2 a -> V2 b
.
You need to lift f
using fmap
so that it has the type you want.
instance Functor (Pnt2d i) where
fmap f (Pnt2d i v) = Pnt2d i (fmap f v)
With lenses, you could do:
instance Functor (Pnt2d i) where
fmap f = v2 %~ fmap f
Upvotes: 4