2012-05-23 2 views
7

Следующий код предназначен для создания либо двойного, либо целочисленного. s предполагается либо negate, либо id; n вся деталь; и f дробная часть или Nothing для целого числа.Потеря полиморфизма после сопоставления с образцом

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) 

, когда я скомпилировать это я получаю:

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 

Похоже, так или иначе компилятор потерял след того факта, что s является полиморфным. Что здесь произошло и как это исправить?

ответ

10

s не полиморфный внутри вашей функции: вы можете использовать любую функцию, которая работает на некоторыеNum экземпляр в качестве этого параметра, может быть функцией, которая работает только на Complex! Вам нужна универсально определенная функция s, то есть такая, которая действительно может быть вызвана с любымNum экземпляром.

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

То работает, то:

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

Интересно! Я нашел то, что было неправильно (он действительно хотел «Либо a'), как возвращение, но я не понимал, что вокруг есть способ. –

+6

@leftaroundabout: На самом деле вам нужно _универсально_ количественно '' ', и это то, что делает подпись 2-го ранга. 'ExistentialQuantification' ничего не делает в этом примере, важным расширением является« Rank2Types ». – Vitus

+0

@Vitus: ах, правильно! Я продолжаю смешивать его, но это имеет смысл, думая об этом. Ред. – leftaroundabout

Смежные вопросы