4

How come I can't set a String constraint, but a Num works just fine?

This works:

ltest' :: (Num a) => a -> a
ltest' a = (\b -> b * 2) a

This does not:

test' :: (String a) => a -> a
test' a = a ++ " good job"

Error:

• Expecting one fewer argument to ‘String’
  Expected kind ‘* -> Constraint’, but ‘String’ has kind ‘*’
• In the type signature:
    test' :: (String a) => a -> a
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
v0d1ch
  • 2,738
  • 1
  • 22
  • 27

1 Answers1

13

String is a type:

type String = [Char]

Num is a class:

class Num a where
    (+), (-), (*)       :: a -> a -> a
    negate              :: a -> a
    abs                 :: a -> a
    signum              :: a -> a
    fromInteger         :: Integer -> a
    negate x            = 0 - x

Constraints only involve classes, not types.

Your ltest' has a type parameter, a.1 This can be expressed explicitly:

ltest' :: forall a. (Num a) => a -> a

This means it works with any type a that has an instance of the Num class.

Your test' doesn't need type parameters, because it only works with one type2 (the argument can only be of type String). So it also doesn't need any constraints, because there are no type parameters to constrain.

test' :: String -> String
test' a = a ++ " good job"

1 In other words, ltest' has a polymorphic type.

2 In other words, test' has a monomorphic type.

Chris Martin
  • 30,334
  • 10
  • 78
  • 137