Which parts of Real World Haskell are now obsolete or considered bad practice?

In the chapter 19 of Real World Haskell a lot of the examples now fail due to the change of Control.Exception.

That makes me think maybe some of the stuff in this book is actually obsolete and not worth studying anymore, after all it's been 6 years. My only other reference is Learn You a Haskell For Great Good, though it's a great book, it's much more basic compared with RWH.

Can anyone who have read the book before please give some advice on which parts of it are no longer relevant? Especially the chapters in the second half of the book, for example, software transactional memory, concurrent programming, socket programming, etc.

EDIT: This is about the edition of the book that's published on Dec 2008, which is the only known edition as of today (Nov 2017)


Main issue of RWH

It's old. RWH was written at a time version 6.8 of GHC was being used. 6.8 used base version 3.0.x.x. 6.10.1 already used 4.0.0.0, which introduced many changes. And that's just the jump from 6.8 to 6.10. The current version of GHC is 7.10. Monads have been changed. There's currently a discussion to remove return from Monad, so the Monad instance in Real World Haskell will really be out of sync with the real world.

That being said, it's still a useful resource for general guidelines. But keep in mind that many libraries changed since its release.

Something you can read along while reading RWH is "What I Wish I Knew When Learning Haskell" by Stephen Diehl. It provides additional insight, but be aware, some sections aren't really newcomer friendly.

General remarks

  • Read the comments. They usually contain information whether the given paragraph/section is still relevant and/or working.
  • Read the documentation of the libraries/functions you want to use. Even if you're lazy, know at least the types.

Remarks to chapters

This is just a quick overview of some of the things that I noticed while reading RWH. It's probably incomplete.

Chapter 2. Types and Functions vs the FTP

Since GHC 7.10.

The type of null has been changed due to the Foldable-Traversable-Proposal. Many other functions such as foldr, foldl and many other that were previously only defined for [a] in the Prelude have been replaced with more general Foldable t => t a variants.

Chapter 11. Testing and quality assurance

Since Haskell-platform 2010 or late 2008.

Although this is mentioned in a footnote, the QuickCheck library has changed in many ways from version 1 to version 2. For example, generate now uses Gen a instead of StdGen, and the functionality of the old generate is in Test.QuickCheck.Gen.unGen.

In doubt, check the documentation.

Chapter 14. Monads & Chapter 15. Programming with monads

Code breaking: Applicative m => Monad m

As of GHC 7.10, Applicative is now a superclass of Monad, something that wasn't planned in 2007.

In GHC 7.10, Applicative will become a superclass of Monad, potentially breaking a lot of user code. To ease this transition, GHC now generates warnings when definitions conflict with the Applicative-Monad Proposal (AMP).

See 7.8.1 release notes.

The State/Writer/Reader monads

In the Will the real state monad please stand up? section, the authors claim

In order to define a Monad instance, we have to provide a proper type constructor as well as definitions for (>>=) and return. This leads us to the real definition of State.

-- file: ch14/State.hs
newtype State s a = State
    runState :: s -> (a, s)
}

That's no longer true, because State and its friends are now implemented via

type State  s = StateT  s Identity
type Writer w = WriterT w Identity
type Reader r = ReaderT r Identity

So they're defined by their monad transformer.

Chapter 17. Interfacing with C: the FFI

The overall chapter is fine, but as one can read in the comments or on Yuras Shumovich's blog, the finalizer part in the following code is bad practise:

pcre_ptr <- c_pcre_compile pattern (combineOptions flags) errptr erroffset nullPtr
if pcre_ptr == nullPtr
    then do
        err <- peekCString =<< peek errptr
        return (Left err)
    else do
        reg <- newForeignPtr finalizerFree pcre_ptr -- release with free()
        return (Right (Regex reg str))

As malloc() should be used with free(), new with delete, allocate with deallocate, one should always use the correct function.

TL;DR You should always free memory with the same allocator that allocated it for you.

If a foreign function allocates memory, you should also use the accompanying deallocation function.

Chapter 19. Error handling

Error handling changed completely from 6.8 to 6.10, but you noticed that already. Better read the documentation.

Chapter 22. Extended Example: Web Client Programming

Some of the example seem to be broken. Also, there are other HTTP libraries available.

Chapter 25. Profiling and optimization

General profiling techniques are still the same, and the example (see below) is a great case study for problems that can occur in your program. But RWH is missing multi-threaded profiling, e.g. via ThreadScope. Also, lazy IO isn't concerned throughout the whole book, as far as I know.

mean :: [Double] -> Double
mean xs = sum xs / fromIntegral (length xs)

Chapter 24 & Chapter 28 (Concurrent and parallel programming & STM)

While Chapter 24. Concurrent and multicore programming and Chapter 28. Software transactional memory are still relevant, Simon Marlow's book Parallel and Concurrent Programming in Haskell focuses solely on concurrent and parallel programming and is pretty recent (2013). GPU programming and repa are completely missing in RWH.

Chapter 26. Advanced library design: building a Bloom filter

As with the other chapters, the general guidelines of the design library is still well written and relevant. However, due to some changes (?) concerning ST, the result cannot be compiled anymore.

Chapter 27. Network programming

It's still mostly up to date. After all, network programming doesn't change so easily. However, the code uses deprecated functions bindSocket and sClose, which should be replaced by bind and close (preferably via qualified import). Keep in mind that it's very low-level, you might want to use a more specialized high-level library.

Appendix A. Installing GHC and Haskell libraries

GHC 6.8 was the last version before the Haskell Platform has been introduced. Therefore, the appendix tells you to get GHC and Cabal by hand. Don't. Instead, follow the instructions on the haskell.org download page.

Also, the appendix doesn't tell you about Cabal sandboxes, which were introduced in Cabal 1.18 and free you from dependency hell. And of course, stack is missing completely.

Missing content

Some topics are not discussed in RWH at all. This includes streaming libraries such as pipes and conduit, and also lenses.

There are several resources out there for those topics, but here are some links to introductions to give you an idea what they're about. Also, if you want to use vectors, use the vectors package.

Control.Applicative

RWH uses Control.Applicative's (<$>) at several points, but doesn't explain Control.Applicative at all. LYAH and the Typeclassopedia contain sections on Applicative. Given that Applicative is a superclass of Monad (see above), it's recommended to learn that class by heart.

Furthermore, several operators of Control.Applicative (and the typeclass itself) are now part of the Prelude, so make sure that your operators don't clash with <$>, <*> and others.

Lenses

  • Video by Edward Kmett (author of lens)
  • Video by Adam Gundry "Lenses: compositional data access and manipulation"
  • Introduction and tutorial by Jakub Arnold

Streaming libraries

  • Conduit Overview by Michael Snoyman (author of conduit)
  • Pipes tutorial by Gabriel Gonzales (author of pipes, included in the pipes package)

Tooling

  • version 1.18 of Cabal, which introduced sandboxes
  • stack, a cross-platform program for developing Haskell projects
  • ghc-mod, a backend for vim, emacs, Sublime Text and other editors

New/missing language extensions and GHC changes

  • runtime type polymorphism (:i ($) has changed tremendously)
  • -XTypeInType
  • -XDataKinds
  • -XGADT
  • -XRankNTypes
  • -XGenericNewtypeDeriving
  • -XDeriveFunctor
  • any other extension that happened after 6.6