2017-07-20 3 views
0

J'essaie de créer un wrapper newtype pour le type Linear.V et dériver des instances utiles. Je tentais ceci:Une erreur typecheck dans la dérivation wrapper pour Linear.V

{-# LANGUAGE DataKinds, PolyKinds, ScopedTypeVariables, 
StandaloneDeriving, FlexibleContexts, UndecidableInstances, 
GeneralizedNewtypeDeriving, PartialTypeSignatures, TypeFamilies #-} 

import Linear.V 
import Control.Lens.At 

data Foo = Foo1 | Foo2 deriving (Show, Eq) 

Tentative 1 - Je pense GeneralizedNewtypeDeriving ferait, mais Nope:

newtype Bar n = Bar { 
    getBar :: V n Foo 
} deriving (Show, Eq, Ixed) 

Je reçois cette erreur:

• Couldn't match representation of type ‘f (V n Foo)’ 
           with that of ‘f (Bar n)’ 
     arising from the coercion of the method ‘ix’ 
      from type ‘Index (V n Foo) 
        -> Control.Lens.Type.Traversal' (V n Foo) (IxValue (V n Foo))’ 
      to type ‘Index (Bar n) 
        -> Control.Lens.Type.Traversal' (Bar n) (IxValue (Bar n))’ 
     NB: We cannot know what roles the parameters to ‘f’ have; 
     we must assume that the role is nominal 
    • When deriving the instance for (Ixed (Bar n)) 

J'ai fait essayer 2 en utilisant autonome dérivant comme ceci:

newtype Bar n = Bar { 
    getBar :: V n Foo 
} deriving (Show, Eq) 
type instance Index (Bar n) = Int 
type instance IxValue (Bar n) = Foo 

deriving instance Ixed (V n Foo) => Ixed (Bar n) 

Mais j'ai eu une autre erreur:

• Couldn't match representation of type ‘f1 (V n Foo)’ 
          with that of ‘f1 (Bar n)’ 
    arising from a use of ‘GHC.Prim.coerce’ 
    NB: We cannot know what roles the parameters to ‘f1’ have; 
    we must assume that the role is nominal 
• In the expression: 
    GHC.Prim.coerce 
     @(Index (V n Foo) 
     -> Control.Lens.Type.Traversal' (V n Foo) (IxValue (V n Foo))) 
     @(Index (Bar n) 
     -> Control.Lens.Type.Traversal' (Bar n) (IxValue (Bar n))) 
     ix 
    In an equation for ‘ix’: 
     ix 
     = GHC.Prim.coerce 
      @(Index (V n Foo) 
       -> Control.Lens.Type.Traversal' (V n Foo) (IxValue (V n Foo))) 
      @(Index (Bar n) 
       -> Control.Lens.Type.Traversal' (Bar n) (IxValue (Bar n))) 
      ix 
    When typechecking the code for ‘ix’ 
    in a derived instance for ‘Ixed (Bar n)’: 
    To see the code I am typechecking, use -ddump-deriv 
    In the instance declaration for ‘Ixed (Bar n)’ 
• Relevant bindings include 
    ix :: Index (Bar n) 
      -> Control.Lens.Type.Traversal' (Bar n) (IxValue (Bar n)) 
     (bound at a.hs:12:1) 

Je ne suis pas sûr pourquoi l'une des erreurs qui se passe réellement. Cela pourrait-il être fait d'une manière ou d'une autre? Je ne suis pas si expérimenté avec les fonctionnalités avancées de niveau de type et jusqu'à présent, je ne pouvais pas écrire cette définition d'instance en particulier, donc je considérerais cela comme une solution. Mais je préférerais utiliser le mécanisme deriving d'une façon ou d'une autre, puisqu'il semble plus réutilisable.

EDIT: Je l'ai essayé exemple manuel decalaration:

type instance Index (Bar n) = Int 
type instance IxValue (Bar n) = Foo 

instance Ixed (Bar n) where 
    ix i f (Bar v) = ix i f v 

Mais qui donnent l'erreur suivante:

• Couldn't match type ‘V n Foo’ with ‘Bar n’ 
    Expected type: f (Bar n) 
    Actual type: f (V n Foo) 
• In the expression: ix i f v 
    In an equation for ‘ix’: ix i f (Bar v) = ix i f v 
    In the instance declaration for ‘Ixed (Bar n)’ 
• Relevant bindings include 
    v :: V n Foo (bound at a.hs:14:15) 
    f :: IxValue (Bar n) -> f (IxValue (Bar n)) (bound at a.hs:14:8) 
    i :: Index (Bar n) (bound at a.hs:14:6) 
    ix :: Index (Bar n) 
      -> Control.Lens.Type.Traversal' (Bar n) (IxValue (Bar n)) 
     (bound at a.hs:14:3) 

Ce qui me semble comme que le compilateur ne peut pas comprendre que la Index des deux V n Foo et Bar n est Int. Mais je ne suis pas sûr de ça.

Répondre

1

Vous y êtes presque. Le problème restant est la ixpour le V n Foo sous-jacent, qui retourne finalement une fonction V n Foo -> f (V n Foo), dans une traversée ix pour le type de wrapper Bar n, qui devrait finalement retourner une fonction Bar n -> f (Bar n). Nous devons "déballer" la définition de Traversal' pour le savoir.

Dans votre code, ix i f v est de type f (V n Foo), donc il suffit de fmap avec le constructeur Bar:

type instance Index (Bar n) = Int 
type instance IxValue (Bar n) = Foo 

instance Ixed (Bar n) where 
    ix i f (Bar v) = fmap Bar (ix i f v) 
+0

Merci, cela est solution acceptable pour moi. Je suppose qu'il a zéro frais généraux d'exécution, non? Y a-t-il encore un espoir de le faire en utilisant le mécanisme de «dérivation»? – user1747134

+0

@ user1747134 C'est un nouveau type, donc je suppose que ça n'aura pas d'overhead. Je ne pense pas qu'il existe un moyen d'utiliser 'deriving'. – danidiaz