Типы сопоставления типов данных в Haskell. Короткие сокращения? - PullRequest
4 голосов
/ 11 ноября 2009

В следующем коде на Haskell как это можно написать более кратко? Нужно ли перечислять все четыре условия, или они могут быть обобщены более компактным образом? Например, есть ли способ, которым я могу воспользоваться тем, что Haskell уже знает, как добавить float и int, без необходимости вручную указывать fromIntegral ?

data Signal = SignalInt Int | SignalFloat Float | Empty deriving (Show)

sigAdd :: Signal -> Signal -> Signal
sigAdd (SignalInt a) (SignalInt b) = SignalInt (a + b)
sigAdd (SignalInt a) (SignalFloat b) = SignalFloat ((fromIntegral a) + b)
sigAdd (SignalFloat a) (SignalInt b) = SignalFloat (a + (fromIntegral b))
sigAdd (SignalFloat a) (SignalFloat b) = SignalFloat (a + b)

main :: IO ()
main = do
  putStrLn (show (sigAdd (SignalFloat 2) (SignalInt 5)))

1 Ответ

7 голосов
/ 11 ноября 2009

Haskell не знает, как добавить Float и Int; это очень специфично и явно о типах:

Prelude> (5 :: Int) + 3.5

<interactive>:1:13:
    No instance for (Fractional Int)
      arising from the literal `3.5' at <interactive>:1:13-15
    Possible fix: add an instance declaration for (Fractional Int)
    In the second argument of `(+)', namely `3.5'
    In the expression: (5 :: Int) + 3.5
    In the definition of `it': it = (5 :: Int) + 3.5

Определить функцию toFloatSig:

toFloatSig (SignalInt a) = fromIntegral a
toFloatSig (SignalFloat a) = a

Тогда вы можете написать:

sigAdd (SignalInt a) (SignalInt b) = SignalInt (a + b)
sigAdd sa sb = SignalFloat (toFloatSig sa + toFloatSig sb)

Также может быть целесообразно сделать Signal экземпляром класса Num , чтобы вы могли добавить их непосредственно с помощью оператора +. Кроме того, вы можете сделать тип более общим:

data (Num a) => Signal a = Signal a | Empty deriving (Show)
...