diff --git a/_posts/2017-10-4-from-design-patterns-to-category-theory.html b/_posts/2017-10-4-from-design-patterns-to-category-theory.html index 6692daec..572841b0 100644 --- a/_posts/2017-10-4-from-design-patterns-to-category-theory.html +++ b/_posts/2017-10-4-from-design-patterns-to-category-theory.html @@ -254,7 +254,7 @@

  • Natural transformations
  • Functor products
  • Functor sums
  • -
  • Functor compositions
  • +
  • Functor compositions
  • Traversals
  • diff --git a/_posts/2018-03-19-functors-applicatives-and-friends.html b/_posts/2018-03-19-functors-applicatives-and-friends.html index 41d4854f..bcc542bc 100644 --- a/_posts/2018-03-19-functors-applicatives-and-friends.html +++ b/_posts/2018-03-19-functors-applicatives-and-friends.html @@ -117,7 +117,7 @@
  • Natural transformations
  • Functor products
  • Functor sums
  • -
  • Functor compositions
  • +
  • Functor compositions
  • Traversals
  • diff --git a/_posts/2022-07-11-functor-relationships.html b/_posts/2022-07-11-functor-relationships.html index 98b68a81..40a6d7bb 100644 --- a/_posts/2022-07-11-functor-relationships.html +++ b/_posts/2022-07-11-functor-relationships.html @@ -33,7 +33,7 @@

  • Natural transformations
  • Functor products
  • Functor sums
  • -
  • Functor compositions
  • +
  • Functor compositions
  • Traversals
  • diff --git a/_posts/2024-10-14-functor-sums.html b/_posts/2024-10-14-functor-sums.html index e1167f97..c6a330b3 100644 --- a/_posts/2024-10-14-functor-sums.html +++ b/_posts/2024-10-14-functor-sums.html @@ -250,7 +250,7 @@

    By now the pattern should be familiar. Call selector(v) directly on the 'naked' values, and pass selector to any other functors' Select method.

    - That's almost all the building blocks we have to declare BinaryTreeZipper<T> a functor as well, but we need one last theorem before we can do that. We'll conclude this work in the next article. + That's almost all the building blocks we have to declare BinaryTreeZipper<T> a functor as well, but we need one last theorem before we can do that. We'll conclude this work in the next article.

    Higher arities # @@ -318,6 +318,6 @@

    There's one more rule like this one.

    - Next: Functor compositions. + Next: Functor compositions.

    diff --git a/_posts/2024-08-20-functor-compositions.html b/_posts/2024-10-28-functor-compositions.html similarity index 91% rename from _posts/2024-08-20-functor-compositions.html rename to _posts/2024-10-28-functor-compositions.html index 61ee9dd5..7872aae3 100644 --- a/_posts/2024-08-20-functor-compositions.html +++ b/_posts/2024-10-28-functor-compositions.html @@ -2,7 +2,7 @@ layout: post title: "Functor compositions" description: "A functor nested within another functor forms a functor. With examples in C# and another language." -date: 2024-08-20 10:58 UTC +date: 2024-10-28 6:58 UTC tags: [Software Design, Functional Programming] --- {% include JB/setup %} @@ -21,10 +21,10 @@ Since functors tend to be quite common, and since they're useful enough that many programming languages have special support or syntax for them, the ability to recognize a potential functor can be useful. Given a type like Foo<T> (C# syntax) or Bar<T1, T2>, being able to recognize it as a functor can come in handy. One scenario is if you yourself have just defined this data type. Recognizing that it's a functor strongly suggests that you should give it a Select method in C#, a map function in F#, and so on.

    - Not all generic types give rise to a (covariant) functor. Some are rather contravariant functors, some are invariant, and some again are monomorphic. + Not all generic types give rise to a (covariant) functor. Some are rather contravariant functors, and some are invariant.

    - If, on the other hand, you have a data type where one functor is nested within another functor while sharing a type parameter, then the data type itself gives rise to a functor. You'll see some examples in this article. + If, on the other hand, you have a data type where one functor is nested within another functor, then the data type itself gives rise to a functor. You'll see some examples in this article.

    Abstract shape # @@ -139,16 +139,16 @@

    public T Item { get; }

    - Just like PriorityCollection<T> there's a 'naked' T value and a collection. The main difference is that here, the collection is of the same type as the object itself: Tree<T>. + Just like PriorityCollection<T> there's a collection, as well as a 'naked' T value. The main difference is that here, the collection is of the same type as the object itself: Tree<T>.

    - You've seen a similar example in the previous article, which also had a recursive data structure. If you assume, however, that Tree<T> gives rise to a functor, then so does the nested composition of putting it in a collection. This means, from the 'theorem' put forth in this article, that IReadOnlyCollection<Tree<T>> composes as a functor. Finally you have a product of a T (which is isomorphic to the Identity functor) and that composed functor. From Functor products it follows that that's a functor too, which explains why Tree<T> forms a functor. The article shows the Select implementation. + You've seen a similar example in the previous article, which also had a recursive data structure. If you assume, however, that Tree<T> gives rise to a functor, then so does the nested composition of putting it in a collection. This means, from the 'theorem' put forth in this article, that IReadOnlyCollection<Tree<T>> composes as a functor. Finally you have a product of a T (which is isomorphic to the Identity functor) and that composed functor. From Functor products it follows that that's a functor too, which explains why Tree<T> forms a functor. The article shows the Select implementation.

    Binary tree Zipper #

    - In both previous articles you've seen pieces of the puzzle explaining why the binary tree Zipper gives rise to functor. There's one missing piece, however, that we can now finally address. + In both previous articles you've seen pieces of the puzzle explaining why the binary tree Zipper gives rise to functor. There's one missing piece, however, that we can now finally address.

    Recall that BinaryTreeZipper<T> composes these two objects: @@ -196,7 +196,7 @@

    On the other hand, sometimes you need to work with a collection of generators, such as seq<Gen<'a>>.

    - These are all examples of functors within functors. It's not a given that you must treat such combinations as a functor in its own right. To be honest, typically, you don't. On the other hand, if you find yourself writing Select within Select, or map within map, depending on your language, it might make your code more succinct and readable if you give that combination a specialized functor affordance. + These are all examples of functors within functors. It's not a given that you must treat such a combination as a functor in its own right. To be honest, typically, you don't. On the other hand, if you find yourself writing Select within Select, or map within map, depending on your language, it might make your code more succinct and readable if you give that combination a specialized functor affordance.

    Higher arities # @@ -249,7 +249,7 @@

    This is useful to know, particularly if you're working in a language with only partial support for functors. Mainstream languages aren't going to automatically turn such stacks into functors, in the way that Haskell's Compose container almost does. Thus, knowing when you can safely give your generic types a Select method or map function may come in handy.

    - To be honest, though, this result is hardly the most important 'theorem' concerning stacks of functors. In reality, you often run into situation where you do have a stack of functors, but they're in the wrong order. You may have a collection of asynchronous tasks, but you really need an asynchronous task that contains a collection of values. The next article addresses that problem. + To be honest, though, this result is hardly the most important 'theorem' concerning stacks of functors. In reality, you often run into situations where you do have a stack of functors, but they're in the wrong order. You may have a collection of asynchronous tasks, but you really need an asynchronous task that contains a collection of values. The next article addresses that problem.

    Next: Traversals.