
Also, this syntax can be used in general to specify the type of a value. i.e. a :: (c1,c2,...,cn) => t means that the name a has type t, where the type that t represents is constrained by all the constraints ci. e.g. foo :: (Num a, Ord b, Eq a) => (a,b) -> (a -> b) -> (b,b) notes that the type of foo is a function from pairs of a and b to functions from functions from a to b to pairs of a and b. However, the a and b previously noted are subject to the constraints that: - a must be an instance of Num and Eq - b must be an instance of Ord This is useful in many cases, which include: - Documenting the type of a function - Coercing a literal to a specific type (e.g. 23 :: Float) - When checking type inference, using (undefined :: a) as a parameter allows me to check types without having to invent some input - When using type aliases and typeclasses, telling GHCi that your expression has some type will either give you a type error or clean up the type signature for your expression. e.g. :t "foo" is [Char], but :t "foo" :: String is String, so you can check whether the more concise type signature is also correct. Best regards, and wishing you much enjoyment studying Haskell, Gesh