Murat Kasimov

More about me

Я language (β)

/Я language (β)/Articles/Jointed functor compositions/

Source code for snippetsTwitter discussionLinkedin discussionFacebook discussion

Let's say we have two covariant functors from Arrow into Arrow:

> `yo` : a o . Given e a `AR_____` a `AR____` o `AR____` Given e o > `yo` : a o . Stops e a `AR_____` a `AR____` o `AR____` Stops e o

There are basically two ways to compose them - nesting each other i.e. one functor becomes a parameter of another one:

: ( t `T'TT` tt `T'I` i ) ~ ( t ( tt i ) ) : ( t `TT'T` tt `T'I` i ) ~ ( tt ( t i ) )

But why do we call this nesting exactly a functor composition? Let's take a look at their subtypes:

: Supertype ( t `T'TT'I` tt `T'I_` i ) ~ ( t `T'TT` tt `T'I` i ) : Supertype ( t `TT'T'I` tt `T'I_` i ) ~ ( t `TT'T` tt `T'I` i )

So that we can wrap our nestings into corresponding wrappers and get new functors:

> `yo` : a o . Given e `T'TT'I` Stops e `T'I_` a `AR_____` a `AR____` o `AR____` Given e `T'TT'I` Stops e `T'I_` o > `yo` : a o . Given e `TT'T'I` Stops e `T'I_` a `AR_____` a `AR____` o `AR____` Given e `TT'T'I` Stops e `T'I_` o

I don't want to mention category of functors since we don't use these notions anywhere else but what we need to know is that this functor composition should be associative for sure...

: Supertype ( t `T'TT'I` tt `T'TT'I_` ttt `T'I__` i ) ~ ( t `T'TT'I` tt `T'TT__` ttt `T'I__` i ) ~ ( ( t `T'TT'I` tt ) ( ttt i ) ) : Supertype ( t `T'TT'I_` tt `T'TT'I` ttt `T'I__` i ) ~ ( t `T'TT__` tt `T'TT'I` ttt `T'I__` i ) ~ ( t ( ( tt `T'TT'I` ttt ) i ) )

... and identity. There should be a functor that doesn't change any other functors - it's called Alone:

: Supertype ( Alone `T'TT'I` t `T'I_` i ) ~ ( Alone `T'TT` t `T'I` i ) ~ ( Alone ( t i ) ) : Supertype ( Alone `TT'T'I` t `T'I_` i ) ~ ( Alone `TT'T` t `T'I` i ) ~ ( t ( Alone i ) )

Coming back to our example - which of these functor compositions is more suitable for these two?

: Supertype ( Given e `T'TT'I` Stops e `T'I_` i ) ~ ( Given e `T'TT` Stops e `T'I` i ) ~ ( Given e ( Stops e i ) ) : Supertype ( Given e `TT'T'I` Stops e `T'I_` i ) ~ ( Given e `TT'T` Stops e `T'I` i ) ~ ( Stops e ( Given e i ) )

What if I tell you that you don't need to think about it since for some functors there is a reserved place?

: Supertype ( Given e `J'T'TT'I` Stops e `T'I__` i ) ~ ( Stops e `TT'T` Given e `T'I` i ) ~ ( Given e ( Stops e i ) ) : Supertype ( Stops e `J'T'TT'I` Given e `T'I__` i ) ~ ( Given e `T'TT` Stops e `T'I` i ) ~ ( Given e ( Stops e i ) )

How does it work? Why do we get the same result when these functors are placed on opposite sides?

: ( t `J'T'TT'I` Stops e `T'I__` i ) ~ ( Jointed `T'I` Stops e `T'I` t ) ~ ( Stops e `TT'T'I` t `T'I_` i ) : ( t `J'T'TT'I` Given e `T'I__` i ) ~ ( Jointed `T'I` Given e `T'I` t ) ~ ( Given e `T'TT'I` t `T'I_` i )

These jointed functors define a preferred type of functor composition per each functor so that you don't get into details of how they are actually built - some joints could be quite complicated:

: Supertype ( World `J'T'TT'I` State e `T'I__` i ) ~ ( World `T'TT` Along e `TT'T` Given e `T'I` i )

The main benefit of these preordered functor compositions is that they are bundled with a set of natural transformations:

> `yok` : a o . Stops e `J'T'TT'I` Given e `T'I__` a `AR_____` a `AR____` Stops e o `AR____` Stops e `J'T'TT'I` Given e `T'I__` o > `yok` : a o . Stops e `J'T'TT'I` Given e `T'I__` a `AR_____` a `AR____` Given e o `AR____` Stops e `J'T'TT'I` Given e `T'I__` o

Let's see how it works on a primive example - Given some Boolean value, halt if it's False:

> Pass `ryo` Enter @ ( Halts `J'T'TT'I` Given Boolean ) `yok'ut` Claim `ha` Given @ Boolean `har` Same `yok` Check

This example is to simple, let's alternate it a bit - let it be ASCII instead of Boolean and we stop if it's not a printable character:

> Pass `ryo` Enter @ ( Stops Caret `J'T'TT'I` Given ASCII ) `yok_'ut` Claim `ha` Given `har_` Ok @ Glyph `has` Error @ Caret `yok_` Check

This snippet is not that practical, but there are some things worth to be noted: having this jointed functor composition we can define individual natural transformations that relate functors inside functor composition!

> ( `yok` Claim ) : Stops Caret `J'T'TT'I` Given ASCII `T'I__` Given ASCII i `AR____` Stops Caret `J'T'TT'I` Given ASCII `T'I__` i > ( `yok` Check ) : Stops Caret `J'T'TT'I` Given ASCII `T'I__` Stops Caret i `AR____` Stops Caret `J'T'TT'I` Given ASCII `T'I__` i

Let's choose another pair of functors - World and State, we also have dedicated natural transformations for them:

> ( `yok` Allot ) : World `J'T'TT'I` State e `T'I__` State e i `AR____` World `J'T'TT'I` State e `T'I__` i > ( `yok` Await ) : World `J'T'TT'I` State e `T'I__` World i `AR____` World `J'T'TT'I` State e `T'I__` i

Let's start with a simple example and gradually add more features - we can statefully update ASCII from console input:

> ... = Pass `ryo` Enter @ ( World `J'T'TT'I` State `T'TT` Maybe `T'I` ASCII ) >> `yok'ut` Await `har` input >> `yok` Allot `ha` State `ha` Event `ha` Swap

Now we want to keep many ASCII characters instead of possible one so that each new character from console input is pushed onto the top of List:

> ... = Pass `ryo` Enter @ ( World `J'T'TT'I` State `T'TT` List `T'I` ASCII ) >> `yok__'ut` Await `har` input >> `yok__` Allot `ha` State `ha___` Event `ha` Swap `ho__'ha` Scope `har` within `ha` Fresh

These are basic examples of jointed functor compositions, in the next chapter we will use more complex ones with different behaviour labels.