2012-04-29 20 views
5

Non capisco il motivo per cui la seguente funzione funziona:confusione con il tipo di Haskell inferenza

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > fromIntegral n 

ma la segue non:

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

che genera l'errore

Could not deduce (n ~ Int) 
    from the context (Integral n) 
     bound by the type signature for 
       isLongerThanN' :: Integral n => n -> [a] -> Bool 
     at blah.hs:140:1-35 
     `n' is a rigid type variable bound by 
      the type signature for 
      isLongerThanN' :: Integral n => n -> [a] -> Bool 
      at blah.hs:140:1 
    In the second argument of `(>)', namely `n' 
    In the expression: length xs > n 
    In an equation for `isLongerThanN'': 
     isLongerThanN' n xs = length xs > n 

(che probabilmente ho frainteso)

Semmai, mi aspetterei che sia il contrario, dal momento che da Integrale sta effettivamente allargando il tipo della variabile n.

+8

Non scrivere 'se foo allora Vero altro false'. È lo stesso di "pippo". – hammar

+1

hai ragione, grazie; L'ho modificato, ma non è questa la domanda – Inept

+4

Ecco perché non l'ha postata come risposta ... – Jasper

risposta

12

consideri l'espressione che non funziona

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

n può essere qualsiasi tipo integer-y, in modo che possa essere trasmesso un Integer o Word o Int. (>) ha il tipo Ord a => a -> a -> Bool quindi entrambi gli operandi sinistro e destro devono essere dello stesso tipo. length xs restituisce un Int quindi questo tipo deve essere quello. Ma, n può essere qualsiasi Integral, non necessariamente Int, quindi abbiamo bisogno di un modo per consentire n da convertire in un Int. Questo è ciò che fa fromIntegral (il fatto che consenta anche che n sia qualsiasi Num è praticamente irrilevante).

Potremmo ampliare la versione di lavoro a guardare come:

toInt :: Integral n => n -> Int 
toInt = fromIntegral 

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > toInt n 

che rende più chiaro che stiamo usando una versione specializzata di fromIntegral.

(Si noti che isLongerThanN n xs = fromIntegral (length xs) > n funziona anche, perché permette il risultato di length da combaciare con il tipo di n.)

+2

Tuttavia, si noti che la scelta di quale si converte può influenzare il risultato; con l'ultimo esempio 'isLongerThanN (0 :: Word8) [1..256] == False' a causa di overflow. – hammar

+0

Oh ok, ho capito. Molte grazie. Perché la versione non funzionante non funziona non era il problema per me, ma stavo leggendo il tipo signature daIntegral :: (Num b, Integral a) => a -> b erroneamente. – Inept