2017-03-17 24 views
0

私は、その引数が順序付けられていれば意味をなさないデータ型を持っていますが、それを動作させるには複雑で潜在的にハッキリなものに深く関わる必要があるようです(主にGADT)。 私がやっていることは(制約付きのデータ型)悪いハズケルの習慣とみなされていますか?これを回避する方法はありますか?興味のある方のためデータインスタンス内のコンテキスト

は、ここに関連するコードです:

{-# 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の制約が必要と思いますが、戻り値の型は注文可能です。

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

ファンクタは、すべてのタイプには適用されませんでなければならない:1は制約にFunctorクラスをパラメータすることができ、また

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] 

を(おそらくこれは、すでにいくつかの標準的な名前を持っているが、私は覚えていないことができます) 'Ord'によって制約されたものだけです。あなたのインスタンスでもそれをさらに制限することはできません。これは、バランスの取れた木のような構造物が、ファンクターのいずれにもなり得ない理由です。 – bheklilr

+3

あなたはそれをファンクタにすることはできません。その周りの通常の方法は、単に 'Data.Set'と' Data.Map'で行われるように、別々の "マップ"関数を実装することです。 – Cubic

答えて

1

あなたは標準Functorクラスを使用してこれを行うことはできません、私は過度のFunctorインスタンスを制約していますので、それがあるとして

、私は以下のコンパイルエラーを取得しています、それはそうされていますfmapは、制約なしですべてデータ型で動作する必要があるためです。

あなたは別のクラスで作業することができます。 1つのオプションは、 "fine-grained functor"クラスを使用して、タイプの各ペアに対して別々のインスタンスを使用できるようにすることです。a b

{-# 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/docs/Data-Functor-Indexed.html)?私は彼らが私が見ていない何らかの形で類似の概念を表しているのかどうか、まったく違うのかどうかは分かりません。 –

+1

@ZoeyHewll私は用語を使いこなしているようです:上記のものは索引付きのファンクタ 'f i j a'ではなく、他のものです。私はその固有の名前を覚えていないが、これがどこかに見つからなければ私は驚くだろう。私は混乱を起こさないように用語を編集します。ありがとう。 – chi

+0

CFunctorの場合、「範囲外です:コンストラクタまたはクラス 'Constraint'」を入力してください。 –

関連する問題