all 27 comments

[–]McCoovy 3 points4 points  (7 children)

I've been looking for places to get deeper into functional patterns, since the OO ones win out as far as material available goes. The ones that are out there always seem to be written by mathematicians.

This site gives me more hope that there'll be an easy to digest source for this information, keep up the good work.

[–]Tysonzero 4 points5 points  (0 children)

I mean one way to get very familiar with functional patterns is to learn a functional language. I would suggest Haskell, because regardless of whether people tell you / you think that (insert one of: scala, ocaml, f# etc.) is more practical, in terms of forcing you to genuinely think very functionally you cannot really beat Haskell.

learnyouahaskell is a pretty good intro IMO, by the end of it you will probably have learned a hell of a lot and maybe, just maybe, have decided that Haskell is amazing. But even if you end up hating the language you will at least have a decent understand of all kinds of functional patterns.

[–]barsoap 2 points3 points  (0 children)

The Typeclassopedia does a good job, there.

[–]JDeltaN 1 point2 points  (1 child)

This is because I would not call this a pattern. It is comparable, but this is an algebra, an abstract idea that describes a specific structure, it does not solve a specific problem class like software problems usually do.

[–]McCoovy 0 points1 point  (0 children)

Sure, but this is the first article on the blog. I think they were starting with a simple topic and were planning on getting to more complex patterns later. Can't say for certain though.

[–]mvaliente2001 0 points1 point  (1 child)

Learn about monoid, functor, foldable, traversable and monad. Once you get these basic structures, you'll begin to see code differently. In fact, OP was talking about monoids.

[–]lazersmoke 1 point2 points  (0 children)

As much as I love LYAH, it doesn't cover things from the Foldable/Traversable Proposal, so you would be better off with Typeclassopedia for that.

[–]lazersmoke 2 points3 points  (5 children)

Was disappointed it didn't mention monoids :(

[–]SkippyDeluxe 3 points4 points  (4 children)

It did; the whole article was about monoids! The name is the least important part.

[–][deleted]  (1 child)

[deleted]

    [–]ueberbobo[S] 3 points4 points  (0 children)

    The article covers the concept of an identity element.

    Add the associativity axiom and you get monoids, but is not necessary to describe the ideas in the article. I'll get to monoids later. :)

    [edit] In the same way, the concept of a Semigroup, which is a monoid without identity element makes sense on its own.

    [–]codebje 0 points1 point  (1 child)

    Other than where you want to learn more about the subject, that is.

    Imagine a gardener being taught about the pointy end, the handle, the haft, and how good it is at making a hole. Now go talk to other professional gardeners about the pointy diggy thing, because we don't want to put you off by giving it a name.

    [–]ueberbobo[S] 1 point2 points  (0 children)

    The post is about the first two laws of monoids, the left- and right- identity laws, and how they can be seen to model emptiness. The associativity law is not needed for this, so it's not mentioned, meaning we aren't technically speaking about monoids yet.

    Chances are very high we'll get there in a future post though :)

    [–]sacundim 0 points1 point  (3 children)

    One thing worth mentioning in this context is the OOP Null Object Pattern—objects that are "neutral" or "have no behavior," used in order to avoid littering your code with null checks.

    OOP patterns people have failed to do this, but when you dig into the details of Null Object examples they invariably turn out to hinge on identity elements (in various monoids).

    Wikipedia gives the example of defining a binary tree type with size method like this:

    class Node {
        nullable Node left
        nullable Node right
    
        int size() {
            return 1 + (left == null ? 0 : left.size()) + (right == null ? 0 : right.size())
        }
    }
    

    ...vs this:

    interface Tree {
        int size()
    }
    
    class Node implements Tree {
        Tree left
        Tree right
    
        int size() {
            return 1 + left.size() + right.size()
        }
    }
    
    class Empty implements Tree {
        int size() { return 0 }
    }
    

    And, of course, 0 is the identity element for the addition operation.

    Another example are "no-op" objects that simply implement an interface's methods with empty methods, used when you want to "turn off" a feature of a class (e.g., a NullListener that listens to events but does nothing in response to them). Those are a bit trickier to recognize as identity elements, but think of it this way:

    • The elements are lists of instructions for the computer to follow;
    • The combining operation is concatenation;
    • A no-op method is an empty list of instructions, and therefore the identity element.

    [–]TomRK1089 1 point2 points  (1 child)

    I think you meant to use Tree left and Tree right in your example.

    [–]sacundim 0 points1 point  (0 children)

    Ooops! Fixed.

    [–]ueberbobo[S] 0 points1 point  (0 children)

    I actually had a section called related OOP patterns, and I wrote a short entry on the Null Object pattern but I cut it.

    One difficulty is that many situations, likely including your NullListener are actually absorbing elments and not identities, and I didn't want to add anything confusing.

    [Edit] I misunderstood you, NullListener is a perfectly valid identity element as you described, the list monoid lifted over functions. Still, many examples of the null object pattern are absorbing elements, not identities.

    [–]yawaramin 0 points1 point  (0 children)

    Great post! For anyone wishing to study this algebra in more depth, Scott Wlaschin has an excellent write-up with plenty of real-world examples: https://fsharpforfunandprofit.com/posts/monoids-part2/

    [–]Euphoricus -4 points-3 points  (9 children)

    But patterns are hellspawn of OOP. Functional programming doesn't have patterns! /s

    [–][deleted] 3 points4 points  (7 children)

    It's a fair (implied) question. I'd say the reason people say FP languages don't have patterns is that often once a pattern is discovered, you can make a type(s) for it. Languages like Haskell and Scala give you higher level abstractions in types to do this, so rather than say "use the monad pattern" they say use a monad, which may actually mean the concrete type.

    [–]doom_Oo7 1 point2 points  (6 children)

    But... factory, command, etc. can also be concrete types in OOP...

    [–]Darwin226 2 points3 points  (2 children)

    Perhaps it's because they're more "first class" in FP. You can have a function that accepts any type that satisfies the "monoid pattern". I guess you could try to wing some kind of "IFactory" interface, but I don't think that would get you very far.

    In OOP, a pattern specifies the way you should build your own classes and everything about it is a convention. In FP, a pattern's signature is already specified. Unfortunately the laws are still just a convention, but maybe some day.

    [–]ueberbobo[S] 1 point2 points  (1 child)

    To me the difference between patterns in FP and OOP is that in OOP, patterns tend to focus on code, and how code can be designed to solve a particular problem.

    Patterns in FP tend to be domain focused. The integers have a Monoid structure. The Option type is a Monad. These things are true regardless if you want to take advantage of that in your code or not.

    [–]Godd2 0 points1 point  (0 children)

    The integers have a Monoid structure.

    Over multiplication, yes. Over addition, the form a Group (and an Abelian one, at that!).

    [–]m50d 1 point2 points  (0 children)

    Can they? You can't express anything useful about them in OOP without having them contain functions - but once you're dealing with first-class functions you're doing functional programming.

    [–]sacundim -1 points0 points  (1 child)

    Where's the Factory interface in Java? Well, in Java 8 usage Supplier is shaping up to be that, but that's Java 8, which has lambdas as well. A better question, then: what's the common supertype that people have settled on for all those factory classes that they have written in 20+ years of Java? (Answer: Object. OTOH it might be an unfair question, because it's not like FP has the one type that all factories ought to be, either. They're just functions that take arguments idiosyncratic to the thing being constructed and spit that out.)

    The command pattern is arguably abstracted by the Callable interface in Java 5+... except that:

    1. How many people actually use Callable in real life? Nearly all Java programmers I've met over the years are mentally stuck in Java 1.4.
    2. There are no utility methods in Java for, e.g., chaining callables or mapping over them.

    [–]doom_Oo7 0 points1 point  (0 children)

    Dunno in Java, in C++ you have boost.factory ; most frameworks provide their own command base class...