could someone explain the connection between type covariance/contravariance and category theory? - covariance

I am just starting to read about category theory, and would very much appreciate it if someone could explain the connection between CS contravariance/covariance and category theory. What would some example categories be (i.e. what are their objects/morphisms?)? Thanks in advance?

A contravariant functor from $C$ to $D$ is the exact same thing as a normal (i.e. covariant) functor from $C$ to $D^{op}$, where $D^{op}$ is the opposite category of $D$. So it's probably best to understand opposite categories first -- then you'll automatically understand contravariant functors!
Contravariant functors don't come up all that often in CS, although I can think of two exceptions:
You may have heard of contravariance in the context of subtyping. Although this is technically the same term, the connection is really, really weak. In object oriented programming, the classes form a partial order; every partial order is a category with "binary hom-sets" -- given any two objects $A$ and $B$, there is exactly one morphism $A\to B$ iff $A\leq B$ (note the direction; this slightly-confusing orientation is the standard for reasons I won't explain here) and no morphisms otherwise.
Parameterized types like, say, Scala's PartialFunction[-A,Unit] are functors from this simple category to itself... we usually focus on what they do to objects: given a class X, PartialFunction[X,Unit] is also a class. But functors preserve morphisms too; in this case if we had a subclass Dog of Animal, we would have a morphism Dog$\to$Animal, and the functor would preserve this morphism, giving us a morphism PartialFunction[Animal,Unit]$\to$PartialFunction[Dog,Unit], telling us that PartialFunction[Animal,Unit] is a subclass of PartialFunction[Dog,Unit]. If you think about that, it makes sense: suppose you have a situation where you need a function that works on Dogs. A function that works on all Animals would certainly work there!
That said, using full-on category theory to talk about partially ordered sets is big-time overkill.
Less common, but actually uses the category theory: consider the category Types(Hask) whose objects are the types of the Haskell programming language and where a morphism $\tau_1\to\tau_2$ is a function of type $\tau_1$->$\tau_2$. There is also a category Judgments(Hask) whose objects are lists of typing judgments $\tau_1\vdash\tau_2$ and whose morphisms are proofs of all the judgments on one list using the judgments on the other list as hypotheses. There is a functor from Types(Hask) to Judgments(Hask) which takes a Types(Hask)-morphism $f:A\to B$ to the proof
B |- Int
----------
......
----------
A |- Int
which is a morphism $(B\vdash Int)\to(A\vdash Int)$ -- notice the change of direction. Basically what this is saying is that if you've got a function that turns A's into B'a, and an expression of type Int with a free variable x of type B, then you can wrap it with "let x = f y in ..." and arrive at an expression still of type Int but whose only free variable is of type $A$, not $B$.

There are very nice videos about contravariance/covariance in Going deep channel in Microsoft Channel9. You can start here:
E2E: Brian Beckman and Erik Meijer - Co/Contravariance in Physics and Programming, 1 of 3
E2E: Brian Beckman and Erik Meijer - Co/Contravariance in Physics and Programming, 2 of 3
E2E: Brian Beckman and Erik Meijer - Co/Contravariance in Physics and Programming, 3 of n
E2E: Whiteboard Jam Session with Brian Beckman and Greg Meredith - Monads and Coordinate Systems

Related

Why is FunctionK not the same as a Natural Transformation

The cats documentation on FunctionK contains:
Thus natural transformation can be implemented in terms of FunctionK. This is why a parametric polymorphic function FunctionK[F, G] is sometimes referred as a natural transformation. However, they are two different concepts that are not isomorphic.
What's an example of a FunctionK which isn't a Natural Transformation (or vice versa)?
It's not clear to me whether this statement is implying F and G need to have Functor instances, for a FunctionK to be a Natural Transformation.
The Wikipedia article on Natural Transformations says that the Commutative Diagram can be written with a Contravariant Functor instead of a Covariant Functor, which to me implies that a Functor instance isn't required?
Alternatively, the statement could be refering to impure FunctionKs, although I'd kind of expect analogies to category theory breaking down in the presence of impurity to be a given; and not need explicitly stating?
When you have some objects (from CT) in one category and some objects in another category, and you are able to come up with a way show that each object and arrow between objects has a correspondence in later then you can say that there is a functor from one to another. In less strict language: you can say that there is a functor from A to B if you can find a "subgraph" in B that has the same shape as A.
In such case you can "zoom out": draw a point, call it object representing category A, draw another, call it object representing B, and draw an arrow and call it functor.
If there are many ways you can do it, you can have multiple functors. And with more categories you can combine these functors like you compose arrows. Which in this "zoomed out" world look like normal objects and arrows. And you can form categories with them. If you can find a mapping between these categories, a functor on functors, then this is a natural transformation.
When it comes to functional programming you don't work in such generic framework. Usually, you assume that:
object is a type
arrow is a function
to define a category you almost always would have to use a generic type, or else it would be too specific to be useful as a general purpose library (isomorphism between e.g. possible transitions of one enum into transition states of another enum could be a functor, but that wouldn't necessarily fit some generic interface)
since programming languages cannot let you define a generic mapping between two arbitrary types, functors that you'll see will be almost exclusively Id ~> F: you can lift a function A => B into List[A] => List[B], Future[A] => Future[B] and so one easily (this proves existence of F[A] -> F[B] arrow for given A -> B arrow, and if A and B are generic you provided a proof for all arrows from Id), but try finding something more complex than "given A, add a wrapper around it to get F[A]" and it's a challenge
similarly the only natural transformations you'll see will be from Id ~> F into Id ~> G that is "given A, change the wrapper type from F[A] to G[A]", because you have a guarantee that there is the same A hidden somehow in both F and G and you don't have to deal with modifying it (only with modifying the wrapper)
The latter being exactly a FunctionK or just a polymorphic function in Scala 3: [A] => F[A] => G[A]. A concept from type theory rather than from CT (although in mathematics a lot of concepts map into each other, like here it FunctionK maps to natural transformation where objects represent types and arrows functions between them).
Category theory isn't so restrictive. As a matter of the fact, isn't even rooted in computer science and was not created with functional programmers in mind. Let's create non-FunctionK natural transformation which models some operation on "state machines" implementation:
object is a state in state machine of sort (let's say enum value)
arrow is a legal transition from one state to another (let say you can model it as a pair of enum values, and it somehow incorporates transitivity)
when you have 2 models of state machines with different enums, BUT you can take one model: one enum and allowed pairs and translate it to another model: another enum and its pair, you have a functor. one that doesn't implement cats.Functor but still
let's say you would model it with some class Translate[Enum1, Enum2] {...} interface
let's say that this translation also extends the model with some functionality, so it's actually Translate[Enum1, Enum2 | ExtensionX]
now, build another extension Translate[Enum1, Enum2 | ExtensionY]
if you can somehow convert Translate[A, B | ExtensionX] into Translate[A, B | ExtensionY] for a whole category of enums (described as A and B) then this would be a natural transformation
notice that it would not fit FunctionK just like Translate doesn't fit Functor
It's a bit stretched example, also hardly anyone implementing an isomorphisms between state machines would reach for functor as a way to describe it, but it should show that natural transformation is not FunctionK. And why it's so rare to see functors and natural transformations different than Id ~> F lifts and (Id ~> F) ~> (Id ~> G) rewrappings.
PS. When it comes to Scala, you can also meet CT used as: object is a type, arrow is a subtyping relationship, thus covariant functors and contravariant functors appear in type parameters. Since "A is a subtype of B" translates to "A can be always upcasted to B", then these 2 interpretations of functors will often be mashed together - something along "don't define map if you cannot upcast and don't define contramap if you cannot downcast parameter" (see also narrow and widen operations in Cats).
PS2. Authors might be defending against hardcore-CT fans: from the point of view of CT Kleisli and ReaderT are 2 different things, yet in Cats they are combined together into a single Kleisli type for convenience. I saw some people complaining about it so maybe authors of the documentation felt that they need this disclaimer.
You can write down FunctionK-instances for things that aren't functors at all, neither covariant nor contravariant.
For example, given
type F[X] = X => X
you could implement a FunctionK[F, F] by
new FunctionK[F, F] {
def apply[X](f: F[X]): F[X] = f andThen f
}
Here, the F cannot be considered to be a functor, because X appears with both variances. Thus, you get something that's certainly a FunctionK, but the question whether it's a natural transformation isn't even valid to begin with.
Note that this example does not depend on whether you take the general CT-definition or the narrow FP-definition of what a "functor" is, the mapping F is simply not functorial.

A type constructor IS a monad or HAS a monad?

People usually say a type IS a monad.
In some functional languages and libraries (like Scala/Scalaz), you have a type constructor like List or Option, and you can define a Monad implementation that is separated from the original type. So basically there's nothing that forbids you in the type system from creating distinct instances of Monad for the same type constructor.
is it possible for a type constructor to have multiple monads?
if yes, can you provide any meaningful example of that? any "artificial" one?
what about monoids, applicatives... ?
You can commonly find this all around in mathematics.
A monad is a triple (T, return, bind) such that (...). When bind and return can be inferred from the context, we just refer to the monad as T.
A monoid is a triple (M, e, •) such that (...). (...) we just refer to the monoid as M.
A topological space is a pair (S, T) such that (...). We just refer to the topological space as S.
A ring is a tuple (V, 0, +, 1, ×)...
So indeed, for a given type constructor T there may be multiple different definitions of return and bind that make a monad. To avoid having to refer to the triple every time, we can give T different names to disambiguate, in a way which corresponds to the newtype construct in Haskell. For example: [] vs ZipList, State s vs ReaderT s (Writer s).
P.S. There is something artificial in saying that a monad or a monoid is a triple, especially given that there are different presentations: we could also say that a monad is a triple (T, fmap, join), or that a monoid is a pair (M, •), with the identity element hidden in the extra condition (because it is uniquely determined by • anyway). The ontology of mathematical structures is a more philosophical question that is outside the scope of SO (as well as outside my expertise). But a more prudent way to reformulate such definitions may be to say that "a monad is (defined|characterized) by a triple (T, return, bind)".
Insofar as you're asking about language usage, Google says that the phrase “has a monad” doesn't seem to be commonly used in the way you're asking about. Most real occurrences are in sentences such as, “The Haskell community has a monad problem.” However, a few cases of vaguely similar usage do exist in the wild, such as, “the only thing which makes it ‘monadic‘ is that it has a Monad instance.” That is, monad is often used as a synonym for monadic, modifying some other noun to produce a phrase (a monad problem, a Monad instance) that is sometimes used as the object of the verb have.
As for coding: in Haskell, a type can declare one instance of Monad, one of Monoid and so on. When a given type could have many such instances defined, such as how numbers are monoids under addition, multiplication, maximum, minimum and many other operations, Haskell defines separate types, such as Sum Int, a Monoid instance over Int where the operation is +, and Product Int, a Monoid instance where the operation is *.
I haven't comprehensively checked the tens of thousands of hits, though, so it's very possible there are better examples in there of what you're asking about.
The phrasing I've commonly seen for that is the one I just used: a type is a category under an operation.

What do you call the data wrapped inside a monad?

In speech and writing, I keep wanting to refer to the data inside a monad, but I don't know what to call it.
For example, in Scala, the argument to the function passed to flatMap gets bound to…er…that thing inside the monad. In:
List(1, 2, 3).flatMap(x => List(x, x))
x gets bound to that thing I don't have a word for.
Complicating things a bit, the argument passed to the Kleisli arrow doesn't necessarily get bound to all the data inside the monad. With List, Set, Stream, and lots of other monads, flatMap calls the Kleisli arrow many times, binding x to a different piece of the data inside the monad each time. Or maybe not even to "data", so long as the monad laws are followed. Whatever it is, it's wrapped inside the monad, and flatMap passes it to you without the wrapper, perhaps one piece at a time. I just want to know what to call the relevant inside-the-monad stuff that x refers to, at least in part, so I can stop mit all this fumbly language.
Is there a standard or conventional term for this thing/data/value/stuff/whatever-it-is?
If not, how about "the candy"?
Trying to say "x gets bound to" is setting you up for failure. Let me explain, and guide you towards a better way of expressing yourself when talking about these sorts of things.
Suppose we have:
someList.flatMap(x => some_expression)
If we know that someList has type List[Int], then we can safely say that inside of some_expression, x is bound to a value of type Int. Notice the caveat, "inside of some_expression". This is because, given someList = List(1,2,3), x will take on the values of each of them: 1, 2, and 3, in turn.
Consider a more generalized example:
someMonadicValue.flatMap(x => some_expression)
If we know nothing about someMonadicValue, then we don't know much about how some_expression is going to be invoked. It may be run once, or three times (as in the above example), or lazily, or asynchronously, or it may be scheduled for once someMonadicValue is finished (e.g. futures), or it may never be used (e.g. empty list, None). The Monad interface does not include reasoning about when or how someExpression will be used. So all you can say about what x will be is confined to the context of some_expression, whenever and however some_expression happens to be evaluated.
So back to the example.
someMonadicValue.flatMap(x => some_expression)
You are trying to say "x is the ??? of someMonadicValue." And you are looking for the word that accurately replaces ???. Well I'm here to tell you that you're doing it wrong. If you want to speak about x, then either do it
Within the context of some_expression. In this case, use the bolded phrase I gave you above: "inside of some_expression, x is bound to a value of type Foo." Or, alternatively, you can speak about x...
With additional knowledge about which monad you're dealing with.
In case #2, for example, for someList.flatMap(x => some_expression), you could say that "x is each element of someList." For someFuture.flatMap(x => some_expression), you could say that "x is the successful future value of someFuture, if it indeed ever completes and succeeds."
You see, that's the beauty of Monads. That ??? that you are trying to describe, is the thing which the Monad interface abstracts over. Now do you see why it's so difficult to give ??? a name? It's because it has a different name and a different meaning for each particular monad. And that's the point of having the Monad abstraction: to unify these differing concepts under the same computational interface.
Disclaimer: I'm definitely not an expert in functional programming terminology and I expect that the following will not be an answer to your question from your point of view. To me the problem rather is: If choosing a term requires expert knowledge, so does understanding.
Choosing an appropriate term largely depends on:
your desired level of linguistic correctness, and
your audience, and the corresponding connotations of certain terms.
Regarding the linguistic correctness the question is whether you properly want to refer to the values/data that are bound to x, or whether you can live with a certain (incorrect) abstraction. In terms of the audience, I would mainly differentiate between an audience with a solid background in functional programming and an audience coming from other programming paradigms. In case of the former, choosing the term is probably not entirely crucial, since the concept itself is familiar, and many terms would lead to the right association. The discussion in the comments already contains some very good suggestions for this case. However, the discussion also shows that you need a certain background in functional programming to see the rationale behind some terms.
For an audience without a background in functional programming, I would rather sacrifice linguistic correctness in favor of comprehensibility. In such a situation I often just refer to it as "underlying type", just to avoid any confusion that I would probably create by trying to refer to the "thing(s) in the monad" itself. Obviously, it is literally wrong to say "x is bound to the underlying type". However, it is more important to me that my audience understands a concept at all. Since most programmers are familiar with containers and their underlying types, I'm aiming for the (flawed) association "underlying type" => "the thing(s) that are in a container" => "the thing(s) inside a monad", which often seems to work.
TL;DR: There always is a trade-off between correctness and accessibility. And when it comes to functional programming, it is sometimes helpful to shift the bias towards the latter.
flatMap does not call the Kleisli arrow many times. And "that thing" is not "inside" the monad.
flatMap lifts a Kleisli arrow to the monad. You could see this as the construction of an arrow M[A] => M[B] between types (A, B) lifted to the monad (M[A], M[B]), given a Kleisli arrow A => M[B].
So x in x => f(x) is the value being lifted.
What data?
data Monady a = Monady
Values of monads are values of monads, their wrapped type may be entirely a fiction. Which is to say that talking about it as if it exists may cause you pain.
What you want to talk about are the continuations like Monad m => a -> m b as they are guaranteed to exist. The funny stuff occurs in how (>>=) uses those continuations.
'Item' seems good? 'Item parameter' if you need to be more specific.
Either the source data can contain multiple items, or the operation can call it multiple times. Element would tend to be more specific for the first case, Value is singular as to the source & not sensible for list usages, but Item covers all cases correctly.
Disclaimer: I know more about understandable English than about FP.
Take a step back here.
A monad isn't just the functor m that wraps a value a. A monad is the stack of endofunctors (i.e., the compositions of m's), together with the join operator. That's where the famous quip -- that a monad is a monoid in the category of endofunctors, what's the problem? -- comes from.
(The whole story is that the quip means the composition of m's is another m, as witnessed by join)
A thing with the type (m a) is typically called a monad action. You can call a the result of the action.

What are practical uses of applicative style?

I am a Scala programmer, learning Haskell now. It's easy to find practical use cases and real world examples for OO concepts, such as decorators, strategy pattern etc. Books and interwebs are filled with it.
I came to the realization that this somehow is not the case for functional concepts. Case in point: applicatives.
I am struggling to find practical use cases for applicatives. Almost all of the tutorials and books I have come across so far provide the examples of [] and Maybe. I expected applicatives to be more applicable than that, seeing all the attention they get in the FP community.
I think I understand the conceptual basis for applicatives (maybe I am wrong), and I have waited long for my moment of enlightenment. But it doesn't seem to be happening. Never while programming, have I had a moment when I would shout with a joy, "Eureka! I can use applicative here!" (except again, for [] and Maybe).
Can someone please guide me how applicatives can be used in a day-to-day programming? How do I start spotting the pattern? Thanks!
Applicatives are great when you've got a plain old function of several variables, and you have the arguments but they're wrapped up in some kind of context. For instance, you have the plain old concatenate function (++) but you want to apply it to 2 strings which were acquired through I/O. Then the fact that IO is an applicative functor comes to the rescue:
Prelude Control.Applicative> (++) <$> getLine <*> getLine
hi
there
"hithere"
Even though you explicitly asked for non-Maybe examples, it seems like a great use case to me, so I'll give an example. You have a regular function of several variables, but you don't know if you have all the values you need (some of them may have failed to compute, yielding Nothing). So essentially because you have "partial values", you want to turn your function into a partial function, which is undefined if any of its inputs is undefined. Then
Prelude Control.Applicative> (+) <$> Just 3 <*> Just 5
Just 8
but
Prelude Control.Applicative> (+) <$> Just 3 <*> Nothing
Nothing
which is exactly what you want.
The basic idea is that you're "lifting" a regular function into a context where it can be applied to as many arguments as you like. The extra power of Applicative over just a basic Functor is that it can lift functions of arbitrary arity, whereas fmap can only lift a unary function.
Since many applicatives are also monads, I feel there's really two sides to this question.
Why would I want to use the applicative interface instead of the monadic one when both are available?
This is mostly a matter of style. Although monads have the syntactic sugar of do-notation, using applicative style frequently leads to more compact code.
In this example, we have a type Foo and we want to construct random values of this type. Using the monad instance for IO, we might write
data Foo = Foo Int Double
randomFoo = do
x <- randomIO
y <- randomIO
return $ Foo x y
The applicative variant is quite a bit shorter.
randomFoo = Foo <$> randomIO <*> randomIO
Of course, we could use liftM2 to get similar brevity, however the applicative style is neater than having to rely on arity-specific lifting functions.
In practice, I mostly find myself using applicatives much in the same way like I use point-free style: To avoid naming intermediate values when an operation is more clearly expressed as a composition of other operations.
Why would I want to use an applicative that is not a monad?
Since applicatives are more restricted than monads, this means that you can extract more useful static information about them.
An example of this is applicative parsers. Whereas monadic parsers support sequential composition using (>>=) :: Monad m => m a -> (a -> m b) -> m b, applicative parsers only use (<*>) :: Applicative f => f (a -> b) -> f a -> f b. The types make the difference obvious: In monadic parsers the grammar can change depending on the input, whereas in an applicative parser the grammar is fixed.
By limiting the interface in this way, we can for example determine whether a parser will accept the empty string without running it. We can also determine the first and follow sets, which can be used for optimization, or, as I've been playing with recently, constructing parsers that support better error recovery.
I think of Functor, Applicative and Monad as design patterns.
Imagine you want to write a Future[T] class. That is, a class that holds values that are to be calculated.
In a Java mindset, you might create it like
trait Future[T] {
def get: T
}
Where 'get' blocks until the value is available.
You might realize this, and rewrite it to take a callback:
trait Future[T] {
def foreach(f: T => Unit): Unit
}
But then what happens if there are two uses for the future? It means you need to keep a list of callbacks. Also, what happens if a method receives a Future[Int] and needs to return a calculation based on the Int inside? Or what do you do if you have two futures and you need to calculate something based on the values they will provide?
But if you know of FP concepts, you know that instead of working directly on T, you can manipulate the Future instance.
trait Future[T] {
def map[U](f: T => U): Future[U]
}
Now your application changes so that each time you need to work on the contained value, you just return a new Future.
Once you start in this path, you can't stop there. You realize that in order to manipulate two futures, you just need to model as an applicative, in order to create futures, you need a monad definition for future, etc.
UPDATE: As suggested by #Eric, I've written a blog post: http://www.tikalk.com/incubator/blog/functional-programming-scala-rest-us
I finally understood how applicatives can help in day-to-day programming with that presentation:
https://web.archive.org/web/20100818221025/http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/chunk-html/index.html
The autor shows how applicatives can help for combining validations and handling failures.
The presentation is in Scala, but the author also provides the full code example for Haskell, Java and C#.
Warning: my answer is rather preachy/apologetic. So sue me.
Well, how often in your day-to-day Haskell programming do you create new data types? Sounds like you want to know when to make your own Applicative instance, and in all honesty unless you are rolling your own parser, you probably won't need to do it very much. Using applicative instances, on the other hand, you should learn to do frequently.
Applicative is not a "design pattern" like decorators or strategies. It is an abstraction, which makes it much more pervasive and generally useful, but much less tangible. The reason you have a hard time finding "practical uses" is because the example uses for it are almost too simple. You use decorators to put scrollbars on windows. You use strategies to unify the interface for both aggressive and defensive moves for your chess bot. But what are applicatives for? Well, they're a lot more generalized, so it's hard to say what they are for, and that's OK. Applicatives are handy as parsing combinators; the Yesod web framework uses Applicative to help set up and extract information from forms. If you look, you'll find a million and one uses for Applicative; it's all over the place. But since it's so abstract, you just need to get the feel for it in order to recognize the many places where it can help make your life easier.
I think Applicatives ease the general usage of monadic code. How many times have you had the situation that you wanted to apply a function but the function was not monadic and the value you want to apply it to is monadic? For me: quite a lot of times!
Here is an example that I just wrote yesterday:
ghci> import Data.Time.Clock
ghci> import Data.Time.Calendar
ghci> getCurrentTime >>= return . toGregorian . utctDay
in comparison to this using Applicative:
ghci> import Control.Applicative
ghci> toGregorian . utctDay <$> getCurrentTime
This form looks "more natural" (at least to my eyes :)
Coming at Applicative from "Functor" it generalizes "fmap" to easily express acting on several arguments (liftA2) or a sequence of arguments (using <*>).
Coming at Applicative from "Monad" it does not let the computation depend on the value that is computed. Specifically you cannot pattern match and branch on a returned value, typically all you can do is pass it to another constructor or function.
Thus I see Applicative as sandwiched in between Functor and Monad. Recognizing when you are not branching on the values from a monadic computation is one way to see when to switch to Applicative.
Here is an example taken from the aeson package:
data Coord = Coord { x :: Double, y :: Double }
instance FromJSON Coord where
parseJSON (Object v) =
Coord <$>
v .: "x" <*>
v .: "y"
There are some ADTs like ZipList that can have applicative instances, but not monadic instances. This was a very helpful example for me when understanding the difference between applicatives and monads. Since so many applicatives are also monads, it's easy to not see the difference between the two without a concrete example like ZipList.
I think it might be worthwhile to browse the sources of packages on Hackage, and see first-handedly how applicative functors and the like are used in existing Haskell code.
I described an example of practical use of the applicative functor in a discussion, which I quote below.
Note the code examples are pseudo-code for my hypothetical language which would hide the type classes in a conceptual form of subtyping, so if you see a method call for apply just translate into your type class model, e.g. <*> in Scalaz or Haskell.
If we mark elements of an array or hashmap with null or none to
indicate their index or key is valid yet valueless, the Applicative
enables without any boilerplate skipping the valueless elements while
applying operations to the elements that have a value. And more
importantly it can automatically handle any Wrapped semantics that
are unknown a priori, i.e. operations on T over
Hashmap[Wrapped[T]] (any over any level of composition, e.g. Hashmap[Wrapped[Wrapped2[T]]] because applicative is composable but monad is not).
I can already picture how it will make my code easier to
understand. I can focus on the semantics, not on all the
cruft to get me there and my semantics will be open under extension of
Wrapped whereas all your example code isn’t.
Significantly, I forgot to point out before that your prior examples
do not emulate the return value of the Applicative, which will be a
List, not a Nullable, Option, or Maybe. So even my attempts to
repair your examples were not emulating Applicative.apply.
Remember the functionToApply is the input to the
Applicative.apply, so the container maintains control.
list1.apply( list2.apply( ... listN.apply( List.lift(functionToApply) ) ... ) )
Equivalently.
list1.apply( list2.apply( ... listN.map(functionToApply) ... ) )
And my proposed syntactical sugar which the compiler would translate
to the above.
funcToApply(list1, list2, ... list N)
It is useful to read that interactive discussion, because I can't copy it all here. I expect that url to not break, given who the owner of that blog is. For example, I quote from further down the discussion.
the conflation of out-of-statement control flow with assignment is probably not desired by most programmers
Applicative.apply is for generalizing the partial application of functions to parameterized types (a.k.a. generics) at any level of nesting (composition) of the type parameter. This is all about making more generalized composition possible. The generality can’t be accomplished by pulling it outside the completed evaluation (i.e. return value) of the function, analogous to the onion can’t be peeled from the inside-out.
Thus it isn’t conflation, it is a new degree-of-freedom that is not currently available to you. Per our discussion up thread, this is why you must throw exceptions or stored them in a global variable, because your language doesn’t have this degree-of-freedom. And that is not the only application of these category theory functors (expounded in my comment in moderator queue).
I provided a link to an example abstracting validation in Scala, F#, and C#, which is currently stuck in moderator queue. Compare the obnoxious C# version of the code. And the reason is because the C# is not generalized. I intuitively expect that C# case-specific boilerplate will explode geometrically as the program grows.

What is a "multisorted algebra", and how do I use it to solve "real problems"?

Apparently, Alexander Stepanov has stated the following in an interview:
“I find OOP [object-oriented programming] technically unsound. It attempts to decompose the world in terms of interfaces that vary on a single type. To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types.” [Emphasis added.]
Ignoring his statement regarding OOP for a moment, what are "multisorted algebras", beyond his terse definition, and can you give a practical example of how they are used (in the language of your choice)?
I believe he was talking about generic programming (he coined the term), whether meant in the context of this talk about the STL, or 'at large', in the sense of:
programming against a sort of interface that describes something that could fit all (and hopefully several) types (hence multi-sorted), ...
... provided they have some properties, often something about the nature of some operations on elements of that type (hence algebras).
To do (1), you need to have a way to specify a program that takes a type as a parameter, i.e. polymorphism, and to do (2), you need a way to say that you also want that type to carry specific operations (and, provided you can express them, properties). In effect, you're parametrizing your program by the structure of the data it manipulates. The paradigm is called in some places bounded polymorphism, datatype-generic programming, ... which reflects that languages have different notions of how to implement that idea — hence the italicized 'sort of' above.
For C++, it seems that —to Stepanov at least— this corresponds to templates (though ideas on how to do this best are still evolving).
For OO languages (Generic Java, C#), constraints on type parameters are typically expressed using subtype bounds ('bounded wildcards' ...).
For Haskell or Scala, you have (respectively, and similarly) type classes or implicits.
The ML family of languages prefers to do this using modules.
note that a number of proof assistants (which can express 'honest-to-god' properties as types) have developed a flavor of type classes : Isabelle, Coq, Matita are such examples
Note that Stepanov just co-wrote an entire book giving an exhaustive development of a library that embodies exactly what (I think) he means. So if you want examples in C++, this is definitely where you should look. Note also that this is much more evolved than the now-common advice of coding against an interface, rather than an object.
By 'practical example', I don't know if you mean 'how' or 'why' does one uses it. To give a caricaturally quick answer to the 'why', genericity is nice because, a bit like run-of-the-mill polymorphism, it lets you reuse code. But, more importantly:
polymorphic code that has to work with every single type often can't do anything interesting, whereas having a constrained interface to play with allows you to write richer programs
by specifying how that interface fits some your data, you have a type-safe way to select just those elements that suit your needs. For example, you probably know that the reduction operator (the reduce of Python & Hadoop, fold of a bunch of functional languages) is parallelizable only if the order in which you apply your reduction function doesn't matter (+, x, min, and work, but set difference doesn't). If you have a notion of 'type equipped with an associative operation', you know that you will be able to call a parallel reduction on it.
any overhead incurred by genericity occurs at compile time. For example, templates are legendarily fast
If you have seen some generic Java, look at say, the Comparable generic interface. It defines just one operation, but the contract it makes, though basic, is very much of algebraic flavor. I quote:
For the mathematically inclined, the relation that defines the natural ordering on a given class C is:
{(x, y) such that x.compareTo((Object)y) <= 0}.
The quotient for this total order is:
{(x, y) such that x.compareTo((Object)y) == 0}.
It follows immediately from the contract for compareTo that the quotient is an equivalence relation on C, > and that the natural ordering is a total order on C.
Now, I can write a method that selects the minimum, once, and use it for any type that fits this interface:
public static <T extends Comparable<T>> T min (T x, T y) {
if (x.compare(y) < 0) x; else y;
}
Naturally, since the way programmative constructs implement that notion varies wildly, what you will get in terms of usability & expressivity will also vary. Perhaps you should not judge data-generic programming just by OO languages like C++ or Java ­— but I've written too much already to start with module ascription or the automatic instance generation of type classes.
I'm too late, but maybe it will be helpful for you. User huitseeker wrote an excellent answer from the viewpoint of software design. I want to answer your question from the viewpoint of mathematics. Before diving into software world Alex Stepanov was a mathematician and studied abstract and universal algebra. And he often tried to bring rigorous mathematical foundations into the world of software and algorithm design. In his books From Mathematics to Generic Programming and Elements of Programming he advocates this design practice. His ideas about mixing concepts of algebraic structures and software design were realised in the notion of generic programming. And now let's talk about his quote:
To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types
In my opinion there are two main concepts he wanted to mention here: the idea of abstract data type (ADT) and algebraic structure. First concept: ADT. ADT - is a mathematical model for a data types where a data type is defined only by it's semantic. Stepanov contrasted the idea of ADT to the idea of object in the OOP sense. Objects contains data and state whilst ADTs - not. ADT - is a behavioural abstraction, an operation cluster which describes interaction with data. Behavioural abstraction is entirely described by means of algebraic specification of abstract data type. You can read about this more in the original Liskov and Zilles paper, also I recommend you a paper Object-Oriented Programming Versus Abstract Data Types by William R. Cook.
(Discalimer: you can skip this paragraph, because it is more "mathematical and not so important") At first I want to clarify some terminology. When I talk about the algebraic structure it is the same as algebra. The word algebra is often also used for an algebraic structure. To be more precise when we talk about algebraic structures (algebras) we usually mean algebra over an algebraic theory. There is a concept of the variety of algebras, because there are several notions of an algebraic structure on an object of some category. By definition, an algebraic theory (algebra over it) consists of a specification of operations and laws that these operations must satisfy: this is a working definition of the algebraic structure we will use, and this definition ,I think, Stepanov implicitly mentioned in the quote.
Second concept which Stepanov wanted to mention is the most interesting property of ADTs: they can be formally modelled directly as many-sorted algebraic structures. Let's talk about it more formally. An algebraic structure - is a carrier set with one or more finitary operations defined on it. These operations are usually defined not over one set but over the multiple ones. E.g. let's define and algebra which models string concatenation. This algebra will be defined not over one set of strings but over two sets: strings set S and natural numbers set N, because we can define an operation which can concatenate a string with itself some finite number of times. So, this operation will take two operands, which belongs to different underlying (carrier) sets: S and N. Set which define these different operands (their types) in algebra called a set of sorts. Sort is an algebraical analog of the type. Algebra with multiple sorts called a multi-sorted algebra. In universal algebra, a signature lists the operations that characterize an algebraic structure. A many-sorted algebraic structure can have an arbitrary number of domains. The sorts are part of the signature, and they play the role of names for the different domains. Many-sorted signatures also prescribe on which sorts the functions and relations of a many-sorted algebraic structure are defined. For a one-sorted variety of algebras a signature is a set, whose elements are called operations, to each of which is assigned a cardinal number (0,1,2,…) called its arity. A signature of multi-sorted algebra can be defined as Σ = (S,OP,A), where S – set of sort names (types), OP - set of operation names and A - arities as before, except that now an arity is a list (sequence or more generally free monoid) of input sorts instead of merely a natural number (the length of the list) together with one output sort. Now we can create an algebraic specification of an abstract data type ADT as a triple:
ADT = (N, Σ, E)
, where N - name of abstract data type, Σ = (S,OP,A) - signature of multi-sorted algebraic structure, E = {e1, e2, …,en} - is a finite collection of equalities in the signature. As can you see now we have a rigorous mathematical description of ADT. In mathematics many-sorted algebraic structures are often used as a convenient tool even when they could be avoided with a little effort. Many-sorted algebraic structures are rarely defined in a rigorous way, because it is straightforward to carry out the generalization explicitly. That's why theory of many-sorted algebras can be successfully applied to software design.
So, Alex Stepanov wanted to say that he prefer ADTs and generic programming to OOP, because thus we can create programs with rigorous mathematical/algebraical foundations. I appreciate his efforts a lot. We all know that algebraical design is always correct, rigorous, beautiful, simple and gives us better abstractions.
Not that I am an expert with the theory of any of those but let's take a look at the quote so that I can try to give my practical understanding to add to the discussion.
To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types.
From my readings, I think families of interfaces that span multiple types sounds a lot like type classes from Haskell, which is similar to concepts from C++. Take a type class like Foldable it actually is a type parametrized interface, ie. a familiy of interfaces that span multiple types. So about your question of how to solve problems with multisorted algebras, generic programming is all about that if you take it to mean type classes or concepts.