Skip to content

Instantly share code, notes, and snippets.

@pbrisbin
Created June 4, 2014 18:02
Show Gist options
  • Save pbrisbin/bca300b913bcb0f1b533 to your computer and use it in GitHub Desktop.
Save pbrisbin/bca300b913bcb0f1b533 to your computer and use it in GitHub Desktop.
-- Within an implementation of the TODO app from LYAH, there was something like
-- this...
data Todo = Todo
newtype Add = Add (Either String Todo)
newtype Remove = Remove (Either String ())
newtype Complete = Complete (Either String Todo)
class Respond a where
-- or something, not important
respond a :: a -> IO ()
instance Respond Add where
respond (Add (Right _ t) = putStrLn $ "Added " ++ show t
respond (Add (Left e _) = error e
instance Respond Remove
respond (Add (Right _ ()) = putStrLn "Todo removed!"
respond (Add (Left e _) = error e
instance Respond Complete
respond (Add (Right _ t) = putStrLn $ "Completed " ++ show t
respond (Add (Left e _) = error e
-- My suggestion:
data Action = Add Todo | Remove | Complete Todo
type Response = Either String Action
respond :: Response -> IO ()
respond (Right (Add t)) = putStrLn $ "Added " ++ show t
respond (Right Remove) = putStrLn $ "Todo removed!"
respond (Right (Complete t)) = putStrLn $ "Completed " ++ show t
respond (Left e) = error e
-- I feel this kind of over-engineering happens to Rubyists specifically,
-- because they don't realize Sum types are available, since they're lacking in
-- Ruby (and most languages).
@pbrisbin
Copy link
Author

pbrisbin commented Jun 4, 2014

I agree pretty much entirely with your sentiment. I think that the difference really comes down to what type of application you're writing. I think it's unlikely when writing a non-library application that you will have a group of values that are similar enough to fit in a type class, but desperate enough that they can't be constructors of a single (sum) type.

This is regardless of scale. For non-library applications, you don't have the issue of defining behavior for types you a) don't know about yet and b) won't be adding yourself in the future. That is when I would for type classes.

Going with a simpler sum type and using pattern exhaustive-ness warnings to ensure correctness when adding new constructors is the way to go 99% of the time (huge, IMO disclaimer here).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment