Skip to content

Latest commit

 

History

History
35 lines (18 loc) · 4.6 KB

math-in-programming.md

File metadata and controls

35 lines (18 loc) · 4.6 KB

Understanding Programming Through Math

I've seen countless many posts in forums and social media telling people they don't need much math in most areas of programming, yet so few of the people saying this don't realize how much math they actually use in their daily coding.

Knowing how much is the key to writing programs that are composable and self-documenting, because you'll just know how they behave and fit together from the mathematical laws they follow.

Code has many patterns in it and these can be (or already have been) modeled by certain concepts in mathematics. Here are some examples.

Anything you can smush together into a bigger version of the same thing obeys the laws of semigroups. String concatenation is one example.

Any two things you can combine into another of the same thing (along with a do-nothing operation) obeys the laws of monoids. Anything made up entirely of monoids is itself a monoid.

Classes, along with their fields and methods, are captured purely with comonads.

Lists of data are sets and can be manipulated with set operations, unless they contain two or more of the same value, then they're multisets. If you can order them, they're posets (or chains if the list has total ordering).

Expression parsing requires a set of data and a set of operations on that data, collectively called an algebra.

Changing the value of a piece of data is done with a morphism. A data type is effectively a category, assuming it obeys commutative laws, and thus the value change is described as an endomorphism within that category. You can also think of going from one value of a type to another value of the same type as an endomorphism in the category of that type.

Changing the value of anything inside a structure (without changing their type) is done with functors. We're not talking about values with types anymore, we're talking about values with types inside a structure such as a list, Promise(), or IEnumerable<T>. Running a function on a value inside a structure requires an applicative functor, so does running a (first-class) function stored inside that structure.

Looping constructs can be captured with recursive functions (no, they're not always more inefficient and difficult to understand than loops; this is an oft-repeated trope). These include maps (list transformations), filters (operating on parts of lists), and folds (turning a list into a single value). Lists stand in for iterators and indexes.

Changing each value in a list is done with list comprehensions (from set theory). These can combine the uses of maps and filters.

Input and output of data to and from the user and the program in a pure manner can be done with monads, which are structures that take in data to be worked with and perform operations on them away from the rest of the code (obeying the laws of monads). This works because the values are preserved and the changes are passed around (monads "are" endofunctors).

Structures themselves can be built up with various morphisms and F-algebras/coalgebras.

Sequential statements can be performed in a pure way with monads as well. "Do" monads perform these operations in functional languages. Monads also handle error checks and null checks, replacing try/catch blocks.

Data encapsulation without classes is done with lexical closures involving returning higher-order functions from normal functions.

(to be continued? Please send pull requests!)