Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why Haskell

Why Haskell

Monads, also known as Kleisli triples in Category Theory, are an (endo-)functor together with two natural transformations, which are surprisingly useful in pure languages like Haskell, but this talk will NOT reference monads. Ever. (Well, at least not in this talk.)

Instead what I intend to impress upon an audience of newcomers to Haskell is the wide array of freely available libraries most of which is liberally licensed open source software, intuitive package management, practical build tools, reasonable documentation (when you know how to read it and where to find it), interactive shell (or REPL), mature compiler, stable runtime, testing tools that will blow your mind away, and a small but collaborative and knowledgeable community of developers. Oh, and some special features of Haskell - the language - too!

Susan Potter

March 16, 2012
Tweet

More Decks by Susan Potter

Other Decks in Programming

Transcript

  1. How can I drive this thing? Figure: Photo from "If

    programming languages were cars" blog post http://machinegestalt.posterous.com/if-programming-languages-were-cars
  2. Can I drive Haskell without all this? Figure: No need

    to know Category Theory proofs, just some intuitions!
  3. # finger $(whoami) Login: susan Name: Susan Potter Directory: /home/susan

    Shell: /bin/zsh Practicing since 1997-09-29 21:18 (GMT) on tty1 from :0 Too much unread mail on [email protected] Now working at Desk.com! Looking for smart developers!;) Plan: github: mbbx6spp twitter: @SusanPotter
  4. Overview: Choosing a language Many considerations political, human, technical Runtime

    performance, reliability, configurability Knowledge culture, mindshare, resources, signal to noise ratio Tooling development, build/release, configuration, deployment
  5. Overview: Choosing a language Many considerations political, human, technical Runtime

    performance, reliability, configurability Knowledge culture, mindshare, resources, signal to noise ratio Tooling development, build/release, configuration, deployment
  6. Overview: Choosing a language Many considerations political, human, technical Runtime

    performance, reliability, configurability Knowledge culture, mindshare, resources, signal to noise ratio Tooling development, build/release, configuration, deployment
  7. Overview: Choosing a language Many considerations political, human, technical Runtime

    performance, reliability, configurability Knowledge culture, mindshare, resources, signal to noise ratio Tooling development, build/release, configuration, deployment
  8. Overview: Agenda My Claims / Hypotheses Laziness, Functional, Type System

    Toolkit & Runtime Library Ecosystem Pitfalls & Hurdles
  9. My Claims Performance is reasonable on par with Java and

    C# Mono; 2-3x CPU times of C (approx); BUT always doubt benchmarks http://shootout.alioth.debian.org/u64q/haskell.php Productivity with long-term benefits after initial steep learning curve Haskell types offer stronger verifiability strong and meaningful checks applied Pure functional code is easier to test probably not controversial
  10. My Claims Performance is reasonable on par with Java and

    C# Mono; 2-3x CPU times of C (approx); BUT always doubt benchmarks http://shootout.alioth.debian.org/u64q/haskell.php Productivity with long-term benefits after initial steep learning curve Haskell types offer stronger verifiability strong and meaningful checks applied Pure functional code is easier to test probably not controversial
  11. My Claims Performance is reasonable on par with Java and

    C# Mono; 2-3x CPU times of C (approx); BUT always doubt benchmarks http://shootout.alioth.debian.org/u64q/haskell.php Productivity with long-term benefits after initial steep learning curve Haskell types offer stronger verifiability strong and meaningful checks applied Pure functional code is easier to test probably not controversial
  12. My Claims Performance is reasonable on par with Java and

    C# Mono; 2-3x CPU times of C (approx); BUT always doubt benchmarks http://shootout.alioth.debian.org/u64q/haskell.php Productivity with long-term benefits after initial steep learning curve Haskell types offer stronger verifiability strong and meaningful checks applied Pure functional code is easier to test probably not controversial
  13. Example: doubleSum 3 (2 + 3) Call by value doubleSum

    3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  14. Example: doubleSum 3 (2 + 3) Call by value doubleSum

    3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  15. Example: doubleSum 3 (2 + 3) Call by value doubleSum

    3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  16. Example: doubleSum 3 (2 + 3) Call by value doubleSum

    3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  17. Example: doubleSum 3 (2 + 3) Call by value doubleSum

    3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  18. Example: doubleSum 3 (2 + 3) Call by value doubleSum

    3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  19. Example: doubleSum 3 (2 + 3) Call by value (evaluates

    inner-most expressions first) doubleSum 3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  20. Example: doubleSum 3 (2 + 3) Call by value (evaluates

    inner-most expressions first) doubleSum 3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  21. Example: doubleSum 3 (2 + 3) Call by value (evaluates

    inner-most expressions first) doubleSum 3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  22. Example: doubleSum 3 (2 + 3) Call by value (evaluates

    inner-most expressions first) doubleSum 3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  23. Example: doubleSum 3 (2 + 3) Call by value (evaluates

    inner-most expressions first) doubleSum 3 (2 + 3) → doubleSum 3 5 → 2 * (3 + 5) → 2 * 8 → 16 Call by name (evaluates outer-most expressions first) doubleSum 3 (2 + 3) → (λ x -> 2 * (3 + x)) (2 + 3)
  24. Laziness: Buyer Beware filter (λ x → x < 6)

    [1..] (never terminates) takeWhile (λ x → x < 6) [1..] (does terminate) dropWhile (λ x → x >= 6) [1..] (does not terminate) Need to understand implications of laziness on functions Laziness with I/O implications lazy I/O with handles is problematic, but iteratee idiom solves most of these. There are a number of libraries available to help with this: enumerator, pipes, . . .
  25. Laziness: Buyer Beware filter (λ x → x < 6)

    [1..] (never terminates) takeWhile (λ x → x < 6) [1..] (does terminate) dropWhile (λ x → x >= 6) [1..] (does not terminate) Need to understand implications of laziness on functions Laziness with I/O implications lazy I/O with handles is problematic, but iteratee idiom solves most of these. There are a number of libraries available to help with this: enumerator, pipes, . . .
  26. Laziness: Buyer Beware filter (λ x → x < 6)

    [1..] (never terminates) takeWhile (λ x → x < 6) [1..] (does terminate) dropWhile (λ x → x >= 6) [1..] (does not terminate) Need to understand implications of laziness on functions Laziness with I/O implications lazy I/O with handles is problematic, but iteratee idiom solves most of these. There are a number of libraries available to help with this: enumerator, pipes, . . .
  27. Laziness: Buyer Beware filter (λ x → x < 6)

    [1..] (never terminates) takeWhile (λ x → x < 6) [1..] (does terminate) dropWhile (λ x → x >= 6) [1..] (does not terminate) Need to understand implications of laziness on functions Laziness with I/O implications lazy I/O with handles is problematic, but iteratee idiom solves most of these. There are a number of libraries available to help with this: enumerator, pipes, . . .
  28. Laziness: Buyer Beware filter (λ x → x < 6)

    [1..] (never terminates) takeWhile (λ x → x < 6) [1..] (does terminate) dropWhile (λ x → x >= 6) [1..] (does not terminate) Need to understand implications of laziness on functions Laziness with I/O implications lazy I/O with handles is problematic, but iteratee idiom solves most of these. There are a number of libraries available to help with this: enumerator, pipes, . . .
  29. Laziness: Also Pretty Suuweeeet! Infinite sequences/lists made possible Recursive functions

    become practical Recursive types become simple Much more as well ...
  30. Laziness: Also Pretty Suuweeeet! Infinite sequences/lists made possible Recursive functions

    become practical Recursive types become simple Much more as well ...
  31. Laziness: Also Pretty Suuweeeet! Infinite sequences/lists made possible Recursive functions

    become practical Recursive types become simple Much more as well ...
  32. Laziness: Also Pretty Suuweeeet! Infinite sequences/lists made possible Recursive functions

    become practical Recursive types become simple Much more as well ...
  33. Purity + Laziness=> Reasoning Equality (referential transparency) Can replace occurrences

    of LHS with RHS Higher Order Functions encourage exploitation of higher-level patterns Function Composition leads to greater reuse
  34. Purity + Laziness=> Reasoning Equality (referential transparency) Can replace occurrences

    of LHS with RHS Higher Order Functions encourage exploitation of higher-level patterns Function Composition leads to greater reuse
  35. Purity + Laziness=> Reasoning Equality (referential transparency) Can replace occurrences

    of LHS with RHS Higher Order Functions encourage exploitation of higher-level patterns Function Composition leads to greater reuse
  36. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  37. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  38. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  39. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  40. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  41. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  42. mysum :: Num a => [a] -> a mysum xs

    = foldr (+) 0 xs myproduct :: Num a => [a] -> a myproduct xs = foldr (*) 1 xs myany :: (a -> Bool) -> [a] -> Bool myany pred xs = foldr (\ x b -> b || pred x) False xs myall :: (a -> Bool) -> [a] -> Bool myall pred xs = foldr (\ x b -> b && pred x) True xs
  43. class Monoid m where mappend :: m -> m ->

    m mempty :: m instance Num a => Monoid a where mappend :: m -> m -> m mappend x y = (+) x y mempty :: m mempty = 0 instance Monoid Bool where mappend :: m -> m -> m mappend True _ = True mappend _ True = True mappend _ _ = False mempty :: m
  44. class Monoid m where mappend :: m -> m ->

    m mempty :: m instance Num a => Monoid a where mappend :: m -> m -> m mappend x y = (+) x y mempty :: m mempty = 0 instance Monoid Bool where mappend :: m -> m -> m mappend True _ = True mappend _ True = True mappend _ _ = False mempty :: m
  45. class Monoid m where mappend :: m -> m ->

    m mempty :: m instance Num a => Monoid a where mappend :: m -> m -> m mappend x y = (+) x y mempty :: m mempty = 0 instance Monoid Bool where mappend :: m -> m -> m mappend True _ = True mappend _ True = True mappend _ _ = False mempty :: m
  46. Haskell type signatures can . . . express side effects

    e.g. String -> IO Int declare computational strategies e.g. Num a => [a] -> Sum a impose constraints e.g. Num a => a -> a question value availability e.g. String -> Maybe Int verify client-server protocol dialogs? an exercise for reader ;)
  47. Haskell type signatures can . . . express side effects

    e.g. String -> IO Int declare computational strategies e.g. Num a => [a] -> Sum a impose constraints e.g. Num a => a -> a question value availability e.g. String -> Maybe Int verify client-server protocol dialogs? an exercise for reader ;)
  48. Haskell type signatures can . . . express side effects

    e.g. String -> IO Int declare computational strategies e.g. Num a => [a] -> Sum a impose constraints e.g. Num a => a -> a question value availability e.g. String -> Maybe Int verify client-server protocol dialogs? an exercise for reader ;)
  49. Haskell type signatures can . . . express side effects

    e.g. String -> IO Int declare computational strategies e.g. Num a => [a] -> Sum a impose constraints e.g. Num a => a -> a question value availability e.g. String -> Maybe Int verify client-server protocol dialogs? an exercise for reader ;)
  50. Haskell type signatures can . . . express side effects

    e.g. String -> IO Int declare computational strategies e.g. Num a => [a] -> Sum a impose constraints e.g. Num a => a -> a question value availability e.g. String -> Maybe Int verify client-server protocol dialogs? an exercise for reader ;)
  51. Interfaces in OO . . . Figure: Class definitions are

    married to the interfaces they implement.
  52. Interfaces in Haskell: Typeclasses. . . Decouple type definition from

    interface Allow upstream implementations Extend thirdparty libraries easily Redefine implementations upstream No meaningless "any type" functions Very flexible
  53. Interfaces in Haskell: Typeclasses. . . Decouple type definition from

    interface Allow upstream implementations Extend thirdparty libraries easily Redefine implementations upstream No meaningless "any type" functions Very flexible
  54. Interfaces in Haskell: Typeclasses. . . Decouple type definition from

    interface Allow upstream implementations Extend thirdparty libraries easily Redefine implementations upstream No meaningless "any type" functions Very flexible
  55. Interfaces in Haskell: Typeclasses. . . Decouple type definition from

    interface Allow upstream implementations Extend thirdparty libraries easily Redefine implementations upstream No meaningless "any type" functions Very flexible
  56. Interfaces in Haskell: Typeclasses. . . Decouple type definition from

    interface Allow upstream implementations Extend thirdparty libraries easily Redefine implementations upstream No meaningless "any type" functions Very flexible
  57. Interfaces in Haskell: Typeclasses. . . Decouple type definition from

    interface Allow upstream implementations Extend thirdparty libraries easily Redefine implementations upstream No meaningless "any type" functions Very flexible
  58. class (Eq a) => Ord a where compare :: a

    -> a -> Ordering compare x y | x == y = EQ | x <= y = LT | otherwise = GT (<), (>), (>=), (<=) :: a -> a -> Bool ... max, min :: a -> a -> a ...
  59. Typically this just works . . . data SimpleShape =

    Square { size :: Double } | Circle { radius :: Double } deriving (Eq, Ord, Show) We explicitly use the default definitions . . . and when it doesn’t . . . instance Ord SimpleShape where ...
  60. Haskell Tooling: Runtime Reasonably performant between JVM 7 and C#

    Mono performance GC settings easily customized Numerous other runtime options
  61. Haskell Tooling: Runtime Reasonably performant between JVM 7 and C#

    Mono performance GC settings easily customized Numerous other runtime options
  62. Haskell Tooling: Runtime Reasonably performant between JVM 7 and C#

    Mono performance GC settings easily customized Numerous other runtime options
  63. Haskell Tooling: Tools Testing tools QuickCheck, HUnit Documentation tools Haddock,

    Hoogle (lookup documentation) Build tools Cabal, cabal-dev, cabal-nirvana, see "next slide"
  64. Haskell Tooling: Tools Testing tools QuickCheck, HUnit Documentation tools Haddock,

    Hoogle (lookup documentation) Build tools Cabal, cabal-dev, cabal-nirvana, see "next slide"
  65. Haskell Tooling: Tools Testing tools QuickCheck, HUnit Documentation tools Haddock,

    Hoogle (lookup documentation) Build tools Cabal, cabal-dev, cabal-nirvana, see "next slide"
  66. Haskell Tooling: Dependency Management Hackage database of freely available Haskell

    libraries Cabal great to get started, BUT . . . cabal-dev & similar provides sandboxing, list RVM with gemsets; more important for statically typed environments cabal-nirvana think compatible distribution snapshot of Hackage DB
  67. Haskell Tooling: Dependency Management Hackage database of freely available Haskell

    libraries Cabal great to get started, BUT . . . cabal-dev & similar provides sandboxing, list RVM with gemsets; more important for statically typed environments cabal-nirvana think compatible distribution snapshot of Hackage DB
  68. Haskell Tooling: Dependency Management Hackage database of freely available Haskell

    libraries Cabal great to get started, BUT . . . cabal-dev & similar provides sandboxing, list RVM with gemsets; more important for statically typed environments cabal-nirvana think compatible distribution snapshot of Hackage DB
  69. Haskell Tooling: Dependency Management Hackage database of freely available Haskell

    libraries Cabal great to get started, BUT . . . cabal-dev & similar provides sandboxing, list RVM with gemsets; more important for statically typed environments cabal-nirvana think compatible distribution snapshot of Hackage DB
  70. Haskell Tooling: Don’ts for Newbies Use GHC (not HUGS) Hugs

    written for educational purposes not industrial usage Forget what you know (imperative/OO) relearn programming in a functional-style return is a function name it does not mean return in the C/Java/C# way class does not mean OO-class think decoupled interface with optional default impelementations and a lot more power
  71. Haskell Tooling: Don’ts for Newbies Use GHC (not HUGS) Hugs

    written for educational purposes not industrial usage Forget what you know (imperative/OO) relearn programming in a functional-style return is a function name it does not mean return in the C/Java/C# way class does not mean OO-class think decoupled interface with optional default impelementations and a lot more power
  72. Haskell Tooling: Don’ts for Newbies Use GHC (not HUGS) Hugs

    written for educational purposes not industrial usage Forget what you know (imperative/OO) relearn programming in a functional-style return is a function name it does not mean return in the C/Java/C# way class does not mean OO-class think decoupled interface with optional default impelementations and a lot more power
  73. Haskell Tooling: Don’ts for Newbies Use GHC (not HUGS) Hugs

    written for educational purposes not industrial usage Forget what you know (imperative/OO) relearn programming in a functional-style return is a function name it does not mean return in the C/Java/C# way class does not mean OO-class think decoupled interface with optional default impelementations and a lot more power
  74. Haskell Tooling: Suggestions Explicit language extensions Intentionally and explicitly enable

    per module Sandbox your builds with cabal-dev or similar Think in types and shapes and use Hoogle to lookup based on types and function "shapes"
  75. Haskell Tooling: Suggestions Explicit language extensions Intentionally and explicitly enable

    per module Sandbox your builds with cabal-dev or similar Think in types and shapes and use Hoogle to lookup based on types and function "shapes"
  76. Haskell Tooling: Suggestions Explicit language extensions Intentionally and explicitly enable

    per module Sandbox your builds with cabal-dev or similar Think in types and shapes and use Hoogle to lookup based on types and function "shapes"
  77. Oh, the possibilities! Parallel / Concurrency Options threads, dataflow, par,

    seq "Cloud" Haskell A kind of Erlang/OTP clone in Haskell Data Parallel Haskell GHC extensions to support nested data parallelism accounting, "Nepal" Haskell’s Foreign Function Interface (FFI) Interface with native code from Haskell GPU Programming in Haskell Obsidian, Nikola, GpuGen, numerous papers on this too Much more. . . Research meeting industrial application
  78. Oh, the possibilities! Parallel / Concurrency Options threads, dataflow, par,

    seq "Cloud" Haskell A kind of Erlang/OTP clone in Haskell Data Parallel Haskell GHC extensions to support nested data parallelism accounting, "Nepal" Haskell’s Foreign Function Interface (FFI) Interface with native code from Haskell GPU Programming in Haskell Obsidian, Nikola, GpuGen, numerous papers on this too Much more. . . Research meeting industrial application
  79. Oh, the possibilities! Parallel / Concurrency Options threads, dataflow, par,

    seq "Cloud" Haskell A kind of Erlang/OTP clone in Haskell Data Parallel Haskell GHC extensions to support nested data parallelism accounting, "Nepal" Haskell’s Foreign Function Interface (FFI) Interface with native code from Haskell GPU Programming in Haskell Obsidian, Nikola, GpuGen, numerous papers on this too Much more. . . Research meeting industrial application
  80. Oh, the possibilities! Parallel / Concurrency Options threads, dataflow, par,

    seq "Cloud" Haskell A kind of Erlang/OTP clone in Haskell Data Parallel Haskell GHC extensions to support nested data parallelism accounting, "Nepal" Haskell’s Foreign Function Interface (FFI) Interface with native code from Haskell GPU Programming in Haskell Obsidian, Nikola, GpuGen, numerous papers on this too Much more. . . Research meeting industrial application
  81. Oh, the possibilities! Parallel / Concurrency Options threads, dataflow, par,

    seq "Cloud" Haskell A kind of Erlang/OTP clone in Haskell Data Parallel Haskell GHC extensions to support nested data parallelism accounting, "Nepal" Haskell’s Foreign Function Interface (FFI) Interface with native code from Haskell GPU Programming in Haskell Obsidian, Nikola, GpuGen, numerous papers on this too Much more. . . Research meeting industrial application
  82. Oh, the possibilities! Parallel / Concurrency Options threads, dataflow, par,

    seq "Cloud" Haskell A kind of Erlang/OTP clone in Haskell Data Parallel Haskell GHC extensions to support nested data parallelism accounting, "Nepal" Haskell’s Foreign Function Interface (FFI) Interface with native code from Haskell GPU Programming in Haskell Obsidian, Nikola, GpuGen, numerous papers on this too Much more. . . Research meeting industrial application
  83. Bonus: References / Resources Channel 9 Lectures (Erik Meijer) http://channel9.msdn.com/Shows/Going+Deep/

    Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1 Learn You A Haskell http://learnyouahaskell.com Haskell Reddit http://www.reddit.com/r/haskell/ Haskell Cafe http://www.haskell.org/mailman/listinfo/haskell-cafe Real World Haskell http://book.realworldhaskell.org/
  84. Bonus: References / Resources Channel 9 Lectures (Erik Meijer) http://channel9.msdn.com/Shows/Going+Deep/

    Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1 Learn You A Haskell http://learnyouahaskell.com Haskell Reddit http://www.reddit.com/r/haskell/ Haskell Cafe http://www.haskell.org/mailman/listinfo/haskell-cafe Real World Haskell http://book.realworldhaskell.org/
  85. Bonus: References / Resources Channel 9 Lectures (Erik Meijer) http://channel9.msdn.com/Shows/Going+Deep/

    Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1 Learn You A Haskell http://learnyouahaskell.com Haskell Reddit http://www.reddit.com/r/haskell/ Haskell Cafe http://www.haskell.org/mailman/listinfo/haskell-cafe Real World Haskell http://book.realworldhaskell.org/
  86. Bonus: References / Resources Channel 9 Lectures (Erik Meijer) http://channel9.msdn.com/Shows/Going+Deep/

    Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1 Learn You A Haskell http://learnyouahaskell.com Haskell Reddit http://www.reddit.com/r/haskell/ Haskell Cafe http://www.haskell.org/mailman/listinfo/haskell-cafe Real World Haskell http://book.realworldhaskell.org/
  87. Bonus: References / Resources Channel 9 Lectures (Erik Meijer) http://channel9.msdn.com/Shows/Going+Deep/

    Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1 Learn You A Haskell http://learnyouahaskell.com Haskell Reddit http://www.reddit.com/r/haskell/ Haskell Cafe http://www.haskell.org/mailman/listinfo/haskell-cafe Real World Haskell http://book.realworldhaskell.org/
  88. Bonus: Brief QuickCheck Example module Tests where import Test.QuickCheck (quickCheck)

    propReverseReverse :: [Char] -> Bool propReverseReverse s = (reverse . reverse) s == s excuse the weird syntax form, indenting didn’t show up ;( main = do {quickCheck propReverseReverse }