How does Haskell's *
work? Does it create a series of
operators, or does it do something else?
CodePudding user response:
This is the Num
type class
type Num :: Type -> Constraint
class Num a where
( ) :: a -> a -> a
(*) :: a -> a -> a
-- .. I'm omitting the other methods
This is how Num
is defined for Int
(src)
instance Num Int where
( ) :: Int -> Int -> Int
I# x I# y = I# (x # y)
(*) :: Int -> Int -> Int
I# x * I# y = I# (x *# y)
-- ..
This is how it's defined for Float
(src)
instance Num Float where
( ) :: Float -> Float -> Float
F# x F# y = F# (plusFloat# x y)
(*) :: Float -> Float -> Float
F# x F# y = F# (timesFloat# x y)
Maybe not enlightening but you can see that (for those instances) they are defined in terms of primitive operations like ( #)
or timesFloat#
. If you define your own number you can define multiplication in terms of repeated addition but the operations are not fundamentally defined that way.
type N :: Type
data N = O | S N
instance Num N where
( ) :: N -> N -> N
O m = m
S n m = S (n m)
(*) :: N -> N -> N
O * _ = O
S n * m = m (n * m)
You can define a "default" multiplication function that is defined in terms of repeated additions
-- >> timesViaPlus @Int @Int 10 20
-- 200
-- >> timesViaPlus @Integer @Integer 10 20
-- 200
timesViaPlus :: Integral n => Num m => n -> m -> m
timesViaPlus n m = sum (fromIntegral n `replicate` m)
or you could specialize it to N
and use it to define (*) @N
.
replicateN :: N -> a -> [a]
replicateN O _ = []
replicateN (S n) a = a : replicateN n a
timesViaPlusN :: Num n => N -> n -> n
timesViaPlusN n m = sum (n `replicateN` m)
instance Num N where
( ) :: N -> N -> N
O m = m
S n m = S (n m)
(*) :: N -> N -> N
(*) = timesViaPlusN