Question

J'ai donc une paire de classes que je vais beaucoup utiliser ensemble et je veux éviter de spécifier les deux à chaque fois. Fondamentalement, au lieu de mettre

:: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) =>

au début de toutes mes spécifications de type, je préfère mettre

:: (OrdFractional a, OrdFractional b, ... OrdFractional z)

Donc, mon idée de départ était simplement de déclarer une nouvelle classe

module Example where

class (Fractional a, Ord a) => OrdFractional a

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)

Mais cela n'a pas fonctionné aussi automatiquement que je l'aurais souhaité:

% ghci
Prelude> :l Example.hs
Ok, modules loaded: Example.
Prelude Example> example (1::Float,3::Float) (2,2) (3,1)

<interactive>:1:0:
    No instance for (OrdFractional Float)
      arising from a use of `example' at <interactive>:1:0-39
    Possible fix:
      add an instance declaration for (OrdFractional Float)
    In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
    In the definition of `it':
        it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1)

La création manuelle d'instances ressemble à un glisser-déposer. Ensuite, j'ai pensé pouvoir essayer de créer automatiquement des instances:

module Example where

class OrdFractional a
instance (Fractional a, Ord a) => OrdFractional a

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)

Mais le compilateur n'a pas aimé ça:

ghc -c Example.hs

Example.hs:4:0:
    Illegal instance declaration for `OrdFractional a'
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are type *variables*,
         and each type variable appears at most once in the instance head.
         Use -XFlexibleInstances if you want to disable this.)
    In the instance declaration for `OrdFractional a'

Y a-t-il un moyen de faire cela?

Était-ce utile?

La solution

Avec l'extension ConstraintKinds introduite dans GHC 7.4, les contraintes sont maintenant du type Constraint . Vous pouvez donc utiliser des synonymes de types ordinaires pour obtenir ce que vous voulez:

{-# LANGUAGE ConstraintKinds #-}

type OrdFractional a = (Ord a, Fractional a)

Autres conseils

Ce que vous voulez, c'est un alias de classe. Il existe une proposition pour l'ajouter à Haskell à l'adresse http://repetae.net/recent/out/classalias. .html

Lorsque le compilateur dit " Utilisez -XFlexibleInstances ", vous devriez essayer d'ajouter

.
{-# LANGUAGE FlexibleInstances #-}

en haut de votre source (et lisez la documentation pour savoir ce qu’elle fait, bien sûr!).

Dans ce cas précis, votre code fonctionnera correctement:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

Des instances flexibles sont nécessaires pour activer le contexte = > sur l'en-tête de l'instance. Des instances indécidables sont requises car le compilateur traite un contexte OrdFractional a . , peut terminer l’ajout de a fractionné et de Ord a au contexte - ce qui n’aide pas directement à déterminer a , et sous des conditions horribles circonstances, les vérifications de type peuvent diverger; le compilateur n'aime vraiment pas ça. (Vous ne voudriez probablement pas que le compilateur continue indéfiniment ou qu'il manque de mémoire, soit.)

Non.

Votre solution d'une super-classe impliquant les autres classes est la solution la plus proche de ce que vous souhaitez, ce qui est possible dans Haskell. Même si cela nécessite des instances manuelles de cette nouvelle classe, elle est parfois utilisée, par exemple dans la réécriture . bibliothèque.

Comme CesarB l’a mentionné, les alias de classe font ce que vous voulez (et plus encore), mais ce n’est qu’une proposition qui existe depuis des années et qui n’a jamais été mise en œuvre, probablement parce qu’elle pose de nombreux problèmes. Au lieu de cela, diverses autres propositions sont apparues, mais aucune d’elles n’a été mise en œuvre non plus. (Pour obtenir la liste de ces propositions, consultez cette page Haskellwiki .) L'un des projets sur Hac5 consistait à modifier le GHC afin d'inclure un petit sous-ensemble d'alias de classe appelés synonymes de contexte ( faites exactement ce que vous demandez ici et rien d’autre), mais malheureusement, cela n’a jamais été fini.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top