Professional Documents
Culture Documents
Engineering Large Projects in Haskell A Decade of FP at Galois
Engineering Large Projects in Haskell A Decade of FP at Galois
Aaron Tomb
Joe Hurd
Adam Wick
Joel Stanley
Andy Adams-Moran
John Launchbury
Andy Gill
John Matthews
David Burke
Laura McKinney
Dylan McNamee
Lee Pike
Eric Mertens
Levent Erkok
Iavor Diatchki
Louis Testa
Isaac Potoczny-Jones
Magnus Carlsson
Jef Bell
Paul Heinlein
Peter White
Sally Browning
Trevor Elliott
Thomas Nordin
Phil Weaver
Brett Letner
Jeff Lewis
Themes
Languages matter!
Writing correct software is difficult!
Programming languages vary wildly in how well they
support robust, secure, safe coding practices
Languages and tools can aid or hinder our efforts:
Type systems
Purity
Modularity / compositionality
Abstraction support
Tools: analyses, provers, model checking
Buggy implementations
Community matters!
Soup of ideas in a large, open research community:
Rapid adoption of new ideas
Support, maintainance and help
Can't build everything we need in-house!
Give back via:
Workshops: CUFP, ICFP, Haskell Symposium
Hackathons
Industrial Haskell Group
Open source code and infrastructure
Teaching: papers, blogs, talks
2008 Galois, Inc. All rights reserved.
Typical conversation:
Engineer A: Spec says this must never
happen
Engineer B: Can we enforce that in the
type system?
2008 Galois, Inc. All rights reserved.
Serious things:
Information flow policies
Correct component wiring and integration
2008 Galois, Inc. All rights reserved.
Recent experience
First demo of a big systems project
Six engineers
50k lines of code, in 5 components,
developed over a number of months
Integrated, tested, demo'd in only a week,
two months ahead of schedule, 2 rungs
above performance spec.
1 space leak, spotted and fixed on first
day of testing
2 bugs found (typos from spec)
2008 Galois, Inc. All rights reserved.
Purity is fundamental
Difficult to show safety without purity
Code should be pure by default
Makes large systems easier to glue:
Pure code is safe by default to call
Theorem proving
Isabelle, Coq
2. Abstractions
Monads
Constantly rolling new monads
Captures critical facts about the execution
environment in the type
Laziness
Captures some concepts perfectly
A stream of 4k packets from the wire
Laziness
Makes time and space reasoning harder!
Mostly harmless in practice
Stress testing tends to reveal retainers
Graphical profiling knocks it dead
Must be able to precisely enable/disable
Be careful with exceptions and mutation
whnf/rnf/! are your friends
2008 Galois, Inc. All rights reserved.
Type classes
We use type classes
Well defined interfaces between large
components (sets of modules)
Natural code reuse
Capture general concepts in a natural way
Capture interface in a clear way
Kick butt EDSLs (see Lennart's blog)
Concurrency
forkIO rocks
Cheap, very fast, precise threads
MVars rock
STM rocks (safely composable locks!)
Result: not shy introducing concurrency
when appropriate
2008 Galois, Inc. All rights reserved.
4. Meta programming
5. Performance
Profiling
Low level Haskell
Cycle-level measurement
EDSLs to generate better code
Calling into C
Performance
Really precise performance requires
expertise
Libraries are helping reify oral traditions
about optimization
Still a lack of clarity about performance
techniques in the broader Haskell
community though
2008 Galois, Inc. All rights reserved.
6. Debugging
Heap profiling
By type profiling of the heap
GHC -fhpc
Great for finding exceptions
Understanding what is executing
+RTS -stderr
Explain what GC, threads, memory is up to
7. Documentation
8. Libraries
9. Shipping code
Cabal
I don't know how Haskell was possible
before Cabal :)
Quickly adopted Cabal/cabal-install across
projects
cabal-install:
Simple, clean integration of internal and
external components into packageable
objects
2008 Galois, Inc. All rights reserved.
10. Conventions
We try to ...
-Wall police
Consistent layout
No tabs
Import qualified Control.Exception
{-# LANGUAGE #-}
Map exceptions into Either / Maybe
We try to ...
deriving Show
Line/column for errors if you must throw
No global mutable state
Put type sigs in when you're done with
the design
Use GHCi for rapid experimentation
Cabal by default.
Libraries by default