📜 ⬆️ ⬇️

From monoids to de Morgan algebras. We build abstractions on Haskell

What do normal distributions, finite automata, hash tables, arbitrary predicates, strings, convex hulls, affine transformations, configuration files, and CSS styles have in common? And what are the integers, Haskell types, arbitrary graphs, alternative functors, matrices, regular expressions, and statistical samples? Finally, is it possible to somehow interconnect boolean algebra, electrical circuits, rectangular tables, thermal insulation of pipes or buildings, and images on a plane? There are two important answers to these questions: 1) programmers work with all these objects, 2) these objects have a similar algebraic structure : the first are monoids, the second are semirings, and the third are de Morgan algebras.


If we, programmers, learn ourselves and teach a computer to work with monoids, half rings and other structures, then it will become easier for all of us to work. Because certain constraints are imposed on algebraic structures, and certain guarantees follow from limitations. All these restrictions and guarantees are valid for all representatives of the structure, which means that you can build universal tools for working with monoids, semirings, algebras and, therefore, with all of the above and many other objects. See how many mathematicians defined algebraic structures! And after all, there are theorems for them, some useful for programmers, some not yet very good, but all of them are reliable, like the best program libraries!


Everything becomes even tastier when homomorphisms are built inside the structure — transformations that preserve the structure. Homomorphisms make it possible to "switch" from one structure object to another - from lists to numbers, from graphs to matrices, from regular expressions to graphs, from electrical circuits to boolean expressions or to graphical representations of these circuits! But isomorphisms are a song in general! If a programmer believes that he does not need mathematics and that all these morphism-morphisms are just abstract nonsense, then he deprives himself of not only an excellent, reliable tool, but, most importantly, an essential part of the pleasure of his work.


In this article, we will show, using the example of de Morgan algebras, how to construct algebraic abstractions, how to define homomorphisms and free algebras for them, and how this can be used, of course.


The article is intended for those who already know what type classes are, functors, monoids and, in general, are well aware of what Haskell programming is. On the other hand, it may be of interest to anyone who is interested in how abstractions are built in programming, and how they can be applied to real problems.


A little about monoids


Monoids are an abstraction of composition. In turn, composition is a key concept in functional programming. That is why monoids are found here so often and play such important roles. Much has been said and written about the value and richness of using monoids. Here we list their main properties, which will be useful to us in the further presentation.


Definition


A monoid is a very simple structure: this is a set on which an associative binary operation is defined that has a single neutral element. The commutativity of the operation is not required, but the neutral element must be neutral, being both the first and second operand.


In the Haskell language for monoids, the class Monoid :


 class Monoid a where mempty :: a mappend :: a -> a -> a 

and the Data.Monoid library provides a number of useful instances of this class, such as Sum , Product , First , Last , Endo , etc.


The key properties of a monoid are the associativity and uniqueness of the neutral element. These restrictions allow us to generalize monoidal operations for an arbitrary order of execution (including for parallel).


Dual monoid


For any monoid, one can define a dual monoid in which the binary operation takes the arguments in the reverse order:


 > Dual [1,2,3] <> Dual [5,6] Dual { getDual = [5,6,1,2,3] } 

Convolution connection


It is well known how a useful and versatile tool is convolution: on the one hand, dozens of useful universal functions that process collections are expressed through convolution, and on the other, lists, trees, and other inductive collections can be collapsed. The package is defined quite a lot. You can collapse the collection both on the right and on the left; this can affect the result (depending on the associativity of the folding function) and the efficiency of the calculations. You can collapse by entering the initial result of the convolution, in case of an empty collection, or doing without it, if there is a guarantee that the collection is not empty. Therefore, in the Haskell standard library and the Data.Foldable library Data.Foldable so many different convolutions:


  foldr, foldl, foldr1, foldl1, foldl', foldl1' 

If we are talking about a convolution into a monoid, one function is enough, due to the associativity of the monoidal operation and the guarantee of the presence of a neutral element.


 fold :: (Monoid m, Foldable t) => tm -> m 

The most commonly used option is to explicitly specify which monoid should be used for the convolution:


 foldMap :: (Monoid m, Foldable t) => (a -> m) -> ta -> m 

If the collection is a functor, the definition of the function foldMap can be given as follows:


 foldMap f = fold . fmap f 

Free monoid


Sometimes it is possible to "move" between monoids, we recall, such transformations are called homomorphisms. Moreover, there exists a monoid from which one can construct a homomorphism into any other. Such a monoid is called free ; its role in Haskell is played by lists.


Free structures reflect the properties of an algebraic system, but do not “compute” anything, do not change data, and do not lose information. In a certain sense, they represent a formal language for describing an element of an algebraic system or category, while homomorphisms can be considered as interpreters of this language. This analogy will be useful to us in the future.


Read more about monoids and their use in Haskell can be found in the articles:



Algebra de Morgana


For many objects, there are several ways to compose and one cannot do without a single monoid. If there are two such methods, then they speak of rings, semirings, lattices, and various algebras. Let us consider several examples that suggest the generality of the algebraic structure underlying them.


Boolean algebra


What we know about Boolean algebra:



!(A wedgeB)=!A vee!B, quad!(A veeB)=!A wedge!B


Algebra Electrical Resistance


Let's consider the problem of calculating an arbitrary bipolar electrical circuit, which may consist of resistances and allows for the series or parallel connection of circuit elements.



')

Source: https://habr.com/ru/post/323832/


All Articles