2012-05-23 12 views
7

El siguiente código está destinado a producir un doble o un entero. s se supone que es negate o id; n la parte entera; y f la parte fraccionaria o Nothing para un número entero.Pérdida de polimorfismo después de coincidencia de patrón

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) 

cuando compilo este me sale:

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 

Parece que la pista de algún modo el compilador ha perdido el hecho de que s es polimórfica. ¿Qué pasó aquí y cómo lo soluciono?

Respuesta

10

s no es polimórfica desde el interior de su función: se puede utilizar cualquier función que funciona en algunos Num ejemplo como este parámetro, puede ser que sea una función que sólo funciona en Complex! Lo que necesita es una función universalmente cuantificada s, es decir, una que se pueda llamar realmente con cualquierNum instancia.

{-# 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) 

que funciona a continuación:

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

Interesante! Había encontrado lo que estaba mal (realmente quería un 'O bien a a') como devolución, pero no me di cuenta de que había una forma de evitarlo. –

+6

@leftaroundabout: De hecho, necesitas'universal_ cuantificado 's' y eso es lo que hace la firma de rango 2. 'ExistentialQuantification' no hace nada en este ejemplo, la extensión importante es' Rank2Types' solamente. – Vitus

+0

@Vitus: ah, claro! Lo sigo mezclando, pero eso tiene mucho más sentido, pensar en ello. Editado – leftaroundabout

Cuestiones relacionadas