0% found this document useful (0 votes)
107 views

Introduction To Programming in Haskell

The document provides an introduction to programming in Haskell. It discusses several topics including: - Industrial uses of functional languages by companies like Intel, HP, and Ericsson. - Why old languages survive due to legacy code and programmers. - Reasons for using Haskell like its high level of abstraction, expressiveness, ability to handle complex data, and prioritization of programmer time over computer time. - Core functional programming concepts like functions, values, expressions, definitions, types, and recursion. - Basic Haskell types including numbers, lists, strings, and functions.

Uploaded by

umjpkgiq
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
107 views

Introduction To Programming in Haskell

The document provides an introduction to programming in Haskell. It discusses several topics including: - Industrial uses of functional languages by companies like Intel, HP, and Ericsson. - Why old languages survive due to legacy code and programmers. - Reasons for using Haskell like its high level of abstraction, expressiveness, ability to handle complex data, and prioritization of programmer time over computer time. - Core functional programming concepts like functions, values, expressions, definitions, types, and recursion. - Basic Haskell types including numbers, lists, strings, and functions.

Uploaded by

umjpkgiq
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 111

Introduction to Programming in Haskell

Programming Languages: ICS 141

UC Irvine
Adapted from John Hughes

Industrial Uses of Functional Languages


Intel (microprocessor verification) Hewlett Packard (telecom event correlation) Legasys (Y2K tool) Hafnium (Y2K tool) Shop.com (e-commerce) Motorola (test generation) Thompson (radar tracking)

Ericsson (telecommunications)
Carlstedt Research & Technology (air-crew scheduling)

Why Do Old Languages Survive?


Legacy code Legacy programmers

Why Haskell?
Haskell is a very high-level language (many details taken care of automatically).
Haskell is expressive and concise (can achieve a lot with a little effort). Haskell is good at handling complex data and combining components. Haskell is not a high-performance language (prioritise programmer-time over computer-time).

Functional Programming
A function is a way of computing a result from the function arguments. A function producing a number from an angle. f(x) = sin x/cos x game(mouse clicks) = screen animation A function producing a sequence of images from a sequence of mouse clicks. A functional program computes its output as a function of its input.

Values and Expressions


A value is a piece of data. 2, 4, 3.14159, John,

An expression computes a value. 2 + 2, 2*pi*r

Expressions combine values using functions and operators.

Operations
Operators are always explicit: b^2 - 4*a*c
Power. Multiplication.

Cannot be written as

b2 - 4ac.

Means (b^2) - (4*a*c), not e.g. b^((2-4)*a*c).

Multiplication (*) binds more tightly than subtraction (-).

Functions
The solution of a quadratic equation:

(-b + sqrt (b^2 - 4*a*c)) / (2*a)

A function.

Definitions and Types


A definition gives a name to a value.
Types specify what kind of value this is.

area :: Int
area = 41*37 Names start with a small letter, and are made up of letters and digits.

An expression says how the value is computed.

Definitions and Types


A definition gives a name to a value.
Types specify what kind of value this is.

area :: Int
area = 41*37

Read :: as has type

An expression says how the value is computed.

Function Definitions
A function definition specifies how the result is computed from the arguments. Function types specify the types of the arguments and the result: type signature declaration area :: Int -> Int -> Int
area l b = l*b The body specifies how the result is computed: declaration

The arguments are given names, after the function name.

Cf. area(l,b) = l*b

Function Notation
Function arguments are not enclosed in brackets! Example: average :: Float -> Float -> Float

average x y = (x + y) / 2
Calls: average 2 3 2.5

average (2+2) (3*3)

6.5

Brackets are for grouping only!

Functional Programming
A functional program consists mostly of function definitions. Simple functions are used to define more complex ones, which are used to define still more complex ones, and so on. Finally, we define a function to compute the output of the entire program from its inputs. If you can write function definitions, you can write functional programs!

A Tour of Some Basic Types


From mathematics, were used to functions whose arguments and results are numbers. In programs, we usually work with much richer types of values.

Some types are built in to programming languages (e.g. numbers), others are defined by programmers (e.g. MP3). Let us tour some of Haskells built-in types.

A Tour of Some Basic Types


Values:
Truth-values Characters Tuples Functions

lists
User-Defined data-types.

Basic Category: Numbers


Numeric types:
based on those of Scheme / Common Lisp These languages are dynamically typed

The Num class provides several basic operations common to all numeric types
addition, (+) subtraction, (-) negation, negate Multiplication, (*) absolute value, abs others

Basic Category: Numbers


The Num class provides several basic operations common to all numeric types addition, (+) subtraction, (-) negation, negate Multiplication, (*) absolute value, abs others NOTE: Haskell is a statically typed language. All operators/functions have a type-signature: (+), (-), (*) :: (Num a) => a -> a -> a negate, abs :: (Num a) => a -> a

Basic Category: Numbers


OPERATOR DETOUR
FIXITY DECLARATIONS

declaration specifies
precedence level from 0 to 9 (with 9 being the strongest(default); normal application is assumed to have a precedence level of 10) left-(infixl), right(infixr), or nonassociativity (infix).

addition, (+) subtraction, (-) negation, negate Multiplication, (*) absolute value, abs others

Basic Category: Numbers


The Num class provides several basic operations common to all numeric types class Integral provides whole-number division and remainder operations. The standard instances of Integral are Integer unbounded or mathematical integers, AKA bignums" class Int Bounded Machine integers Range equivalent to at least 29-bit signed binary

Basic Category: Numbers


The Num class provides several basic operations common to all numeric types class Fractional provides the ordinary division operator (/). further subclass Floating contains trigonometric, logarithmic, and exponential functions class ??? Constructed Numbers made out of primitives: Int, Integer, Float, and Double

Basic Category: Numbers


Numeric Coercions and Overloaded Literals
The Standard Prelude and libraries provide several overloaded functions that serve as explicit coercions:
fromInteger :: (Num a) => Integer -> a fromRational :: (Fractional a) => Rational -> a toInteger :: (Integral a) => a -> Integer toRational :: (RealFrac a) => a -> Rational fromIntegral :: (Integral a, Num b) => a -> b fromRealFrac :: (RealFrac a, Fractional b) => a -> b fromIntegral = fromInteger . toInteger fromRealFrac = fromRational . toRational

Types: Integers
1, 2, 3, 4 :: Int Whole numbers (between -2^31 and 2^31-1).

Some operations:
2+3 2*3 5 6 div 7 2 mod 7 2 3 1

2^3

Types: Real Numbers


1.5, 0.425, 3.14159 :: Float

Real numbers (with about 6 significant figures).

Some operations:
2.5 + 1.5 3 - 1.2 1.4142^2 4.0 1.8 1.99996

1/3

0.333333

sin (pi/4)

0.707107

Types: Lists
A list of values enclosed in square brackets.

A list of integers.
[1,2,3], [2] :: [Int]

Some operations:
[1,2,3] ++[4,5] head [1,2,3] last [1,2,3] [1,2,3,4,5] 1 3

Question
How would you add 4 to the end of the list [1,2,3]?

Quick Q...
How would you add 4 to the end of the list [1,2,3]? [1,2,3] ++ [4] [1,2,3,4]

[4] not 4! ++ combines two lists, and 4 is not a list.

Types: Strings
Any characters enclosed in double quotes. Some operations: Hello ++ World Hello World Hello! :: String The type of a piece of text.

show (2+2)

Question
Is 2+2 equal to 4?

Question
Is 2+2 equal to 4?

No!
2+2 is a string three characters long. 4 is a string one character long. They are not the same text!

Types: Commands
A command to write Hello! to myfile. The type of a command which produces no value.

writeFile myfile Hello! :: IO ()


readFile myfile :: IO String

The type of a command which produces a String.

Question
If myfile contains Hello!,
is readFile myfile equal to Hello!?

Question
If myfile contains Hello!,
is readFile myfile equal to Hello!?

NO!

This is a command to read a file.

This is a constant piece of text.

The result of a function depends only on its arguments; Hello! cannot be computed from myfile.

Effects of Commands
The result of a function depends only on its arguments. The effect of a command may be different, depending when it is executed.
Take one step backwards is always the same command...

Types: Functions
double :: Int -> Int double x = x+x double 2 4

is a function call.

double (no arguments) is a

function value.

Function Composition
quadruple :: Int -> Int quadruple = double . double Function composition: an operator on functions! quadruple 2 double (double 2)

double 4
8

The map Function


doubles :: [Int] -> [Int] doubles = map double A function with a function as its argument and its result!

doubles [1,2,3]

[double 1, double 2, double 3]


[2, 4, 6]

Function Definition by Cases and Recursion


Programming Languages: ICS 141 UC Irvine
Adapted from John Hughes

Definitions Revisited
A definition double :: Int -> Int

double x = 2*x
makes a true statement about the function defined, (whatever x is, then double x and 2*x are equal) gives a way of computing calls of the function.

Question
Given the definition
x :: Int x*x = 4

Is x equal to 2?

Question
Given the definition
x :: Int x*x = 4

Is x equal to 2?

NO!

This is not a valid Haskell definition. It makes a true statement about x, but it does not give a way of computing x.

Computing with Definitions


A function call is computed by replacing the call with a copy of the right hand side, with the argument names replaced by the actual arguments.
double :: Int -> Int double x = 2*x

double 8

2*8
16

Evaluation Order
There may be more than one way to evaluate an expression:
Innermost Reduction eager evaluation 2*8 2*(3+5) Outermost Reduction laxy evaluation
NOTE: Haskell also has lazy data-structures. more on that later.

double 8 double (3+5)

16

Evaluation Order
There may be more than one way to evaluate an expression:
three :: Integer->Integer three x = 3 infinity :: Integer-> Integer infinity = infinity +1

Innermost Reduction eager evaluation three (infinity+1) three infinity =3 three(infinity) Outermost Reduction laxy evaluation three((infinity + 1) +1)
three(((infinity +1)+1)+1).)

Sharing Evaluation
double :: Int -> Int double x = x+x double (3*5)
(3*5)+(3*5) double 15

Is it more work to evaluate the expression in this order?

15+(3*5)
15+15

30

Sharing Evaluation
Via Graph Reduction double :: Int -> Int double x = x+x double (3*5) (3*5)+(3*5) double 15 15+15 30
Haskell represents expressions as graphs so that duplicated subexpressions can be shared and reduced at most once. This is an implementation of PASS-BY-NAME semantics

NO! Haskell `remembers that both occurrences of 3*5 are really the same, and evaluates both in one step.

Sharing Evaluation
Via Graph Reduction double :: Int -> Int double x = x+x double (3*5) (3*5)+(3*5) double 15 15+15 30
Haskell represents expressions as graphs so that duplicated subexpressions can be shared and reduced at most once. This is an implementation of PASS-BY-NAME semantics

NO! Haskell `remembers that both occurrences of 3*5 are really the same, and evaluates both in one step.

Definition by Cases
Often programs must make decisions, and compute different results in different cases.

Example:

Define max x y to return the maximum of its


two arguments.

If x <= y, then max x y should be y. If x>y, then max x y should be x.

The Type of Booleans


We make a decision by asking: does a condition hold?
(e.g. Does x<=y hold?) A condition is either true or false: this is a piece of data, a value! We introduce a new basic type with two values, named after the mathematician George Boole:

True, False :: Bool


Constants begin with a capital letter.

Some Operators Producing Booleans


Note two equals signs, to avoid confusion with a definition. 2 <= 3 2>3 True False

2<3
2 == 3

True
False True

Not equals.

2 /= 3

Functions Returning Booleans


Functions can return boolean results (or any other type).

Example:

inOrder :: Int -> Int -> Int -> Bool


inOrder x y z = x <= y && y <= z

a && b is True if both a and b are True.

Using Booleans to Define Functions by Cases


max :: Int -> Int -> Int max x y | x <= y = y max :: Int -> Int -> Int

OR

max x y | x <= y = y

max x y | x > y = x

|x>y=x

A guard: an expression of type Bool. If the guard is True, the equation applies.

Evaluation with Guards


To evaluate a function call, evaluate each guard in turn until one is True, replace the call with a copy of the right hand side following the true guard. max 4 2 ?? 4 <= 2 max :: Int -> Int -> Int max x y | x <= y = y |x>y=x ?? 4 > 2 False True

Recursion
Problem: define fac :: Int -> Int fac n = 1 * 2 * * n

What if we already know the value of fac (n-1)? = 1 * 2 * * (n-1) * n = fac (n-1) * n

Then fac n

A Table of Factorials
n 0 1 2 3 4 ... fac n 1 1 2 6 24 So fac 3 = 2 * 3. So fac 2 = 1 * 2. So fac 1 = 1 * 1.

Must start somewhere: we know that fac 0 = 1.

A Recursive Definition of Factorial


fac :: Int -> Int fac 0 = 1 Base case.

fac n | n > 0 = fac (n-1) * n


Recursive case.

Evaluating Factorials
fac :: Int -> Int

fac 0 = 1
fac n | n > 0 = fac (n-1) * n

fac 4

?? 4 == 0 ?? 4 > 0

False True

fac 2 * 3 * 4 fac 1 * 2 * 3 * 4

fac (4-1) * 4
fac 3 * 4

fac 0 * 1 * 2 * 3 * 4
1*1*2*3*4 24

Currying
Consider this add function: add :: Integer -> Integer -> Integer In other words, applying add to one argument yields add x y = x + y a new function which is then
applied to the second argument.

An application of add has the form:

add e1 e2

(add e1) e2

This is an example of a curried function.

Currying

add e1 e2

(add e1) e2

NOTE: operands associate left to the function, while results associate to the next right-most operand

Currying
A useful device for reducing the number of parentheses in an expression is the idea of replacing a structured argument by a sequence of simpler ones. Consider smaller (returns the smaller of 2 integers) UNCURRIED: smaller :: (Integer, Integer) Integer smaller(x, y) = if x <= y then x else y CURRIED: smallerc :: Integer (Integer Integer) smallerc x y = if x < y then x else y
smallerc 3 4 means (smallerc 3) 4

Currying
smaller curried: smallerc :: Integer (Integer Integer) smallerc x y = if x < y then x else y smallerc 3 4 means (smallerc 3) 4 Advantages of currying functions. help to reduce the number of parentheses curried functions can be applied to one argument only (giving another function that may be useful in its own right)

Operators
A sampling of Haskell infix built-in operators & their types: -- Functions: (->) Eq((==), (/=)), Ord(compare, (<), (<=), (>=), (>), max, min), -- Num((+), (-), (*), -- Integral(quot, rem, div, mod, quotRem, divMod), -- Fractional((/), recip) -- List (++) :: [a] -> [a] -> [a] [] ++ ys = ys (x:xs) ++ ys = x : (xs++ys)

Operators
A sampling of Haskell infix built-in operators & their types: Lambda Abstractions Instead of using equations to define functions, we can also define them anonymously" via a lambda abstraction. For example, In fact, the equations: inc x = x+1 add x y = x+y

inc = \x -> x+1 add = \x y -> x+y

Operators
A sampling of Haskell infix built-in operators & their types:

Infix Operators really just functions can be defined using equations lexically, infix operators consist entirely of symbols"
function composition (infix): (.) :: (b->c) -> (a->b) -> (a->c) f . g = \ x -> f (g x)

Sections

Remember all operators are just functions. Haskell allows the partial application of an infix operator: called sections. For example: (x+) = \y -> x+y (+y) = \x -> x+y (+) = \x y -> x+y [NOTE: The parentheses are mandatory.]

Sections
coerces an infix operator into an equivalent functional value handy when passing an infix operator as an argument to a function, ex: (What does this return?) map (+) [1,2,3] Examples Allows you to pass a function as an argument inc = (+ 1) add = (+) double = (* 2) First Class Object / pos = (>0) Higher Order Function half = (/2)

Lessons
Recursion lets us decompose a problem into smaller subproblems of the same kind -- a powerful problem solving tool in any programming language!
To ensure termination, define a `problem size which must be greater than zero in the recursive cases, and decreases by at least one in each recursive call.

Tuples and Lists


Programming Languages: ICS 141 UC Irvine
Adapted from John Hughes

Tuples
A tuple is a value made up of several other values, its components.
Examples: A point in the plane (x,y) A point in space (x,y,z)

Round brackets and commas.

A purchase
The null tuple

(Dagens Lunch, 55)


()

Tuple Types
A tuple type specifies the type of each component.

Examples:

(1,2) :: (Int, Int)


(1.5, 2.25) :: (Float, Float) (Dagens Lunch, 55) :: (String, Int) () :: ()

Type Definitions
We can give names to types with a type definition:

type Purchase = (String, Int) All types start with a capital letter. Now Purchase and (String, Int) are interchangeable: dagens :: Purchase dagens = (Dagens Lunch, 55)

Pattern Matching
Functions on tuples can be defined by pattern matching:

name :: Purchase -> String

name (s, i) = s
A pattern which must match the actual argument.

price :: Purchase -> Int price (s, i) = i

Standard Selector Functions


fst (x, y) = x
snd (x, y) = y

But we cannot define:


select 1 (x, y) = x select 2 (x, y) = y

What would the type of the result be?

The type of a functions result is not allowed to depend on the values of the arguments.

Lists
A list is also a value made up of other values, its elements.
Examples:

[1, 2, 3]
[True, False, True] [] [(Dagens Lunch, 55)]

:: [Int]
:: [Bool] :: [Float] :: [Purchase]

Tuples vs. Lists


A tuple consists of a fixed number of components, of various types. A list consists of any number of elements, all of the same type.

Useful, but not much to know.

Ubiquitous! Supported by a rich set of standard functions and constructions.

Lists Can Make Programs Simpler!


Whenever there is a sequence of values, consider using a list.

Lists for Counting


We often need to count:
[1..10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1,3..10] = [1, 3, 5, 7, 9]

[1,3,...] = [1, 3, 5, 7, 9, ... (infinite sequence)


Example: fac :: Int -> Int fac n = product [1..n] Standard function to multiply together list elements.

List Comprehensions
We often do the same thing to every element of a list:

Example:

doubles :: [Int] -> [Int]


doubles xs = [2 * x | x <- xs]

For each element x of xs...

Add 2*x to the list produced.


doubles [1..3] [2, 4, 6]

Summing Squares with Lists


n
[1, 2, 3, , n] [1, 4, 9, , n^2] 1 + 4 + 9 + + n^2 sumsq :: Int -> Int sumsq n = sum [i^2 | i <- [1..n]] Add up the elements of a list.

Filtering Lists
A list comprehension can include a condition which elements must satisfy. Include only those i which pass this test.

Example:
factors :: Int -> [Int]

factors n = [i | i <- [2..n], n `mod` i == 0]

factors 12

[2, 3, 4, 6, 12]

Using factors
Counting the number of factors numFactors :: Int -> Int numFactors n = length (factors n) Testing for a prime number isPrime :: Int -> Bool isPrime n = factors n == [n] The number of elements in a list.

Designing List Comprehensions


Ask yourself: Do I want to process a sequence of elements in turn? If so, use a list comprehension!

<-

] Start by writing down a framework with gaps to be filled in.

Designing List Comprehensions


Ask yourself: What is the list whose elements I want to process?

<- [2..n]

Write it in the gap after the left arrow.

Designing List Comprehensions


Ask yourself: What will I call each element?

|i

<- [2..n]

Fill the name in to the left of the arrow.

Designing List Comprehensions


[ f x | x <- xs ]
read as \the list of all f x such that x is drawn from xs. phrase x <- xs is called a generator more than one generator is allowed, as in: [ (x,y) | x <- xs, y <- ys ]

[ f x | x <- xs ]

Write an expression before the bar.

Designing List Comprehensions


Ask yourself: Do I want to process every element, or make a selection from them?
A Guard places constraints on the elements generated.

| i <- [2..n], n `mod` i == 0] Write a comma and a condition at the end of the comprehension.

Designing List Comprehensions


Ask yourself: What values do I want in the result?

[i

| i <- [2..n], n `mod` i == 0]

Write an expression before the bar.

List Comprehension & Generators


Quicksort Example:

quicksort [] = [] quicksort (x:xs) = quicksort [y | y <- xs, y<x ] ++ [x] ++ quicksort [y | y <- xs, y>=x]

Lists vs. Recursion?


Even problems which do not mention lists can often be solved easily by using lists internally. Haskells powerful list constructions often offer a simpler alternative to using recursion.

But not always! Recursion is a powerful and general tool -therefore harder to use than special purpose tools, when they are applicable.

The Role of Lists


Lists offer a natural way to model real world information -sequences are everywhere!
Lists are easy to manipulate thanks to Haskells support: a good first choice of data structure.

Lists are not always efficient: candidates for replacement by faster structures later in program development.

Some Standard List Functions


Haskell provides many standard functions to manipulate lists. Lets look at a few.

But first:

What is the type of length?

Polymorphic Types
length :: [Int] -> Int length :: [Float] -> Int length :: [Card] -> Int

length has many types! It is polymorphic. That is why it is useful.

For any type t, length :: [t] -> Int A type variable, which may stand for any type.

Taking and Dropping


take n xs
drop n xs

the first n elements of xs,


all but the first n elements.

Examples:
take 3 (factors 12) drop 3 (factors 12) [2, 3, 4] [6, 12]

Question
take and drop have the same (polymorphic) type. What is it?

Question
take and drop have the same (polymorphic) type. What is it?

take, drop :: Int -> [a] -> [a] A must stand for the same type everywhere. Examples: Int -> [Float] -> [Float] Int -> [String] -> [String] Not Int -> [Float] -> [String]

The Zipper
Often we want to combine corresponding elements of two lists:
John , Simon, Mary ]

zip [

Welsh,

English,

Irish ]

[ (John,Welsh),

(Simon,English), (Mary,Irish)]

The type of zip


zip :: [a] -> [b] -> [(a, b)]

Example:

zip [1, 2, 3] [a, b, c]


[(1,a), (2,b), (3,c)]

Here zip :: [Int] -> [String] -> [(Int, String)]

Example: The Position of x in xs


position :: a -> [a] -> Int
Example: position b [a, b, c]

Idea: Mark every element with its position, and search for the one we want.

Marking Elements with Positions


[a, b, c]
zip [a, b, c]

[(a,1), (b,2), (c,3)]

[ 1,

2,

3]

[(a,1), (b,2), (c,3)]

Use zip xs [1..length xs]

Rule of Thumb
Question: Do I want to go through the elements of two lists together? Answer: Use zip!

Lessons
Lists model any kind of sequence in the real world.
Lists can express many kinds of repeated computation in programs. Special constructions and a rich set of polymorphic standard functions let us manipulate lists very easily indeed. Look for opportunities to use them!

Types in Haskell
Programming Languages: ICS 141 UC Irvine

Strong Typing
Haskell is a typeful programming language computations evaluate expressions yield values Each value has an associated type.
Values Types

First class objects passed as arguments returned as results placed in data structures, etc

NOT first-class

attribute of a value

Strong Typing
TYPE SAFE:
Static Type System Ensures that Haskell programs are type safe; i.e. no programmer mismatches

Haskell's type system possesses two important properties:


every well-typed expression is guaranteed to have a unique principal type the principal type can be inferred automatically
TRIVIA Hindley-Milner type system, which forms the basis of the type systems of Haskell

Basic Types
Int : finite! Integer: infinite enumeration. Type Rules for
Tuples
For (e1,e2, ,en); n >= 2, if ti is the type of ei, then the type of the tuple is (t1,t2, : : : ,tn).

Lists
For [e1,e2, ,en]; n >= 0, each ei must have the same type t, and the type of the list is [t].

User Defined Types


Enumerated Types
Define types using a data declaration. Ex:
BOOLEAN
predefined type in Haskell is that of truth values:

data Bool = False | True


COLOR

data Color = Red | Green | Blue | Indigo | Violet Bool & Color: Enumerated Types
consist of a finite number of nullary data constructors.

Pattern Matching
Semantics Pattern matching can either fail, succeed or diverge
(done top-to-bottom, left-to-right)

Matching is permitted using the constructors of any type, userdefined or not. Nesting of patterns is permitted to arbitrary depth.
Example:
contrived :: ([a], Char, (Int, Float), String, Bool) -> Bool contrived ([], 'b', (1, 2.0), "hi", True) = False

Wild-cards:
head (x:_) = x tail (_:xs) = xs
PATTERN MATCHING DIFFERENCE BETWEEN PROLOG & HASKELL HASKELL: one-way" matching, PROLOG: two-way" matching (via unification), & backtracking.

Polymorphic Types
Types that are universally quantified in some way over all types. Polymorphic type expressions essentially describe families of types. (a) [a] is the family of types consisting of, for every type a, the type of lists of a. i.e. Lists of integers (e.g. [1,2,3]) Lists of characters (e.g. ['a','b','c']) Lists of Lists of integers (e.g. [[1], [2] , [3]]) Etc

What about? [2,'b']

is it a valid example?

Example: counting the number of elements in a list


length :: [a] -> Integer length [] = 0 length (x:xs) = 1 + length xs

User Defined Types


Types can also be recursive, as in the type of binary trees:
data Tree a = Leaf a | Branch (Tree a) (Tree a)

NOTE: Tree is a type constructor Branch and Leaf are data constructors. Suppose we wish to define a function fringe that returns a list of all the elements in the leaves of a tree from left to right. It's usually helpful to write down the type of new functions first; in this case we see that the type should be Tree a -> [a].
fringe :: Tree a -> [a] fringe (Leaf x) = [x] fringe (Branch left right) = fringe left ++ fringe right

User Defined Types


Haskell provides a way to define type synonyms; i.e. names for commonly used types. Type synonyms are created using a type declaration. Example:
type Purchase = (String,Int) name :: Purchase -> String name (s, i) = s p1 :: Purchase p1 = ("Shannon", 4470)

Lazy Data Structures


Data structures in Haskell are generally lazy: the components are not evaluated until needed. This permits structures that contain elements which, if evaluated, would lead to an error or fail to terminate. Lazy data structures enhance the expressiveness of Haskell and are an essential aspect of the Haskell programming style. Internally, each field of a lazy data object is wrapped up in a structure commonly referred to as a thunk that encapsulates the computation defining the field value. This thunk is not entered until the value is needed; thunks which contain errors do not affect other elements of a data structure.

Miscellaneous
Types begin with Upper case, identifiers with lower, & Haskell is case sensitive. Comments
To end of line: the characters -- and all subsequent characters to the end of the line are ignored. Embedded or Multi-Line: {--}

Modules
Creating Modules Importing Modules
Haskell's Standard Prelude (in Appendix A of the Report and the standard libraries (found in the Library Report [5]) contain lots of useful examples of Haskell code In order to use the functions created in the modules, i.e. List, etc it is required that you import List

You might also like