35

Soooo...

Semigroups, Monoids, Monads, Functors, Lenses, Catamorphisms, Anamorphisms, Arrows... These all sound good, and after an exercise or two (or ten), you can grasp their essence. And with Scalaz, you get them for free...

However, in terms of real-world programming, I find myself struggling to find usages to these notions. Yes, of course I always find someone on the web using Monads for IO or Lenses in Scala, but... still...

What I am trying to find is something along the "prescriptive" lines of a pattern. Something like: "here, you are trying to solves this, and one good way to solve it is by using lenses this way!"

Suggestions?


Update: Something along these lines, with a book or two, would be great (thanks Paul): Examples of GoF Design Patterns in Java's core libraries

Community
  • 1
  • 1
Hugo Sereno Ferreira
  • 8,600
  • 7
  • 46
  • 92
  • 4
    A pattern compensates for a lack of language; by definition rich abstraction support is the opposite of that situation. These are tools for structuring your programme in a defined way - the point is that you recognise that the procedural code you would otherwise write corresponds to a processing pattern for which you have functional support, and then you only need to write the substantive bit, not the control code. – Marcin Dec 11 '11 at 08:22
  • 3
    You may be interested in this similar question: [How to learn Haskell](http://stackoverflow.com/questions/1012573/how-to-learn-haskell) – Dan Burton Dec 11 '11 at 08:35
  • The advice often is start with Learn you a haskell sequence: Functor, Applicative, Monoid, Monad, then arrows and zippers. And remember each has only 1 or 2 important functions: fmap for Functor, pure and <*>(apply) for Applicative; bind for Monad. – Gene T Dec 11 '11 at 13:16

5 Answers5

19

The key to functional programming is abstraction, and composability of abstractions. Monads, Arrows, Lenses, these are all abstractions which have proven themselves useful, mostly because they are composable. You've asked for a "prescriptive" answer, but I'm going to say no. Perhaps you're not convinced that functional programming matters?

I'm sure plenty of people on StackOverflow would be more than happy to try and help you solve a specific problem the FP way. Have a list of stuff and you want to traverse the list and build up some result? Use a fold. Want to parse XML? hxt uses arrows for that. And monads? Well, tons of data types turn out to be Monads, so learn about them and you'll discover a wealth of ways you can manipulate these data types. But its kind of hard to just pull examples out of thin air and say "lenses are the Right Way to do this", "monoids are the best way to do that", etc. How would you explain to a newbie what the use of a for loop is? If you want to [blank], then use a for loop [in this way]. It's so general; there are tons of ways to use a for loop. The same goes for these FP abstractions.

If you have many years of OOP experience, then don't forget you were once a newbie at OOP. It takes time to learn the FP way, and even more time to unlearn some OOP tendencies. Give it time and you will find plenty of uses for a Functional approach.

Dan Burton
  • 53,238
  • 27
  • 117
  • 198
  • 6
    While your general point is fine, links to SO questions that deal with specific examples of real problems solved by Scala would be far more relevant to the questioner. It is _very common_ for people to want to learn by example; it must be right for them to seek to do so. – Donal Fellows Dec 11 '11 at 08:01
  • 2
    @DonalFellows - fair enough. I'm not familiar enough with the Scala questions on SO to compose such a list; I'd certainly upvote whoever does that. – Dan Burton Dec 11 '11 at 08:06
  • Well I don't know Scala much at all. Maybe some other kind soul here knows the area enough to provide the sort of guide needed (or to just point to the relevant parts of the scala tag wiki). – Donal Fellows Dec 11 '11 at 08:27
  • 4
    I think this doesn't really answer the question. I don't see why it's not possible to pull examples "out of thin air" for FP, but not for OO (for which a typical introduction contains any number of examples). I do get a little frustrated with the (all too common, but not universal) assertion that these abstractions will be useful, without providing proof-by-example. – The Archetypal Paul Dec 11 '11 at 11:38
  • 1
    @Paul - suppose someone asked this same question, but about OO. Could you really distill something like [Design Patterns](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) into a single answer? Perhaps [Typeclassopedia](http://haskell.org/haskellwiki/Typeclassopedia) (warning: Haskell) would be a helpful read, but I have a hard time imagining a complete answer to this question packed into SO format. – Dan Burton Dec 11 '11 at 19:50
  • 2
    I think I could provide a summary and some pointers to examples without much difficulty, yes. In fact, someone's already done a rather superb job of it: http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns – The Archetypal Paul Dec 11 '11 at 21:05
12

I gave a talk back in September focused on the practical application of monoids and applicative functors/monads via scalaz.Validation. I gave another version of the same talk at the scala Lift Off, where the emphasis was more on the validation. I would watch the first talk until I start on validations and then skip to the second talk (27 minutes in).

There's also a gist I wrote which shows how you might use Validation in a "practical" application. That is, if you are designing software for nightclub bouncers.

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
7

I think you can take the reverse approach and instead when writing a small piece of functionality, ask yourself whether any of those would apply: Semigroups, Monoids, Monads, Functors, Lenses, Catamorphisms, Anamorphisms, Arrows... A lots of those concepts can be used in a local way.

Once you start down that route, you may see usage everywhere. For me, I sort of get Semigroups, Monoids, Monads, Functors. So take the example of answering this question How do I populate a list of objects with new values. It's a real usage for the person asking the question (a self described noob). I am trying to answer in a simple way but I have to refrain myself from scratching the itch "there are monoids in here".

Scratching it now: using foldMap and the fact that Int and List are monoids and that the monoid property is preserved when dealing with tuple, maps and options:

// using scalaz
listVar.sliding(2).toList.foldMap{
  case List(prev, i) => Some(Map(i -> (1, Some(List(math.abs(i - prev))))))
  case List(i) => Some(Map(i -> (1, None)))
  case _ => None
}.map(_.mapValues{ case (count, gaps) => (count, gaps.map(_.min)) })

But I don't come to that result by thinking I will use hard core functional programming. It comes more naturally by thinking this seems simpler if I compose those monoids combined with the fact that scalaz has utility methods like foldMap. Interestingly when looking at the resulting code it's not obvious that I'm totally thinking in terms of monoid.

Community
  • 1
  • 1
huynhjl
  • 41,520
  • 14
  • 105
  • 158
6

You might like this talk by Chris Marshall. He covers a couple of Scalaz goodies - namely Monoid and Validation - with many practical examples. Ittay Dror has written a very accessible post on how Functor, Applicative Functor, and Monad can be useful in practice. Eric Torreborre and Debasish Gosh's blogs also have a bunch of posts covering use cases for categorical constructs.

This answer just lists a few links instead of providing some real substance here. (Too lazy to write.) Hope you find it helpful anyway.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
4

I understand your situation, but you will find that to learn functional programming you will need to adjust your point of view to the documentation you find, instead of the other way around. Luckily in Scala you have the possibility of becoming a functional programmer gradually.

To answer your questions and explain the point-of-view difference, I need to distinguish between "type classes" (monoids, functors, arrows), mathematically called "structures", and generic operations or algorithms (catamorphisms or folds, anamorphisms or unfolds, etc.). These two often interact, since many generic operations are defined for specific classes of data types.

You look for prescriptive answers similar to design patterns: when does this concept apply? The truth is that you have surely seen the prescriptive answers, and they are simply the definitions of the different concepts. The problem (for you) is that those answers are intrinsically different from design patterns, but it is so for good reasons.

On the one hand, generic algorithms are not design patterns, which suggest a structure for the code you write; they are abstractions defined in the language which you can directly apply. They are general descriptions for common algorithms which you already implement today, but by hand. For instance, whenever you are computing the maximum element of a list by scanning it, you are hardcoding a fold; when you sum elements, you are doing the same; and so on. When you recognize that, you can declare the essence of the operation you are performing by calling the appropriate fold function. This way, you save code and bugs (no opportunity for off-by-one errors), and you save the reader the effort to read all the needed code.

On the other hand, structures concern not the goal you have in mind but properties of the entities you are modeling. They are more useful for bottom-up software construction, rather than top-down: when defining your data, you can declare that it is a e.g. a monoid. Later, when processing your data, you have the opportunity to use operations on e.g. monoids to implement your processing. In some cases it is useful to strive to express your algorithm in terms of the predefined ones. For instance, very often if you need to reduce a tree to a single value, a fold can do most or all of what you need. Of course, you can also declare that your data type is a monoid when you need a generic algorithm on monoids; but the earlier you notice that, the earlier you can start reusing generic algorithms for monoids.

Last advice is that probably most of the documentation you will find about these concepts concerns Haskell, because this language has been around for much more time and supports them in a quite elegant way. Quite recommended here are Learn you a Haskell for Great Good, a Haskell course for beginners, where among others chapters 11 to 14 focus on some type classes, and Typeclassopedia (which contains links to various articles with specific examples). EDIT: Finally, an example of applications of Monoids, taken from Typeclassopedia, is here: http://apfelmus.nfshost.com/articles/monoid-fingertree.html. I'm not saying there is little documentation for Scala, just that there is more in Haskell, and Haskell is where the application of these concepts to programming was born.

Blaisorblade
  • 6,438
  • 1
  • 43
  • 76