Question

I've recently forayed into the world of functional programming (FP) and am wondering how to "think functionally" for even moderately sized applications? Especially w.r.t. the analysis and design of FPs.

With OOP we're trained to think in terms of objects, their attributes and relations. We model our analyses/designs using class and sequence diagrams. However, the same models seem to be a bad fit when designing for FPs. What are the equivalent modeling paradigms for functional programming? It seems DFDs maybe a good fit but I maybe wrong.

For example: I was thinking of designing a simulation of Monopoly, the board game using Haskell, just to learn the language. When doing OOAD you come up with classes like board contains items that have attributes/methods attached to it. You have player and various other objects and their associated relations that can be captured in a class diagram. And their interactions in a sequence diagram. However, these modeling paradigms doesn't seem to transfer well for functional programs. So just "how" do you model functionally?

Note: I'm looking for concrete references/examples that can explain how to analyze and design functional programs given that I'm coming from a heavily object-oriented way of thinking/modeling.

Was it helpful?

Solution

According to Simon Peyton Jones:

The language in which you write profoundly affects the design of programs written in that language. For example, in the OO world, many people use UML to sketch a design. In Haskell or ML, one writes type signatures instead. Much of the initial design phase of a functional program consists of writing type definitions. Unlike UML, though, all this design is incorporated in the final product, and is machine-checked throughout.

Source: Masterminds of Programming

So instead of drawing all the fancy UML diagrams, you actually write type definitions coupled with undefined in the design phase.

OTHER TIPS

All of my programming these days consists of single-person projects. If I were collaborating on a project with other programmers, I think that writing type definitions and using undefined would be a good approach.

But I gather what you're really looking for is some advice about how you can learn to think functionally. So here are some thoughts.

When programming in Haskell, there are two ways I think about the program I'm writing.

  • If the program is mathematical, I think of the program as a set of equations.

  • Otherwise, I tend to think of the program as one or more chains of of data transformations. (So perhaps DFDs would be useful.)

So in your Monopoly example, my first thought would be to figure out how I'm going to represent the state of the board (e.g., which properties have houses, who owns them). Then I might have a function that transforms the board when someone buys a property, and other functions for other things players might do. (There's also monads for representing state, State and StateT. I might use them, if and when I feel they will make the code clearer, but I usually keep things basic to start.)

One of the mistakes I made most often as a beginner was to create a lot of unnecessary classes and data types.

Short answer: composition of smaller programs.

You first study the problem before you, then you develop a set of small operations (often in the form of combinators) that you reckon make sense in that problem's context, and finally you build the solution around those operations. I'm under the impression that all packages found on Hackage follow this approach.

In this way the final solution is (more often than not) simple, clear and elegant. As you can appreciate the aforementioned set of small operations you choose for your solution is critical; with practice, you'll develop the sensibility to pick it wisely.

My book suggestion is Pearls of Functional Algorithm Design, by Richard Bird, Google Books (preview). In this book you'll learn about the calculational approach to functional programming, which I think is most valuable.

Two books you might be interested in:

  1. Structure and Interpretation of Computer Programs - a classic intro to CS textbook in Scheme. I think it's a must for programmers interested in FP.

  2. How to Design Programs - similar to SICP, slightly more modern and focuses on design. The language of choice here is Racket.

If you want a hands-on project in Haskell, I'd recommend Write Yourself a Scheme in 48 Hours, a wonderful tutorial for implementing an interpreter for Scheme. AST manipulation is where FP (and especially Haskell) shines, so I think writing an interpreter is a good experience for new FP programmers.

My perspective regarding the FP vs OO analysis and design debate is the following:

  • OOAD and DDD (Domain-Driven Design) are very useful tools for software systems decomposition;
  • FP has types, OO has classes and interfaces: they are dual in different worlds;
  • FP has type instances, OO has class instances (aka, objects in OO);
  • Use composition in FP, where in OO you would use inheritance;
  • Both FP and OO languages come with polymorphic constructs;
  • Both FP and OO use collections (sets, lists and maps) to make connections between instances (of types in FP, and of classes in OO);
  • Associations in FP are typically implemented as collections of instance IDs, whereas absensein OO they are implemented as collections of references to the memory locations of objects. This comes from the immutability property of data structures in FP.

Most books in FP, like those referred in the other answers before mine, do not show you how to design (aka, decompose) complex real-world problems. They generally demonstrate FP's features with very short examples (e.g., compare them with the examples in Craig Larman's Applying UML and Patterns excelent book, and judge yourself).

For something more close to what could be called Functional-Oriented Analysis and Design (FOAD), I recommend these:

DDD, OOAD, and FOAD, can be implemented in any programming language, however some programming languages offer constructs that make these approaches easier or harder to implement, but they are perfectly practical. This is evident by the many sources you can find discussing DDD in the context of FP.

Dr. Alan Kay said this regarding the essence of OOP (here):

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them.

Following this statement, Joe Armstrong, one of Erlang's creator, an FP language with important uses in the industry (e.g., WhatsApp), argues that Erlang is perhaps the most OO language around (see this interview also featuring Ralph Johnson).

Also, some say that Erlang is the best language that captured the essence of OO programming: the passing of messages between objects.

Hope this was helpful.

I can only speak from the perspective of Erlang OTP. We think in terms of processes, which have a state and functions. So in the state the process will have all the "variables" and handler functions react to data the process receives in its message queue. They act on the received data, possibly alter their own state, possibly return some data and/or have some side effects. The state can be stored in a map or a record or any other valid data type. Usually we define a record called state() or loopData().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top