[swift-evolution] [Proposal] Higher Kinded Types (Monads, Functors, etc.)

Elviro Rocca retired.hunter.djura at gmail.com
Sun Dec 11 07:48:43 CST 2016


Hi everyone, I read every post in the Higher-Kinded Types ( https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002736.html <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/002736.html> ) thread from about a year ago, and I was wondering what's the status on the matter: I'm aware of the proposal draft ( https://github.com/typelift/swift/issues/1 <https://github.com/typelift/swift/issues/1> ), but I'd like to know if the Swift team has reconsidered the possible relevance of HKT for Swift in the foreseeable future.

By reading the discussion I found that the main concern from the Swift team was about practical use cases that could be of interest for a huge chunk of Swift developers: I don't think that a language feature should be there only if affects the majority of users, because of course you always have users at many different levels of awareness and understanding, not to mention experience and background, but I understand that, considering the time constraints in language development and proposals review, the focus should (initially) be on things that matter the most to the vast majority of developers.

But the idea of opposing a proposal because it's "hard to understand" (to some people, with different background) is baffling to me: there could be NO evolution whatsoever if everyone's only focus was on what feels familiar. But I don't want to talk about this: I just want to mention that if someone argues that they're not understanding a construct even if they consider themselves smart and experienced, that's their problem (maybe they're simply non experienced in that particular field), not a problem of the construct itself. And the fact that most things are mappable is not something functional programmers "believe": there's a huge corpus of research in the field of abstract mathematics that confirms this intuition. But anyway, let's move on.

I'd like to mention something that I consider a practical use case for the need of being able to express something like mappables and flatMappables in a abstract way: what's usually referred to as "monad transformers". I know that it's another concept that can be hard to grasp if you're not used to work with monads, but bear with me. Also, not sure about the etiquette here: it's an old discussion, but I wanted to offer my two cents.

Many functional programming techniques try to achieve true composability of code by decomposing logic in generic classes, that express a particular piece of that logic: the "Result" type  ( https://github.com/antitypical/Result <https://github.com/antitypical/Result> ) is a classic case (the same concept is similarly implemented by Swift throwable functions, but in a less composable way). There are many more types that do this, for example the Deferred type ( https://github.com/bignerdranch/Deferred <https://github.com/bignerdranch/Deferred> ) was also mentioned in the discussion. Another type that I use a lot is the Writer type ( https://en.wikipedia.org/wiki/Monad_(functional_programming)#Writer_monad <https://en.wikipedia.org/wiki/Monad_(functional_programming)#Writer_monad> ) that lets me accumulate an auxiliary result while executing an algorithm ( for example, generating an index path while traversing a tree ). And the Optional type is already in Swift. But while these types are useful by themselves, they become even more powerful when combined: for example, Deferred + Result is basically a Future, that is, an asynchronous computation that can fail. Even more interesting is a Deferred + Writer + Result (I going to refer to it as "DefWriRes"), something that I currently use while developing my HTTP clients, because I can accumulate information about request and response in a clean, composable way: unfortunately, mapping and flatMapping breaks when combining these types, because mapping a DefWriRes will require a function working on Writer, while I really just work on the type wrapped by the internal Result. Monad transformers work that way: they allow you to "go deeper" in combined monads. Now, the interesting thing is that to map a DefWriRes we only need to now that Deferred, Writer and Result are mappable, but without this abstraction I'm forced to copy and paste hundreds of lines of code (for every possible combination) where the only thing that changes is the type definition, because the method calls are just maps.

The case is similar for flatMap, so I need to call "flatMap" on something that's flatMappable, with the difference that I need to be able to unwrap the value in the Result (so I need to know how Result works, it's not just mapping), and I need to be able to create a "empty" Writer and Deferred (that's already achievable by the type system). But the case is similar, the only difference is that I need a specific "ResultTransformer" (I actually implemented this via protocols and constrained extensions, but the implementation details are not relevant for the case).

So what's the use case? If I was able to generically express a mappable and a flatMappable, I could combine those things multiple times at any level without rewriting the same almost identical code for every combination. And even if you're not a functional programmer, types like these are very useful to clearly and cleanly express the semantics of your code: in fact, the Optional type is extremely useful exactly for this, and I'm thankful for the fact that it is in the standard library, along with the respective map and flatMap methods.

What do you think? Thanks


Elviro
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161211/c98856bb/attachment.html>


More information about the swift-evolution mailing list