编写Pnt2d数据类型Functor实例时遭遇occurs check错误求助
问题与解决方案
问题描述
我定义了如下数据类型:
data Pnt2d i v = Pnt2d {_p2id:: i, _v2:: V2 v}
想为它实现Functor实例,让fmap作用在第二个组件(V2)的内部值上,写的代码是:
instance Functor (Pnt2d i) where fmap f (Pnt2d i v) = Pnt2d i (f v)
结果出现了"occurs check"错误。我知道Functor只能作用在多参数类型的第二个参数上,这里符合要求,但第二个类型参数是V2的内部参数,怀疑这是错误原因。试过用Lenses但没解决,希望得到有无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)
错误原因
你写的代码里,v的类型是V2 a,但fmap要求f的类型是a -> b——直接把f作用在v上,相当于要求a等于V2 a,这是个无限递归的类型,Haskell自然会报occurs check错误。你的需求是让fmap映射到V2内部的v类型参数上,而不是映射V2本身,所以得调整fmap的实现。
无Lenses解决方案
因为V2本身已经是Functor实例(如果用的是linear库或自定义V2,只要它实现了Functor),可以直接复用它的fmap:
instance Functor (Pnt2d i) where fmap f (Pnt2d i v) = Pnt2d i (fmap f v)
如果是自定义的V2还没实现Functor,先给V2加个实例:
data V2 a = V2 a a deriving (Show) instance Functor V2 where fmap f (V2 x y) = V2 (f x) (f y)
这样Pnt2d的fmap就能正确把函数应用到V2的两个元素上。
用Lenses的解决方案
如果想用Lens操作,先给_v2定义一个Lens(需要Control.Lens库):
import Control.Lens _v2 :: Lens' (Pnt2d i v) (V2 v) _v2 = lens _v2 (\p newV2 -> p { _v2 = newV2 })
然后Functor实例可以写成:
instance Functor (Pnt2d i) where fmap f = over (_v2 . mapped) f
这里_v2 . mapped是一个遍历器,能直接访问V2内部的元素,over函数会把f应用到这些元素上。
内容的提问来源于stack exchange,提问作者user855443
相关产品推荐
相关产品推荐

