2012-05-23 14 views
7

Il seguente codice è destinato a produrre un doppio o un intero. s è assunto come negate o id; n l'intera parte; e f la parte frazionaria o Nothing per un numero intero.Perdita di polimorfismo dopo la corrispondenza del modello

computeValue :: Num a => (a->a) -> Integer -> (Maybe Double) -> Either Double Integer 
computeValue s n Nothing = Right $ s n 
computeValue s n (Just a) = Left $ s (fromIntegral n + a) 

quando compilo questo ottengo:

test1.hs:2:28: 
    Couldn't match type `Integer' with `Double' 
    Expected type: Either Double Integer 
     Actual type: Either Double a 
    In the expression: Right $ s n 
    In an equation for `computeValue': 
     computeValue s n Nothing = Right $ s n 

test1.hs:2:38: 
    Couldn't match type `Integer' with `Double' 
    In the first argument of `s', namely `n' 
    In the second argument of `($)', namely `s n' 
    In the expression: Right $ s n 

Sembra pista in qualche modo il compilatore ha perso il fatto che s è polimorfico. Cosa è successo qui e come lo risolvo?

risposta

10

s non è polimorfica dall'interno della funzione: è possibile utilizzare qualsiasi funzione che funziona su alcuni Num esempio come questo parametro, potrebbe essere una funzione che funziona solo su Complex! Quello che ti serve è una funzione universalmente quantificata s, ad esempio una che può essere effettivamente chiamata con qualsiasi istanzaNum.

{-# LANGUAGE Rank2Types #-} 

computeValue :: (forall a . Num a => a->a) -> Integer -> Maybe Double -> Either Double Integer 
computeValue s n Nothing = Right $ s n 
computeValue s n (Just a) = Left $ s (fromIntegral n + a) 

che funziona quindi:

Prelude Data.Either> computeValue id 3 Nothing 
Right 3 
Prelude Data.Either> computeValue negate 57 (Just pi) 
Left (-60.1415926535898) 
+0

Interessante! Avevo trovato ciò che non andava (voleva davvero un "o a a") come ritorno, ma non mi rendevo conto che c'era un modo per aggirarlo. –

+6

@leftaroundabout: In realtà hai bisogno di _universally_ quantificato 's' e questo è ciò che fa la firma di rank 2. 'ExistentialQuantification' non fa nulla in questo esempio, l'estensione importante è solo' Rank2Types'. – Vitus

+0

@Vitus: ah, giusto! Continuo a mischiarlo, ma questo ha molto più senso, pensandoci. Modificato. – leftaroundabout

Problemi correlati