#
#
Bibliography
⌜🐇 Rabbit holes to get started with CIMMIC are:
- Learn You a Haskell for Great Good! (LYAHFGG) is a widely-used, often-suggested beginners site for starting out with Haskell. Work through at least chapters 1 and 2 to understand a lot of what we’ll be doing with Haskell below[fn:1]. Pay particular attention to lists and list comprehensions. (RC-hole)
- Another big favorite for Haskell starters, but slightly more challenging is A Gentle Introduction to Haskell 98. AGITH was written by elite school professors (Yale) and uses more math terminology than LYAHFGG. Which is what we’ll be doing, but usually with a shallower on-ramp. (RO-hole)
- The Haskell Wiki [fn:2] is full of knowledge gems, but don’t expect to fully understand it yet. Maybe start with this article and peruse through the rest of the “99 Questions.” (RO-hole)
- We need to learn mathematical logic, since logic is simply baked into every programming language. Try this LibreTexts series on logic. Pay particular attention to the notation used on logic operators and the terminology as well. This stuff comes up all the time in programming. (RC-hole)
- These basic set theory slides with their tie-in to Haskell at the end are very good as well. Do something between a grok and a skim. We’ll eventually be covering all the material therein. (RO-hole)
- Read through this Wikipedia Set[fn:3] article, paying special attention to the Basic Operations section—maybe even rabbit-hole into the union article to understand some basic algebraic operations on sets. You’ve probably seen this stuff before with Venn diagrams; this is some of the algebra behind the diagrams. (RO-hole)
- Another big-league site for the serious-minded is the Rosetta Code site. Here you can search on hundreds algorithms and numerical analysis articles, each task done in the code of dozens of programming languages[fn:4]. (RFYI-hole)
🐇⌟
With this section we’ll do a quick warm-up with some ideas in Haskell, i.e., just a feel for the math and Haskell we’ll be exploring. In the next section we’ll get started proper, and, yes, we’ll be more detail-oriented and explanation-rich. But do get started on the rabbit-holing above.
Some things in mathematics must be assumed as a starting point, as
axiomatic/[fn:1]. One great example would be the /natural or
counting numbers. These are the whole numbers starting typically
with
\begin{align*} \mathbb{N} = \{\text{all the whole numbers starting with zero}\} \end{align*}
By whole numbers we mean whole and atomic[fn:3], as in not rational (fractional), decimal-places real, or transcendental, or irrational numbers. But what is meant by all and, even worse, starting with? For example, is there any sort of order implied, or are these whole numbers just in whatever order as long as they’re after zero? Obviously, this is not our intuitive understanding of the counting numbers.
Around the time of Kindergarten we learned a sort of nursery rhyme of
the first ten numbers—probably using our fingers as aides. Next, we
learned to write the numeric symbols from
But how could we indicate five things without the
numerical symbol
There is the unary numeral system (UNS) where numbers are
represented in a /unary/[fn:7] way, e.g., one is
How would we add or subtract in our UNS system? Ironically, we could invent a sort of columnar subtracting borrowing from decimal vertical subtraction
\begin{array}{r}
&11111
-\!\!\!\!\!\!&11\
\hline
&11100
\end{array}
then we just throw out the zeroes and count up the ones. But we can’t really do addition vertically. Perhaps not vertically but horizontally?
\begin{align*} 11111 + 11 = 1111111 \end{align*}
We could also remove the
(length [1,1,1,1]) - (length [1,1])
2
uns1 list1 list2 = (length list1) - (length list2)
uns1 [1,1,1,1] [1,1]
2
As with all computer-numerical treatments of mathematics, we must
first decide which data structure to use. As is often the case with
Haskell, we will utilize lists to do our work. This may seem ironic in
some cases, since so much of math can be seen as, e.g., set
theory-based. Yes, Haskell has a library for sets, but beginners in
most programming languages start with lists and arrays as the go-to
data structure. Hence, we will manipulate our UNS with lists. This
means a set or string of ones will be represented as a list with
integer ones as its sole elements, e.g., [1,1,1,1,1]
is
- cite:&chamberlandsingle
The unary system
Or we could say “the number after
four.” But that’s just the number after three—and so on until we
arrive at zero, which we call, yes, zero, and write as
…the next, next, next, next, next number after zero.
But just to check this for accuracy, we again fall back on numerical
symbols and names. So we count the number of next’s and translate
this chain of next links back into
So we seem to be stuck with names and symbols, our numbering system,
so to speak, to even get off the ground with numbers as representative
of amounts. However, mathematics will want to take us much further
into the conceptualization of numbers, abstractions far beyond the
simple notion of how many. In abstract algebra, operations on numbers
such as addition and subtraction have consequences beyond number names
or symbols. So the subtraction of one natural number from another is a
“taking away” of one amount from another. But what if we try to take
When we played with the notion of next above, it was as if we
started by feeding a basic starting thing, a zero, into a next
machine, and out came “the next thing after zero”. We might have
noted that to be
According to a modern treatment, there are five basic Peano axioms[fn:10]. The first axiom states
-
$0$ is a natural number, i.e.,$0 ∈ \mathbb{N}$
This is our starting point. Peano then gives four axioms to establish equality
- For every natural number
$n$ ,$S(n)\;$ is a natural number. That is, the natural numbers are closed under$S\;$ . Or$x ∈ \mathbb{N} → Sx ∈ \mathbb{N}\;\;$ .
- For all natural numbers x and y, if x = y, then y = x. That is, equality is symmetric.
- cite:&van2010computational
To check whether two sets are the same one has to check that they have the same members. The fact that membership is all there is to set identity, or that sets are fully determined by their members, is called the principle of extensionality.
Set comprehensions are math shorthand for declaring sets
𝖟𝕭: The set of all natural numbers multiplied by
\begin{align*} E = \{2n \; | \; n ∈ \mathbb{N}\} \end{align*}
We could now have a variation such as
\begin{align*} O = \{n \;|\; n ∈ \mathbb{N}, n ∉ E\} \end{align*}
If every member of a set
let s1 = Set.fromList ["a", "b"]
s1
fromList ["a","b"]
What about a descriptive definition such as
\begin{align*} \text{For allx } x ∈ P\text{, there existsy } y > x \text{ such that } y ∈ P. \end{align*}
➝
For all
[(x,y,z) | x <- [True,False], y <- [True,False], z <- [True,False]]
[(True,True,True),(True,True,False),(True,False,True),(True,False,False),(False,True,True),(False,True,False),(False,False,True),(False,False,False)]
[y > x | x <- [1..10], y <- [1..15]]
[if y > x then y else 0 | x <- [1..10], y <- [1..15]]
fromList ["a","b"]
[x | x <- [1..10], y <- [5..20], x < y ]
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10]
filter even [1..10]
[2,4,6,8,10]
[x | x <- [1..10], (even x)]
[2,4,6,8,10]
0 | 3 |
1 | 6 |
2 | 12 |
3 | 24 |
4 | 48 |
5 | 96 |
6 | 192 |
7 | 384 |
8 | 768 |
reset
set term svg font "Garamond,25"
set title "Exponential growth" font "CMU serif,15"
set style line 1 lc krgb '#0060ad' lt 1 lw 2 # --- blue
set yrange[0:800]
set xrange[0:10]
set terminal svg size 300,500
plot data with lines ls 1 notitle smooth csplines
1 | 2 | 3 | 4 | 5 | 6 | 7 |
2 | 4 | 8 | 16 | 32 | 64 | 128 |
-2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0.25 | 0.5 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 |
If some process is increasing at an exponential rate, it
means that for each unit of change the rate is growing or decreasing
by a common ratio. In the example above, the common ratio is
independent var | first dependent var | second dependent var |
---|---|---|
0.1 | 0.425 | 0.375 |
0.2 | 0.3125 | 0.3375 |
0.3 | 0.24999993 | 0.28333338 |
0.4 | 0.275 | 0.28125 |
0.5 | 0.26 | 0.27 |
0.6 | 0.25833338 | 0.24999993 |
0.7 | 0.24642845 | 0.23928553 |
0.8 | 0.23125 | 0.2375 |
0.9 | 0.23333323 | 0.2333332 |
1 | 0.2225 | 0.22 |
1.1 | 0.20909075 | 0.22272708 |
1.2 | 0.19999998 | 0.21458333 |
1.3 | 0.19615368 | 0.21730748 |
1.4 | 0.18571433 | 0.21071435 |
1.5 | 0.19000008 | 0.2150001 |
1.6 | 0.1828125 | 0.2046875 |
1.7 | 0.18088253 | 0.1985296 |
1.8 | 0.17916675 | 0.18888898 |
1.9 | 0.19342103 | 0.21315783 |
2 | 0.19 | 0.21625 |
2.1 | 0.18214268 | 0.20714265 |
2.2 | 0.17727275 | 0.2022727 |
2.3 | 0.1739131 | 0.1989131 |
2.4 | 0.16770833 | 0.1916667 |
2.5 | 0.164 | 0.188 |
2.6 | 0.15769238 | 0.18076923 |
2.7 | 0.1592591 | 0.1888887 |
2.8 | 0.1598214 | 0.18928565 |
2.9 | 0.15603453 | 0.1844828 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
In Haskell rational numbers are handled by Data.Ratio
import Data.Ratio
The basic “give back the simplest form” function is %
50 % 10
5 % 1
numerator (60 % 20)
3
:{
-- combRatio :: Ratio
combRatio r = show (numerator (r)) ++ "/" ++ show (denominator (r))
:}
combRatio (60 % 20)
3/1
⇲ Tip: Put an infix operator in parentheses to use as prefix
r1 = (%) 50 10
:t r1
r1 :: Integral a => Ratio a
60 % 20 :: (Integral a) => Ratio a
3 % 1
60 % 20 :: Rational
3 % 1
First, the data type
data (Integral a) => Ratio a = !a :% !a deriving (Eq)
The :%
is a data constructor (the :
insures it’s a constructor
and not just an operator function) that is placed between the two
Integral
parameters. But in the source %
calls ~reduce~[fn:11]
reduce :: (Integral a) => a -> a -> Ratio a
{-# SPECIALISE reduce :: Integer -> Integer -> Rational #-}
reduce _ 0 = ratioZeroDenominatorError
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y
(%) :: (Integral a) => a -> a -> Ratio a
x % y = reduce (x * signum y) (abs y)
quot 6 3 -- returns the quotient, discards the remainder, if any
2
The built-in Haskell gcd
was used to reduce the rational number,
e.g., fraction, to its lowest terms.
𝖟𝕭. Find the lowest terms of
gcd 42 56
14
i.e.,
\[ \frac{42}{56} \]
Euclid’s algorithm, is an efficient method for computing the greatest common divisor (GCD) of two integers (numbers), the largest number that divides them both without a remainder.
:{
eGCD :: Integral i => i -> i -> i
eGCD 0 b = b
eGCD a b = eGCD (b `mod` a) a
:}
eGCD 60 25
5
This code give the first four /perfect numbers/[fn:12]
:{
main = do
let n = 4
mapM_ print $
take n [candidate | candidate <- [2 .. 2 ^ 19], getSum candidate == 1 ]
where
getSum candidate =
1 % candidate + sum [1 % factor + 1 % (candidate `div` factor)
| factor <- [2 .. floor (sqrt (fromIntegral candidate))]
, candidate `mod` factor == 0 ]
:}
main
6 28 496 8128
Something[fn:13] else[fn:14]
[fn:1] Truthfully, this will be your go-to reference/tutorial for the immediate CIMMIC future. Get going with it and try to self-pace your way through it all. It’s not in-depth per se but will get you in the Haskell ballpark, so to speak.
[fn:2] Grokking Haskell Wiki articles can be like trying to drink from a full-blast fire hose, but good can be gained from them by the brave and virtuous.
[fn:3] Mathematics as experienced in Wikipedia’s articles can also be a firehose experience, but again good can be gleaned.
[fn:4] Check out this article and then its Haskell answer here … although this would be graduate-level Comp-Sci stuff. Notice, perhaps, the list of 19 languages. These are the biggest of the big in the realm of doing math with computers.
[fn:5] See Positional notation.
[fn:6] My mechanical pocket watch has a face with Roman numerals evenly positioned around a circle, twelve main numbers for the hours with five little marks between each number for the minutes and seconds. But internally, the mechanics only know about ticking; they know nothing of the numbers and their positions on the watch face. So the steady ticking is mapped to the watch face dumbly. Is ticking, therefore, the most fundamental sort of counting?
[fn:7] Unfortunately, unary here has two meanings. It means we’re only using one numeral to do our counting, and it indicates a unary function, i.e., a function that takes only one value and returns only something from its domain—which is a very abstract version of the idea of a unary operator where only one thing is operated on. For example, addition is a binary operation since it takes two numbers and adds them. But making a number a negative number by placing the negative sign in front of the number is an example of a unary operation.
[fn:8] More on the binary number system later.
[fn:9] How would you order a box of crayons? One way would be by their colors. But is brown ahead or behind green? Crayon colors don’t seem to have an ahead or behind, maybe just a “beside” or “along with” perhaps?
[fn:10] Peano actually had nine axioms; however, four of these deal with the equality of his natural numbers, which we’ll deal with later when we explore relations, a more general concept above functions.
[fn:11] quot
returns the quotient, discards the remainder; gcd
is
the built-in greatest common divisor; signum
gives back 1
if
argument is greater than zero, -1
if less than zero, zero if zero.
[fn:12] In number theory, a perfect number is a positive integer that
is equal to the sum of its positive divisors, excluding the number
itself. For instance,
[fn:13] This is the crummier, brute-force version
0 min | 10 min | 20 min | 30 min | 40 min | 50 min |
20.0 | 10. | 5. | 2.5 | 1.25 | 0.625 |
[fn:14] Another attempt
0 min | 10 min | 20 min | 30 min | 40 min | 50 min |
20.0 | 10. | 5. | 2.5 | 1.25 | 0.625 |