2016-11-21 1 views
6

J'essaie de créer un type qui garantit qu'une chaîne contient moins de N caractères.Impossible de faire correspondre le type '*' avec 'Nat'

{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE ScopedTypeVariables #-} 
{-# LANGUAGE DataKinds #-} 

import GHC.TypeLits (Symbol, Nat, KnownNat, natVal, KnownSymbol, symbolVal) 
import Data.Text (Text) 
import qualified Data.Text as Text 
import Data.Proxy (Proxy(..)) 

data TextMax (n :: Nat) = TextMax Text 
    deriving (Show) 

textMax :: KnownNat n => Text -> Maybe (TextMax n) 
textMax t 
    | Text.length t <= (fromIntegral $ natVal (Proxy :: Proxy n)) = Just (TextMax t) 
    | otherwise = Nothing 

Cela donne à l'erreur:

src/Simple/Reporting/Metro2/TextMax.hs:18:50: error: 
• Couldn't match kind ‘*’ with ‘Nat’ 
    When matching the kind of ‘Proxy’ 
• In the first argument of ‘natVal’, namely ‘(Proxy :: Proxy n)’ 
    In the second argument of ‘($)’, namely ‘natVal (Proxy :: Proxy n)’ 
    In the second argument of ‘(<=)’, namely 
    ‘(fromIntegral $ natVal (Proxy :: Proxy n))’ 

Je ne comprends pas cette erreur. Pourquoi ça ne marche pas? I've used almost this exact same code to get the natVal of n in other places and it works.

Y a-t-il une meilleure façon de procéder?

+1

remarque de côté: en tournant le ' L'extension de PolyKinds, ghc est plus clémente avec l'idée d'un 'Proxy' poly-kinded et le message d'erreur devient différent et rend beaucoup plus clair que c'est un problème typique 'ScopedTypeVariables'. – gallais

Répondre

7

Vous avez besoin d'un forall explicite dans la signature de textMax, de sorte que ScopedTypeVariables coups de pied et l'n dans l'annotation Proxy n devient la même n dans la contrainte KnownNat n:

textMax :: forall n. KnownNat n => Text -> Maybe (TextMax n) 
textMax t 
    | Text.length t <= (fromIntegral $ natVal (Proxy :: Proxy n)) = Just (TextMax t) 
    | otherwise = Nothing