Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 实现参数化类型的函子_Haskell_Functional Programming_Functor - Fatal编程技术网

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
    ...