Haskell 实现参数化类型的函子
有这种类型的:Haskell 实现参数化类型的函子,haskell,functional-programming,functor,Haskell,Functional Programming,Functor,有这种类型的: {-# LANGUAGE GADTs #-} data Rgb a = (Num a, Show a) => Rgb a a a 我完全能够实现Showtypeclass: instance Show (Rgb a) where show (Rgb r g b) = "Rgb (" ++ show r ++ "," ++ show g ++ "," ++ show b ++ ")" 但是如果我试着用函子做同样的事情: instance Functor (Rgb a
{-# LANGUAGE GADTs #-}
data Rgb a = (Num a, Show a) => Rgb a a a
我完全能够实现Show
typeclass:
instance Show (Rgb a) where
show (Rgb r g b) = "Rgb (" ++ show r ++ "," ++ show g ++ "," ++ show b ++ ")"
但是如果我试着用函子做同样的事情
:
instance Functor (Rgb a) where
fmap f (Rgb r g b) = Rgb (f r) (f g) (f b)
我在GHCi上获得了以下输出:
<interactive>;:1093:19:
The first argument of ‘Functor’ should have kind ‘* > *’,
but ‘Rgb a’ has kind ‘*’
In the instance declaration for ‘Functor (Rgb a)’
但是我更喜欢为
Rgb
类型实现fmap
。您的Functor
实例不应该有类型参数:
instance Functor Rgb where
fmap f (Rgb r g b) = Rgb (f r) (f g) (f b)
如果要派生实例,包括Functor
,请使用派生Functor
杂注:
{-# LANGUAGE DeriveFunctor #-}
data Rgb a = Rgb a a a -- NOTE: DO NOT CONSTRAIN DATA!
deriving (Show, Eq, Ord, Functor)
此外,数据类型声明上的类型约束几乎总是无用的。约束需要这些约束的函数
您发现的问题是由于类型的类型:种类。我们使用
*
编写种类,GHCi中的:kind
命令可以帮助:
λ> :kind Int
Int :: *
λ> :kind Char
Char :: *
λ> :kind Maybe Int
Maybe Int :: *
所有的函子
都有一个类型参数,所以它们看起来都是这样的:
λ> :kind Maybe
Maybe :: * -> *
λ> :kind IO
IO :: * -> *
RGB
属于*->*
类型,但是当您编写RGB a
时,您将a::*
应用于它,它将变成RGB a:::*
,这对编译器来说没有意义
现在,这对您来说应该是有意义的:
The first argument of ‘Functor’ should have kind ‘* > *’,
but ‘Rgb a’ has kind ‘*’
以前尝试实现functor实例时失败的原因是数据类型上的以下约束:
-- Do not do this. This is poor Haskell.
data Rgb a = (Num a, Show a) => Rgb a a a
你应该写:
data Rgb a = Rgb a a a
然后在每个实例上添加约束:
instance (Show a) => Show (RGB a) where
...
instance (Num a) => Num (RGB a) where
...
然后你的函子实例就可以了。你在GHCi中试过你的第一个建议吗?我也尝试删除类型参数,但编译器仍然拒绝接受更改(老实说,我在发布问题之前也尝试过):(@gsscoder这是因为您将数据类型中的类型约束为
Num
和Show
。这是一件坏事:您使用的约束不正确。可能会解释原因,但现在,请删除数据声明中的约束。我会将此添加到答案中。是的,现在我知道,删除约束是可行的;但我认为DeriveFunctor
是一个更简单的路径。@gsscoder当然可以,但我建议使用类型类,至少作为将来的练习。这真的是一个数据类型上下文吗?这个位置看起来更像是一个存在的位置。数据类型上下文不在左边吗?
instance (Show a) => Show (RGB a) where
...
instance (Num a) => Num (RGB a) where
...