2017-03-17 33 views
0

我有一个数据类型,只有在它的参数可以排序时才有意义,但是我似乎需要深入研究一些复杂并且可能有害的东西才能使其工作(主要是GADT)。 是我在做什么(受限数据类型)认为不好的haskell练习,有没有解决这个问题的方法?数据实例中的上下文

对于那些有兴趣,这里的相关代码:

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE InstanceSigs #-} 
import Data.List (sort) 

data OrdTriple a where 
    OrdTriple :: (Ord a) => a -> a -> a -> OrdTriple a 

instance Functor OrdTriple where 
    fmap :: (Ord a, Ord b) => (a -> b) -> OrdTriple a -> OrdTriple b 
    fmap f (OrdTriple n d x) = OrdTriple n' d' x' 
     where 
      [n', d', x'] = sort [f n, f d, f x] 

起初,我以为我只是把上下文的函子实例(这是我与挣扎的唯一实例),但似乎我不能(没有提及包含的类型),即使我可以仍然需要约束fmap它的返回类型是可订购的。

正因为如此,我得到以下编译错误,这似乎是因为我过于约束函子实例:

No instance for (Ord a) 
Possible fix: 
    add (Ord a) to the context of 
    the type signature for 
     fmap :: (a -> b) -> OrdTriple a -> OrdTriple b 
When checking that: 
    forall a b. 
    (Ord a, Ord b) => 
    (a -> b) -> OrdTriple a -> OrdTriple b 
    is more polymorphic than: 
    forall a b. (a -> b) -> OrdTriple a -> OrdTriple b 
When checking that instance signature for ‘fmap’ 
    is more general than its signature in the class 
    Instance sig: forall a b. 
       (Ord a, Ord b) => 
       (a -> b) -> OrdTriple a -> OrdTriple b 
    Class sig: forall a b. (a -> b) -> OrdTriple a -> OrdTriple b 
In the instance declaration for ‘Functor OrdTriple’ 
+3

函子必须适用于所有类型的,不只有那些受'Ord'限制的。即使在你的实例中,你也不能进一步限制它。这就是为什么像平衡树木这样的结构也不能成为仿函数的原因。 – bheklilr

+3

你不能让它成为函子。通常的解决方法就是简单地实现一个单独的“map”函数,就像Data.Set和Data.Map一样。 – Cubic

回答

1

使用标准Functor类你不能做到这一点,因为它的fmap必须工作在全部数据类型,没有限制。

你可以使用不同的类。一种选择是使用“细粒度仿函子”类,它允许您为每对类型a b使用单独的实例。 (这大概已经有一些标准的名称,但我不记得了)

class FgFunctor f a b where 
    fgmap :: (a->b) -> f a -> f b 

-- regular functors are also fine-grained ones, e.g. 
instance FgFunctor [] a b where 
    fgmap = fmap 

instance (Ord a, Ord b) => FgFunctor OrdTriple a b where 
    fgmap f (OrdTriple n d x) = OrdTriple n' d' x' 
     where [n', d', x'] = sort [f n, f d, f x] 

另外,可以参数化的Functor类与约束:

{-# LANGUAGE GADTs, KindSignatures, MultiParamTypeClasses, 
    ConstraintKinds, TypeFamilies, FlexibleInstances #-} 
{-# OPTIONS -Wall #-} 
module CFunctor where 

import Data.List (sort) 
import Data.Kind (Constraint) 

data OrdTriple a where 
    OrdTriple :: (Ord a) => a -> a -> a -> OrdTriple a 

class CFunctor (f :: * -> *) where 
    type C f a :: Constraint 
    cmap :: (C f a, C f b) => (a -> b) -> f a -> f b 

-- regular functors are also constrained ones, e.g. 
instance CFunctor [] where 
    type C [] a = a ~ a 
    cmap = fmap 

instance CFunctor OrdTriple where 
    type C OrdTriple a = Ord a 
    cmap f (OrdTriple n d x) = OrdTriple n' d' x' 
     where [n', d', x'] = sort [f n, f d, f x] 
+0

您的IxFunctor与[this](http://stackoverflow.com/a/27771772/6112457)或(略有不同)[this](https://hackage.haskell.org/package/indexed-0.1)相关。 3 /文档/数据函子-Indexed.html)?我无法分辨他们是否以某种我没有看到的方式表示类似的概念,或者它们是否完全不同。 –

+1

@ZoeyHewll看来我搞砸了术语:上面的一个不是一个索引函子'f i j a',而是别的东西。我不记得它的专有名称,但如果在某个地方找不到它,我会感到惊讶。我会修改术语,以免造成混淆。谢谢。 – chi

+0

对于CFunctor,我得到'不在范围内:类型构造函数或类'约束'# –

相关问题