Steve
Steve

Reputation: 43

Pattern matching data types in Haskell. Short cuts?

In the following Haskell code, how can this be written more succinctly? Is it necessary to list all four conditions, or can these be summarized by a more compact pattern? For instance, is there a way I can take advantage of Haskell already knowing how to add a float and an int, without having to manually specify 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)))

Upvotes: 4

Views: 1129

Answers (1)

Thomas
Thomas

Reputation: 182038

Haskell does not know how to add a Float and an Int; it is very specific and explicit about types:

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

Define a function toFloatSig:

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

Then you can write:

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

It might also be appropriate to make Signal an instance of the Num class, so that you can add them directly with the + operator. Also, you could make the type more generic:

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

Upvotes: 7

Related Questions