Expressions, Functions and the Substitution Model

In Haskell, computation is done on expressions. Here are some examples:

3 + 4

sqrt 9.0

sqrt (3 + 6)

Note that expressions have a value and that value has some type. 

3 + 4  => 7  : Int

sqrt 9.0  => 3.0  : Float

sqrt (3 + 6)  => 3.0  : Float

We can define functions which take parameters of some type and return the value of an expression using those parameters.  Whenever we define a function we usually declare the type of that function.  That is, we specify the types of the parameters as well as the type of the returned value.

square :: Float -> Float
square x = x * x

hypotenuse :: Float -> Float -> Float
hypotenuse a b = sqrt (square a + square b)

Observe that the function square takes a parameter which is a Float and returns a value which is a Float.  We denote the type of this function therefore as Float -> Float.   The definition specifies a parameter x, and the return value as the expression obtained when we multiply x to itself.

Note that the function hypotenuse takes two Floats as parameters and returns a Float.  We will discuss later why the type for that function is written so strangely as Float -> Float -> Float

Suppose we wish to compute the value of the following expression:

hypotenuse (3 + 2) (3 * 4)

To evaluate that expression we would simply substitute the expression definition for the function hypotenuse and replace its parameters with the values of its argument expressions:

hypotenuse (3 + 2) (3 * 4) =>                            -- substitute into the body of hypotenuse
sqrt (square (3+2)  + square (3 * 4))  =>        -- evaluate the arguments of square
sqrt (square 5  + square 12)  =>                        -- substitute into the body of square
sqrt (5 * 5 + 12 * 12)    =>                                  -- evaluate the argument of sqrt
sqrt (169) =>
13.0

We will find this substitution model quite useful as expressions get more complex.
 

Application :  Manipulating Words and Sentences

We will consider an application of manipulating words and sentences.  The values of both words and sentences will be of the type Language.  We will have two constructor functions word and sent which take a String and convert it to a Language object.

The following is a list of operators that we can perform on Language objects.

firstItem :: Language -> Language                 -- gives the first letter or word of a word or sentence
lastItem :: Language -> Language                 -- gives the last letter or word of a word or sentence
butFirst :: Language -> Language                 -- gives everything BUT the first letter or word of a word or sentence
butLast :: Language -> Language                 -- gives everything BUT the last letter or word of a word or sentence
item :: Int -> Language -> Language             -- gives the nth letter or word of a word or sentence
count :: Language -> Int                                  -- gives the number of letters or words of a word or sentence
(
+++)  :: Language -> Language->Language   -- concatenate two Language objects together
empty :: Language -> Bool                             -- determines if a word or sentence is empty
member :: Language -> Language->Bool     -- determines if a letter or word is contained in a word or sentence
wordToSent :: Language -> Language        -- converts a word to sentence of one word
sentToWord:: Language -> Language         -- converts a sentence to a single word

Consider the following example expressions:

word "computer" +++ word "s"    => computers : Language

sent "foundations of computer" +++ word "science"  => [foundations of computer science] : Language

count(butFirst (word "dogs"))  => 3 : Int

Consider the following function definitions.  Can you figure out what they do?

addS :: Language -> Language
addS w = w +++ word "s"

thirdPerson :: Language -> Language
thirdPerson verb = sent "she" +++ addS verb
 

Application : Quilts

Now we will look at building expressions which are not composed of number or language objects but are instead made up of quilt images.  The basic building blocks of our quilts will be predefined basic blocks of type Image.

    testBB

    cornerBB

       novaBB

    rcrossBB

We can manipulate blocks with two predefined operators:

quarterTurnRight :: Image -> Image         -- rotates a quilt by a quarter turn right

stack :: Image -> Image -> Image               -- stacks two quilts (of equal width)

We can display a quilt by using the function draw.  Consider the following expressions and figure out what they will display.

draw (stack (quarterTurnRight testBB) rcrossBB)

draw (quarterTurnRight (stack testBB testBB))