2012-02-28 1 views
5

Les suivants contrôles de type de programme si je précise sur la ligne de commande (par exemple ghci file.hs):ghci - compilation impatiente en mode interactif?

import Data.Ratio 
foo = let x = [1..] 
      y = (1%2) + (head x) 
     in y 

Cependant, si je saisis de manière interactive, je vais une erreur de type:

Prelude> import Data.Ratio 
Prelude Data.Ratio> let x = [1..] 
Prelude Data.Ratio> let y = (1%2) + (head x) 
<interactive>:1:23: 
    Couldn't match expected type `Ratio a0' with actual type `Integer' 

Il semble que x est avidement typé comme [Integer] par opposition au plus général (Num t, Enum t) => [t].

Y at-il quelque chose que je peux faire à ce sujet? Existe-t-il d'autres situations dans lesquelles le mode interactif diffère du mode par lots?

+1

restriction de monomorphisme ... – augustss

+1

et tapez défaut – Ptival

+3

, il est en effet la restriction de monomorphisme redoutée. Il y a deux façons de le contourner: donner une signature explicite ou désactiver cette restriction (dans GHCi, vous pouvez faire ': set -XNoMonomorphismRestriction' et vous avez terminé, les pragmas de langage et les drapeaux de compilation fonctionnent aussi). – Vitus

Répondre

10

Manchettes sans arguments, à savoir ceux de la forme x = ... sont soumis à le monomorphism restriction, ce qui signifie que GHC essaiera de le rendre non polymorphe en utilisant les informations de type disponibles, et de se rabattre sur type defaulting pour résoudre iguities. (En fait, GHCi utilise a slightly more permissive set of defaulting rules, mais cela n'a pas vraiment d'importance pour cette question).

Depuis là quand vous écrivez let x = [1..] aucune autre information de type est disponible, par défaut de type cause du type à déduire que [Integer], puisque Integer est le type numérique par défaut.

Il existe plusieurs façons de résoudre ce problème:

  1. Utilisez une signature de type. Cela fonctionne toujours, mais cela peut parfois être fastidieux lorsque vous travaillez avec des types complexes.

    > let x = [1..] :: [Rational] 
    
  2. Ecrivez la liaison avec des arguments. Cela ne s'applique pas dans votre cas, mais vous voyez parfois ce problème lors de l'écriture de définitions de fonctions sans point.

    > let f = (+) 
    > :t f 
    f :: Integer -> Integer -> Integer 
    > let f x y = x + y 
    > :t f 
    f :: Num a => a -> a -> a 
    
  3. Donnez le type vérificateur plus d'informations. Dans votre cas, nous pourrions éviter le problème en écrivant les deux liaisons dans une instruction let. GHC peut ensuite utiliser les informations de type de la deuxième liaison pour déduire correctement que x doit avoir le type [Rational].

    > let x = [1..]; y = 1%2 + head x 
    > :t x 
    x :: [Ratio Integer] 
    
  4. Désactiver la restriction de monomorphisme. Cela peut avoir de sérieuses implications sur les performances si vous vous attendiez à ce que le type de quelque chose soit par ex. un Integer, alors qu'il s'agit en fait d'un Num a => a, puisque ce dernier doit être recalculé chaque fois que le premier peut être partagé. C'est la principale raison pour laquelle la restriction existe en premier lieu.

    Cependant, dans l'interpréteur, cela pose généralement moins de problèmes, donc la commodité en vaut souvent la peine.

    > :set -XNoMonomorphismRestriction 
    > let x = [1..] 
    > :t x 
    x :: (Num t, Enum t) => [t] 
    

    Si vous voulez que cela par défaut, vous pouvez l'ajouter à votre .ghci file.

4

Vous peut faire quelque chose à ce sujet en définissant x être les suivants:

let x = [1..] :: [Ratio Int] 

comme dans:

Data.Ratio Prelude> let x = [1..] :: [Ratio Int] 
Data.Ratio Prelude> let y = (1%2) + (head x) 
Data.Ratio Prelude> y 
3 % 2 
Data.Ratio Prelude> 
+1

Je déconseille fortement d'utiliser 'Ratio Int', sauf si vous savez absolument que votre calcul ne peut pas déborder et que vous êtes désespéré pour la performance - et même alors je ne l'aime pas. À mon avis, c'était une mauvaise erreur de faire de 'Ratio' un type polymorphe, même de petits calculs peuvent facilement dépasser 64 bits, et ensuite vous obtenez un non-sens complet. –