2016-01-05 3 views
0

Когда я пытаюсь это:Есть ли способ избежать UndecidableInstances в этом примере?

import GHC.Generics (Generic) 
import Control.DeepSeq (NFData(..)) 
import Data.Vector.Generic (Vector) 

data Entry a = Entry !Bool a 
      deriving (Generic, NFData) 

-- The variable @[email protected] is meant to be instantiated with a 'Vector' 
-- type. Most operations for the type have a @Vector v (Entry a)@ 
-- constraint. 
newtype DenseIntMap v a = DenseIntMap (v (Entry a)) 

instance NFData (v (Entry a)) => NFData (DenseIntMap v a) where 
    rnf (DenseIntMap va) = rnf va 

... Я получаю эту ошибку:

/Users/casillas/GitHub/tau-sigma/src/TauSigma/Util/DenseIntMap.hs:53:10: 
    Constraint is no smaller than the instance head 
     in the constraint: Vector v (Entry a) 
    (Use UndecidableInstances to permit this) 
    In the instance declaration for ‘NFData (DenseIntMap v a)’ 

/Users/casillas/GitHub/tau-sigma/src/TauSigma/Util/DenseIntMap.hs:53:10: 
    Constraint is no smaller than the instance head 
     in the constraint: NFData (v (Entry a)) 
    (Use UndecidableInstances to permit this) 
    In the instance declaration for ‘NFData (DenseIntMap v a)’ 

Использование UndecidableInstances действительно делает его уйти, но я осторожны с использованием этого расширения. Есть ли другой способ заставить вещи работать в этом случае? (Не меняя типы слишком много, желательно.)

+0

Почему вы хотите, чтобы ограничение 'Vector'? Кажется, у нее нет никакой цели. – dfeuer

+0

@dfeuer: О, да, ты прав. Однако, когда я удаляю его, я все равно получаю ошибку 'NFData v (Entry a)', если я не использую расширение. Я отредактирую вопрос. –

+0

Кроме того, почему вы опасаетесь 'UndecidableInstances'? У Haskell есть очень жалкое оправдание для проверки окончания. – dfeuer

ответ

5

Предупреждение: Я не тестировал этот код.

Подход, который кажется чистым для меня следовать Prelude.Extras -style путь:

class NFData1 f where 
    rnf1 :: NFData a => f a ->() 

Теперь вы можете писать для каждого векторного типа, что-то вроде

instance NFData1 V where 
    rnf1 = rnf 

А потом

instance (NFData1 v, NFData a) => NFData (DenseIntMap v a) where ... 

Альтернативный подход, который лучше всего подходит вашему текущему коду, - это думать о v как Vector явно. Вместо того, чтобы беспокоиться о том, как v a предпочел бы, чтобы заставить себя, таран собственное понятие вниз ее горло путем складывания: что-то вроде

instance (Vector v a, NFData a) => NFData (DenseIntMap v a) where 
    rnf = V.foldl' (\() e -> rnf e)() 

Этот второй подход, как представляется, скорее всего, плохо играть с вектором слияния, если вы не будете осторожны о том, какие векторы вы хотите силой слева направо и которые справа налево.

Смежные вопросы