-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathChapter1a.lhs
74 lines (59 loc) · 2.67 KB
/
Chapter1a.lhs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
Introduction
============
The intended audience of this blog post (which will be a chapter or
part of a chapter in the book) is applied mathematicians,
computational physicists, numerical analysts and anyone who has the
need to compute numerical solutions, who have a limited acquaintance
with Haskell and who do not wish to learn about parsing, searching and
sorting, compiler design and other such techniques that are often used
as examples in pedagogic Haskell material. Instead we take the example
of multiplying matrices in the hope that it will provide a more
motivating example. This intitial version is based on a fascinating
discussion the author had with two (applied?) mathematicians. The
exposition is more detailed than other blog posts although more words
does not necessarily mean greater perspicuity. All feedback is
gratefully received.
Implementations
===============
We assume our matrix is dense. There are many ways to implement matrix
multiplication in Haskell. We start with the bookies' favourite.
Lists
-----
We represent vectors as lists and matrices as lists of vectors, that
is lists of lists. We can capture this using type synonyms.
> type Vector a = [a]
> type Matrix a = [Vector a]
First let us multiply a vector by a matrix. Let us ignore the
implementation to start with and just focus on the type
signature.
First we note that Haskell can infer this type; we do not
actually need to give it although this is a good check the
implementation in some sense satisfies its specification.
Here is the function without a type signature. Ignore the
implementation and note below that we can ask ghci to tell us the
type.
> matTimesVecNoSig m v = result
> where
> lrs = map length m
> l = length v
> result = if all (== l) lrs
> then map (\r -> sum $ zipWith (*) r v) m
> else error $ "Matrix has rows of length " ++ show lrs ++
> " but vector is of length " ++ show l
[ghci]
:t matTimesVecNoSig
Notice that ghci does not know to use the type synonyms; we have
introduced them purely as an aid for the reader.
> matTimesVec :: Num a => Matrix a -> (Vector a -> Vector a)
> matTimesVec m v = result
> where
> lrs = map length m
> l = length v
> result = if all (== l) lrs
> then map (\r -> sum $ zipWith (*) r v) m
> else error $ "Matrix has rows of length " ++ show lrs ++
> " but vector is of length " ++ show l
First, notice that we have made the implicit brackets in the type
signature explicit. Ignoring *Num a =>* for the time being, we see
that *matTimesVec* takes a matrix a returns a function which itself
takes a vector and returns a vector.