A function f is a rule that assigns to each element x in a set A exactly one element, called f(x), in a set B. ... The range of f is the set of all possible values of f(x) as x varies throughout the domain, that is, {f(x) | x ∈ A}The set A above is the domain and the possible outputs of function f are called the range (set B).
Also, I haven't discussed this yet, but we can also talk about the composition of two functions:
Given two functions f and g, the composite function f ◦ g (also called the composition of f and g) is defined by (f ◦ g)(x) = f(g(x))
The above quotes are from James Stewart (1987) Calculus Second Edition, Brooks/Cole Publishing.
In terms of identifying the range and domain, let's look at the type signature from our Haskell add3 function from last post
Here the domain for which add3 is declared to be valid is the set of all numbers (referred to as "a" here , where "a" is of type class Num, i.e., "a" is some kind of number). The range is similarly the set of all real numbers (i.e., type class Num). For those of us hailing from object oriented programming, don't be fooled. These "sets of kinds of things" are really types and remember a class is a "user defined type". So we're directly dealing with types. So functions (both in math and in Haskell) map input types (or kinds of types) to a single output type (or kind of type).
add3 :: (Num a) => a -> a
An example of a "type" might be the integers (the set of numbers like {-infinity ..., -2, -1, 0, 1, 2, ... +infinity}). In Haskell, the integers are conveniently predefined for us with the name "Integer". An example of a "kind of type" are numbers (conveniently predefined in Haskell as "Num"). An integer is a kind of number (in math notation, I think they write it like this: "I ⊂ N" where I are the integers and N all numbers". Mathematicians out there, did I get it right?).
As for function composition, let's look at some examples again using add3:
This example shows function composition as mentioned above (the "." takes the role of the "◦" symbol in Haskell). Here, I've assigned the add3 function to values f and g, just to make the correspondence to the mathematics explicit.
Prelude> :load ./Add.hs
*Main> (add3 . add3) 3
9
*Main> add3 (add3 3)
9
*Main> let f = add3
*Main> let g = add3
*Main> (f . g) 3
9
*Main> f (g 3)
9
*Main> (f . f . f . f . f) 3
18
*Main> f (f (f (f (f 3) ) ) )
18
So far, I've found that the composition symbol makes the most sense when you are composing more than two functions or in "point free style" declarations. For example, we could define add15 as:
add15 :: (Num a) -> a -> a
add15 = add3 . add3 . add3 . add3 . add3

0 comments:
Post a Comment