数据实例中的上下文 [英] Context in data instances

查看:124
本文介绍了数据实例中的上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数据类型,只有在它的参数可以被排序时才有意义,但是我似乎需要深入研究一些复杂的,可能有点冒险的东西来让它起作用(主要是GADT)。
我在做什么(受限的数据类型)被认为是不好的haskell练习,有没有办法解决这个问题?

I have a datatype which only makes sense if its arguments can be ordered, however I seem to be needing to get deep into some complex and potentially hacky stuff to get it to work (GADTs, mainly). Is what I'm doing (constrained datatypes) considered bad haskell practice, and is there any way around this?

对于那些感兴趣的人,这里是相关的代码:

For those interested, here's the relevant code:

{-# 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]

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

At first I thought I'd just put a context in the Functor instance (it's the only instance I'm struggling with) but it seems I can't (no mention of the contained type), and even if I could I'd still need the constraint on fmap that its return type be orderable.

事实上,我收到以下编译错误,看起来是因为我过分限制了Functor实例:

As it is, I'm getting the following compile error, which it seems is because I'm overly constraining the Functor instance:

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’


推荐答案

您不能使用标准的 Functor 类来完成这项工作,因为它的 fmap 必须在 all 数据类型,不受限制。

You can't do this using the standard Functor class, since its fmap must work on all data types, without constraints.

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

You could work with a different class. One option is to use an "fine-grained functor" class which lets you use a separate instance for each pairs of types a b. (Probably this already has some standard name, but I can't remember)

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 类。

Alternatively, one can parametrize the Functor class with a constraint:

{-# 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]

这篇关于数据实例中的上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆