Haskell 在逆变函子的实例声明中删除类型同义词
如果我定义:Haskell 在逆变函子的实例声明中删除类型同义词,haskell,Haskell,如果我定义: class Contravariant f where contramap :: (b -> a) -> f a -> f b type Op r a = (->) a r 并希望定义: instance Contravariant (Op r) where contramap f g = g . f 我得到的错误是实例类型不能是同义词。所以我想我需要一些类似于: instance Contravariant ((->) _ r)
class Contravariant f where
contramap :: (b -> a) -> f a -> f b
type Op r a = (->) a r
并希望定义:
instance Contravariant (Op r) where
contramap f g = g . f
我得到的错误是实例类型不能是同义词。所以我想我需要一些类似于:
instance Contravariant ((->) _ r) where
contramap f g = g . f
这当然行不通。如何使这个逆变实例工作?根据注释,通常的方法是定义一个
newtype
。请注意,语法与定义数据
类型基本相同,只是使用newtype
代替数据
,并且只允许一个字段。特别是,您需要一个构造函数,它通常与类型同名:
newtype Op r a = Op (a -> r)
-- ^^ ^^ ^^^^^^^^
-- newtype constructor field
这具有定义与a->r
同构的类型的效果,但是类型参数a
在完整类型Op r a
中位于“最后”,这允许您为Op r
定义一个逆变
实例。请注意,您需要在适当的地方展开和包装构造函数:
instance Contravariant (Op r) where
contramap f (Op g) = Op (g . f)
要进一步证明这是正确的方法,请注意,来自base
的inData.Functor.Contravariant
已经这样设置,除非他们决定使用字段访问器getOp
:
-- from the Data.Functor.Contravariant source
newtype Op a b = Op { getOp :: b -> a }
instance Contravariant (Op a) where
contramap f g = Op (getOp g . f)
根据注释,通常的方法是定义
newtype
。请注意,语法与定义数据
类型基本相同,只是使用newtype
代替数据
,并且只允许一个字段。特别是,您需要一个构造函数,它通常与类型同名:
newtype Op r a = Op (a -> r)
-- ^^ ^^ ^^^^^^^^
-- newtype constructor field
这具有定义与a->r
同构的类型的效果,但是类型参数a
在完整类型Op r a
中位于“最后”,这允许您为Op r
定义一个逆变
实例。请注意,您需要在适当的地方展开和包装构造函数:
instance Contravariant (Op r) where
contramap f (Op g) = Op (g . f)
要进一步证明这是正确的方法,请注意,来自base
的inData.Functor.Contravariant
已经这样设置,除非他们决定使用字段访问器getOp
:
-- from the Data.Functor.Contravariant source
newtype Op a b = Op { getOp :: b -> a }
instance Contravariant (Op a) where
contramap f g = Op (getOp g . f)
尝试使用newtype而不是type来定义Op。我不是hs方面的专家,但是type只创建一个别名。newtype的构造函数必须只有一个字段。@vkubicki您的类型只有一个字段,所以这不是障碍。它有两个类型参数,那又怎样?任何
type
同义词都可以转换为newtype
,因为它们都只有一个字段限制。这就是我在newtype Op r a=(->)a r中得到的错误newtype Op r a=Op(a->r)
相当于newtype Op r a=Op((->)a r)
尝试使用newtype而不是type来定义Op。我不是hs方面的专家,但是type只创建一个别名。newtype的构造函数必须只有一个字段。@vkubicki您的类型只有一个字段,所以这不是障碍。它有两个类型参数,那又怎样?任何类型
同义词都可以转换为新类型
,因为它们都只有一个字段限制。这就是我在新类型Op r a=(->)a r时遇到的错误新类型Op r a=Op(a->r)
等同于新类型Op r a=Op((->)a r