12 ms·
Swift Functors, Applicatives, and Monads in Pictures
- skybrian 11y agoIf functional languages had called them the Mappable, Applicable, and FlatMappable interfaces, and used map(), apply(), and flatMap() instead of operators, it would have avoided a lot of confusion. But I guess that's how you avoid success at all costs.
- mokagio 11y agoAhahah, that might be true :) Although because those concepts comes from category theory, i.e. https://en.wikipedia.org/wiki/Functor https://en.wikipedia.org/wiki/Functor and there's more to it than just "it defines" map, keeping the "academic" name seems fair enough.
- corysama 11y agoAre there any nice, one-step-at-a-time introductions to Haskell that stick to lowly, commonplace English rather than insisting that "just a monoid in the category of endofunctors" is universally preferable because technically it technically is technically more technically correct?
- chongli 11y agoI haven't read it but you might want to check out coolsunglasses'[0] book, Haskell Programming from first principles[1]. He wrote it specifically for people who have no background in this stuff. [0] https://news.ycombinator.com/user?id=coolsunglasses https://news.ycombinator.com/user?id=coolsunglasses [1] http://haskellbook.com/ http://haskellbook.com/
- ucarion 11y agoTo add to chongli's suggestion, I learned Haskell (and had a great time doing it) from "Learn You a Haskell": http://learnyouahaskell.com/ http://learnyouahaskell.com/
- wetmore 11y agoNobody insists "monoid in the category of endofunctors" is universally preferable. It's a joke. What you'll usually see people insist is to describe monads by their operations, rather than through metaphor. That is, a monad is a type parametrized by some other type, with the following two functions: 1) return :: a -> m a 2) (>>=) :: m a -> (a -> m b) -> m b such that three laws hold: a) return x >>= f == f x b) m >>= return == m c) (m >>= f) >>= g == m >>= (\x -> f x >>= g) For monads in Haskell, this is the technically correct definition. That said, most people will tell you the best way to understand monads is to look at a few basic monad instance implementations (Maybe, Either a) and program with them, slowly learning new instances.
- dllthomas 11y agoCleaning up the parent's formatting as I think it's too late for them to edit. Content is unchanged: That is, a monad is a type parametrized by some other type, with the following two functions: 1) return :: a -> m a 2) (>>=) :: m a -> (a -> m b) -> m b such that three laws hold: a) return x >>= f == f x b) m >>= return == m c) (m >>= f) >>= g == m >>= (\x -> f x >>= g)
- merijnv 11y agoTo be fair, I don't know a single person that explains things using > "just a monoid in the category of endofunctors" In fact, even among people who DO know the category theory necessary to understand this expression it's considered a very obtuse and useless explanation. Especially in the context of Haskell. As for good readable introductions, I consider Wadler's paper "Monads for Functional Programming" to actually be a pretty good introduction. Another good intro is "You Could Have Invented Monads! (And Maybe You Already Have.)" http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
- jameshart 11y agoThe problem is that the category-theory view of functors and monads and monoids completely dominates the literature. Imagine if, when you first started programming, and you wanted to do something with numbers, and you found out that in your programming language, the way you did that was to use something they called "Integers" (I know, right? ridiculous). So you google "Integers" and you find https://en.wikipedia.org/wiki/Integer https://en.wikipedia.org/wiki/Integer, which helpfully tells you "In elementary school teaching, integers are often intuitively defined as the disjoint union of the (positive) natural numbers, the singleton set whose only element is zero, and the negations of natural numbers."[1] And you get the impression that to add a couple of numbers together you're actually going to have to understand cardinality and group theory and so on. That's kind of where we are with monads, with the insistence on the academic language. Though it does suggest that I could have fun by persuading beginning programmers that to really grok text processing they need to start off with a thorough grounding in string theory. [1] I checked with my son, who goes to elementary school. I'm not sure he even knows what a disjoint union is. I'll have to have words with the teacher.
- LimpWristed 11y agoYou're over-exaggerating :) From the wiki link, the very first definition works just fine. In fact, I don't see anything about unions, disjointedness in there. Certainly, no group theory. You don't need to know how to construct, count(cardinality) or know the properties of integers(number/group theory) to know what they are for the purposes of programming. No, there's no cabal making everything more difficult than it needs to be ;D I think wiki always gets unfairly maligned for this sort of thing.
- TillE 11y agoI'd forgotten how spectacularly academic Wikipedia's math articles are. It actually seems a little better than it used to be, but for example good luck learning what the hell a quaternion is by reading the Wikipedia article, even if you have sufficient background to understand and use them in practice. The German article is much better.
- Ivanov 11y ago
- dustingetz 11y agoI don't think applicable is the same as apply, am I wrong?
- jfoutz 11y agoeh, it's close. if the semantics are apply(fun,args) it's not much of a mental stretch to do apply([fun1,fun2], [arg_for_fun1,arg_for_fun2]) it's probably better to just suck it up and learn the precise terms though. a lot of hazy thinking can hide behind overloaded words.
- jerf 11y agoHonest question: Is there a reason 'flatmap' is any better other than it is what you learned it as somewhere? I'm not convinced English has a word or convenient phrase for "monad", and it doesn't strike me that "flatMap" is it. How do I "flatMap" Haskell's STM monad? Or a probability monad? (I know the mechanics of the answer, I am specifically referring to the English-induced intution.) I don't see the intuition being particularly correct; flatMap is really tied to List, which isn't a particularly great thing to be tied to since it isn't very used. List's monadic interface is cute for some little algorithms, sure, which makes it disproportionately appear in examples, but list's monad implementation has complexity O(m^n) (where m is the size of the lists and n the number of lists you're going to consider) and you need some algorithm that gives you some serious culling on that before it's practical for very much.
- mokagio 11y agoThat's true. The concept of "flatmapping" an array is easy to get, but what about flatmapping and optional/maybe value?
- AdieuToLogic 11y ago> ... what about flatmapping and optional/maybe value? The same concepts apply. With an option type, flatMap can be defined in Scala Option[1] types as: flatMap[B](f: (A) ⇒ Option[B]): Option[B] For the empty option situation (None in Scala), the result is a None. For the populated case (Some in Scala), the result is what f produces when given the value contained in the original Option[A] type. Of course, f is free to produce a None for its result should it so desire. What makes Monads neat IMHO is that so long as the container type adheres to the Monad laws[2], then the developer can fully rely on the behaviour conforming to a common set of expectations. 1 - http://www.scala-lang.org/api/2.11.7/#scala.Option http://www.scala-lang.org/api/2.11.7/#scala.Option 2 - http://eed3si9n.com/learning-scalaz/Monad+laws.html http://eed3si9n.com/learning-scalaz/Monad+laws.html
- dllthomas 11y agoI think the parent was saying that "flatMap" failed to give them intuition around Option, not that Option wasn't a monad.
- whateveracct 11y agoJoinable would be a much better name than FlatMappable. FlatMap makes it apply too much to collections.
- quchen 11y ago"flatmap" hints at it consisting of two components, flattening and mapping. Both are to be seen in a generalized context though, and the words are familiar to many when thinking about collections. 1. Mapping - the same as what Functor/Mappable provides. We use this to "map" over a structure, producing a nested structure. 2. Flattening: we just built our nested structure, time to squash it again. In types akin to templates, Structure<A> ------------------------ (map something suitable over it) Structure<Structure<B>> ------------------------ (flatten it) Structure<B> It's not a terrible name, but it probably doesn't help seeing the bigger picture either. "Flattening" a parser, a subroutine, an empty thing -- that's not really something very intuitive.
- Tyr42 11y agoJoin (flatten) is a fundamental monadic operation. join:: m (m a) -> m a I have a parser of a single character and a way to generate new character parsers char :: Char -> Parser Char x :: (Parser Char) let y = fmap (char . toUpper) x :: (Parser (Parser Char)) It's a parser which creates a new parser out of the input it consumes. I do think that fmap/pure/join is the easier to understand set of defining functions for monads.
- quchen 11y agojoin is one possible fundamental monadic operation. You can also define monads in other ways, such as endofunctors such that the Kleisli structure forms a category. In this case, you have the identity arrow (called return in Haskell) and Kleisli composition (<=< in Haskell) as fundamental operations. Neither of these is more fundamental than the other. You can convert back and forth, f >=> g = \x -> f x >>= g m >>= f = (f <=< id) m join = (>>= id) m >>= f = join (fmap f m) So if you're focused on composing monadic operations, thinking about it in terms of >=> is often a good idea.
- chongli 11y agoThere's more to the interfaces than merely the operators; there are laws, too. Besides that, the operators give a big advantage when sequencing operations, something you can't do with map() notation.
- adamwk 11y agoThen why not have both? Applicative Functors have both `fmap` and `<$>`. `>>=` could easily be an alias of `flatMap` or `bind` or whatever.
- chongli 11y agoI'm right there with you. I'm a Haskell user; I love user-definable operators.
- lmm 11y agoBecause code is read more than it's written; multiple ways of writing the same thing makes it easier to write but harder to read.
- dragonwriter 11y agoMultiple ways of writing the same thing makes it easier to read, often, because you are more free to use the form that is more readable and intuitive in context; that's one reason why natural languages (including written languages) tend to have multiple ways of expressing the same ideas.
- jameshart 11y agoWhen you implement an equality operator, or addition/multiplication operators on a type there are 'laws' too, but that doesn't stop it coming down to 'has an equals method'.
- wyager 11y agoThose intuitions do not generalize correctly. It's better for people new to the concepts to realize that they don't understand than to incorrectly believe they understand (based on mediocre collection-oriented analogies).
- lelf 11y agoBecause 1) those concepts are already have proper names; 2) there is a ton of (even predating our modern programming era) useful literature using proper names; 3) those proposed “non-confusing” names have zero meaning for a lot of monads/applicaties/… I feel like 99% who want whem have only seen containers.
- dllthomas 11y agoOne thing that I really like about Haskell's practice of naming interfaces after mathematical constructs is that it makes it clear what the rules for those interfaces "should be" and changes the character of a few kinds of discussion. If we called them "Mappable", "Applicable", "FlatMappable" (yuck), "AssociativeAppendableWithIdentity"... then there would be disagreement about whether some new construct "is really" Applicable. Is summation really "Appending"? And these arguments are high stakes, because the most important thing about an interface is that it tells the user what they can expect. If I ask for an Appendable, and get something that doesn't follow the rules I think Appendable should have, then... whose code is broken? In Haskell, it's entirely clear whether a new type "is really" a Monoid or Functor - does it obey the laws? Okay! Whether "container" is a good way to think of Functor is recognized as a purely pedagogic question (not that there's never drama in pedagogy, but those people getting work done can opt out without worry that it will break their code when they try to interface with others).
- coldcode 11y agoInteresting. And people think Swift is easy to learn. Not all of it though.
- hellofunk 11y agoSwift itself is quite easy to learn, and you don't actually have to do any functional programming in it if you don't know how to do so. I'll bet most people writing in Swift are doing little more than they would have done in Objective-C since it fully supports the OO paradigm. Over time, more and more will adopt some of the neat things you can do with this first-class functions.
- mokagio 11y agoSwift is actually quite simple to pickup, and thanks to its static typing the compiler helps along the way. This functional side of what you can do with the language seems harder because the cryptic concepts, and on top of it there is no real built-in support. Overall though, once you've tried them out a bit they are not that hard, and actually very useful :)
- sleepychu 11y agoI appreciate that this article is just a quick code snippet rewrite but it really could have done with some quick (even if ugly) edits on the graphics and as a result ditched all the Haskell asides. Assuming of course that I'm correct in my assumption that the articles is aimed at Swifties looking at FAM and not Haskellers looking at Swift.
- panic 11y agoWhy even have the concept of a monad in Swift? The language is neither lazy nor purely functional, so the problem monads were introduced to solve doesn't exist. You can just write regular code to do I/O.
- Retra 11y agoMonads exist regardless of whether you call them that. They are a mathematical idea. An algebraic structure. If you made a language that used conditionals based on 1 and 0, it could do boolean logic, even if you didn't include boolean values explicitly. Monads exist in just about every programming language. They weren't introduced to solve a problem. They already existed, and just happen to be useful to solve certain problems.
- panic 11y agoThey weren't introduced to solve a problem. Monads were definitely introduced to Haskell as a way to solve the problem of I/O -- see Section 7 of http://www.scs.stanford.edu/~dbg/readings/haskell-history.pdf http://www.scs.stanford.edu/~dbg/readings/haskell-history.pd... for more details. It's true that monads existed as a concept in category theory before they were used in programming languages, but they didn't really catch on until their use in Haskell. Certainly you don't see articles about applying other esoteric category theory concepts to Swift programs.
- gohrt 11y agoMonads are generally useful beyond IO, and pure programming style is available (and recommended) in almost every language. From the article you linked: "Although Wadler’s development of Moggi’s ideas was not directed towards the question of input/output, he and others at Glasgow soon realised that monads provided an ideal framework for I/O."
- panic 11y agoYes, definitely. To be clear, I'm a fan (and long-time user) of monads in Haskell, and I think they're a great solution to the problem of embedding impure effects in a pure language. I just don't understand why you'd use them in a language where you can just write the impure effects in a direct style, especially when there's no 'do' notation equivalent.
- superfunc 11y agoI was expecting a Chipotle menu
- efnx 11y agoPeople often complain about Haskell syntax and operators looking ugly (I disagree) but dang: func <^><T, U>(f: T -> U, a: T?) -> U? { return a.map(f) } Gnartown!
- CookWithMe 11y agoWhat is so ugly about it? Swift tries to be somewhat close to the usual C-syntax (it's supposed to be the successor of Obj-C, after all). For someone used to C-syntax, I guess the main deviation is that the return type is in the back and that there's a func keyword. As for the operaters, there is the addition of generics (what is wrong about <> ?), -> to describe signature of a function (a very sensible choice IMO) and ? for Optionals (again, fine for me). I don't really see how a statically typed language can substantially improve this, but I'd be happy if someone can proof me wrong :-)
- kittenfluff 11y agoIt's not clear to me why it's necessary to include <T, U> at the start of the function definition. In Haskell, unquantified type variables are implicitly universally quantified, i.e. you assume that the signature must be valid for any types T and U. That's the only thing I think could be substantially improved, though. Personally I find the style where you separate the type signature from the function definition easier to read, for example How about <^> : (T -> U) * T? -> U? <^> (f, a) { return a.map(f) } or even <^> : (T -> U) * T? -> U? <^> (f, a) -> a.map(f) which is already pretty close to the Haskell equivalent (<^>) :: (t -> u) -> Maybe t -> Maybe u (<^>) = fmap Arguably, Haskell syntax could be improved with more built-in syntax <^> : (t -> u) -> t? -> u? <^> = fmap though I haven't thought about what this means for parsing the language.
- lmm 11y agoExplicit is better than implicit. Does Haskell allow functions to have value parameters that aren't declared?
- FeepingCreature 11y agolet post = Post.findByID(1) if post != nil { return post.title } else { return nil } Or, as a cool C-like would put it: let post = Post.findByID(1) return post?.title Just saying!
- octocoupler 11y agoThat is how it's done in Swift. Are you saying there are C languages that do the same thing?
- FeepingCreature 11y agoWell, mine does ( https://github.com/FeepingCreature/fcc https://github.com/FeepingCreature/fcc ). I don't think it's very widespread, sadly. Example: https://github.com/FeepingCreature/fcc/blob/master/tests/test69.nt https://github.com/FeepingCreature/fcc/blob/master/tests/tes...
- octocoupler 11y agoNice! If you want it to be, you should add some information and examples. Or a simple website, even.
- FeepingCreature 11y agoNo I mean the syntax. :) For my language, I'll do some proper advertising on it once I figure out version two; v1 is very much a testbed for playing around with language design.