Skip to content

Instantly share code, notes, and snippets.

@gabebw
Created August 19, 2015 18:29
Show Gist options
  • Save gabebw/a794bacec6760c00daaa to your computer and use it in GitHub Desktop.
Save gabebw/a794bacec6760c00daaa to your computer and use it in GitHub Desktop.
{-
The expression problem: Adding new data types and new functionality to
existing data types is at odds.
OOP:
* adding new data types is easy
- just write new code, and adhere to the API
* But adding new functionality to existing data types is hard
- e.g. having to add `prettyPrint` to every class in the system
- requires editing all existing classes
FP:
* adding new data types to the system is hard
- all functions that act on those data types must change to accommodate the new type
* but adding new functionality to existing types is easy
- just add a new function and pattern-match on existing data types
-}
-- Typeclasses solve the expression problem (ish):
-- Without changing existing code, we can make functions act on new datatypes
-- that conform to a typeclass.
-- Let's take this function:
-- myShow :: (Show a) => a -> String
-- myShow thing = "It's me: " ++ thing
-- Say we have this datatype:
data Fish = Carp | Salmon
-- And we want a function, `wow`, that takes these data types and says e.g.
-- "Wow, it's Carp", "Wow, it's Salmon", etc.
--
-- So we write this:
wow Carp = "Wow, it's Carp"
wow Salmon = "Wow, it's Salmon"
-- Now let's add another data type:
data Metal = Steel | Gold
-- Since we have a new type, we need to change `wow` -- which is *code we
-- already wrote* -- in order to make `wow` work with our
-- new data type:
wow Gold = "Wow, it's Gold"
wow Steel = "Wow, it's Steel"
-- On the flip side, Haskell makes adding a new function that acts on all
-- existing data types easy. We don't have to change any existing code, this is
-- 100% brand new:
notImpressed Carp = "Ugh, it's Carp"
notImpressed Salmon = "Ugh, it's Salmon"
notImpressed Gold = "Ugh, it's Gold"
notImpressed Steel = "Ugh, it's Steel"
-- But what about typeclasses? Type classes let us add new functionality
-- to existing types without changing existing code.
-- For example, let's assume we have just `Fish`, like before.
class Wow a where
wow :: a -> String
data Fish = Carp | Salmon
instance Wow Fish where
wow Carp = "Wow, it's Carp"
wow Salmon = "Wow, it's Salmon"
-- Now we add Metal:
data Metal = Steel | Gold
-- We can add `wow` for Metal *without changing existing code*
instance Wow Metal where
wow Steel = "Wow, it's Steel"
wow Gold = "Wow, it's Gold"
-- Neat!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment