views:

153

answers:

1

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)))
+6  A: 

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)
Thomas
> sigAdd sa sb = SignalFloat (toFloatSig a + toFloatSig b)Should this be "...(toFloatSig sa + toFloatSig sb)"? Thanks.
Steve
You're right, thanks.
Thomas
I'd definitely look to make Signal Num work.
Don Stewart