4

次のクラスがあるとします。

class ListIsomorphic l where
    toList   :: l a -> [a]
    fromList :: [a] -> l a

を使用してベクトル型のインスタンスを作成するにはどうすればよいData.Vector.Genericですか? これは機能しません:

instance (V.Vector v a) => ListIsomorphic v where
    toList   = V.toList
    fromList = V.fromList

私に与える:

test.hs:31:10:
    Variable ‘a’ occurs more often than in the instance head
      in the constraint: V.Vector v a
    (Use UndecidableInstances to permit this)
    In the instance declaration for ‘ListIsomorphic v’
4

2 に答える 2

6

しないでくださいvすべてのインスタンスをクラスに追加すると、インスタンスListableが重複するため、使用するのが面倒になります。

AVector v a => vは、どの項目がリストの要素になり得るかによって制約されるため、リストと同型ではありません。この制約をキャプチャするクラスが必要です。

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}

import Data.Constraint

class ConstrainedList l where
    type Elem l a :: Constraint
    toList   :: Elem l a => l a -> [a]
    fromList :: Elem l a => [a] -> l a

ConstrainedListすべてのタイプのインスタンスを追加Vector v a => vしてインスタンスの領域が重複するのではなく、関心のあるタイプに対してのみ定義します。以下Vectorでは、ベクター パッケージ内のインスタンスを持つすべてのタイプをカバーします。

import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Generic as VG

instance ConstrainedList VP.Vector where
    type Elem VP.Vector a = VG.Vector VP.Vector a
    toList   = VG.toList
    fromList = VG.fromList

他のタイプのインスタンス

要素に空の制約のみを必要とするConstrainedList通常のリストのインスタンスを作成できます。[]

instance ConstrainedList [] where
    type Elem [] a = ()
    toList   = id
    fromList = id

インスタンスを使用するtoList、またはインスタンスfromListも必要とする場所Elem l a

cmap :: (ConstrainedList l, Elem l a, Elem l b) => (a -> b) -> l a -> l b
cmap f = fromList . map f . toList

リストと要素の具体的な型がわかっている場合、これらの関数は、制約をいじることなく簡単に使用できます。

cmap (+1) [1,2,3,4]

ヒア・ビー・ドラゴンズ

次のことは試さないでください。追加の制約なしでリストに同型であるもののクラスに興味がある場合は、別のクラスを作成してください。これは、窮地に立たされたときにできること、つまりドラゴンを召喚することを示しています。

の要素に制約がないことの証明を必要とする関数を作成することもできますConstrainedList。これはconstraints、GHC で実際にはサポートされていないパッケージとプログラミング スタイルの領域からはずれていますが、十分なconstraints例がないため、ここでは省略します。

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}

map' :: forall l a b. (ConstrainedList l, () :=> Elem l a, () :=> Elem l b) =>
                      (a -> b) -> l a -> l b
map' f = case (ins :: () :- Elem l a) of { Sub Dict ->
         case (ins :: () :- Elem l b) of { Sub Dict ->
         fromList . map f . toList
         }}

を確認するConstrainedListだけで a に制約がないことを確認できElem l a ~ ()ますが、その制約が別の方法で記述されている場合は機能しません。

{-# LANGUAGE FlexibleInstances #-}

class Any a
instance Any a

data AList a = AList {getList :: [a]}
    deriving (Show)

instance ConstrainedList AList where
    type Elem AList a = Any a
    toList   = getList
    fromList = AList

()と同じタイプではありませんがAny a、を()意味しAny aます。制約パッケージは、型クラスに具体化することで、このような関係をキャプチャしClass:=>

{-# LANGUAGE MultiParamTypeClasses #-}

--       class () => Any a
instance Class ()   (Any a) where
    cls = Sub Dict

-- instance ()  => Any a
instance    () :=> Any a where
    ins = Sub Dict

そのすべての作業により、具体的なリスト型がわかっている場合、それらの辞書をすべて提供しなくても、関数を簡単に再利用できます。

map'' :: (a -> b) -> AList a -> AList b
map'' = map'
于 2015-08-20T23:12:53.367 に答える