4
votes

Both the following declarations work for replicate' 3 5. I am not able to understand why you need Num and Ord when Integral would do. The second one was what I came up with and the first one was here - http://learnyouahaskell.com/recursion.

What do I lost with just Integral?

1

replicate' :: (Num a, Ord a) => a -> b -> [b]
replicate' 0 x = []
replicate' n x = x:replicate' (n-1) x

2

replicate' :: (Integral a) => a -> b -> [b]
replicate' 0 x = []
replicate' n x = x:replicate' (n-1) x

Note: I need to give some clarification here after willem's answer below (he understood the question without this clarification). The code in http://learnyouahaskell.com/recursion is

replicate' :: (Num i, Ord i) => i -> a -> [a]  
replicate' n x  
    | n <= 0    = []  
    | otherwise = x:replicate' (n-1) x  

Not what I have mentioned in 1. Willem's reply explains all three snippets.

Also, a related question is available at Haskell type definition, => etc

1
Welcome to SO! I'm a little bit confused by your question - are you asking why the typeclasses Ord and Num exist in the first place? Or are you asking why LearnYouAHaskell teaches the first one instead of the second?Frank Schmitt
You’re right – Integral would be better. replicate' 3.3 5 shouldn’t do what it does.Ry-
Integral implies Num and Ord.Willem Van Onsem
@FrankSchmitt I am trying to understand the difference.Karthikeyan

1 Answers

12
votes

Haskell always aims to construct the most generic type signature. If we take a look at the implementation:

replicate' :: (Num i, Ord i) => i -> a -> [a]  
replicate' n x  
    | n <= 0    = []  
    | otherwise = x:replicate' (n-1) x

We see that the (<=) :: Ord a => a -> a -> Bool function is applied to n, and we calculate n-1 in the recursion (with (-) :: Num a => a -> a -> a). The most generic type signature thus will add a Num and Ord type constraint on that number.

We thus can call replicate' 3.1415 1, and it will return the first four items. But it is probably nonsensical to do that.

The Integral typeclass is a typeclass for integral numbers. It supports integer division. Any Integral type must be a member of the Real and Enum typeclass.

A type that is a member of the Real typeclass, should support a function toRational :: Real a => a -> Rational to convert that number to a Rational, and furthermore should be a member of the Num and Ord typeclasses.

This thus means that if a type is a member of the Integral typeclass, it is a member of Num, Enum, Ord and Real as well. You thus made the type more restrictive. But I think in the context of a replicate' it makes perfect sense to do that.

Note that it might not be ideal to write:

replicate' :: (Num a, Ord a) => a -> b -> [b]
replicate' 0 x = []
replicate' n x = x:replicate' (n-1) x

In case we here call replicate (-3) 1, or replicate 3.14 1 (as @leftroundabout pointed out), we will obtain an infinite list of 1s.