data Bool = False | True
data Point = Point Float Float
  let x = Point 3.0 4.0 :: Point
  data Shape = Circle Point Float
  data Shape = Circle Point Float | Rectangle Point Point
  ghci> :t Point
Point :: Float -> Float -> Point
  Constructors can be partially applied
ghci> let points = map (Point 0) [1 2 3]
  Why doesn’t this work?
Prelude> map (Point 1) [0, 2, 3]
:7:1:
No instance for (Show Point) arising from a use of `print'
Possible fix: add an instance declaration for (Show Point)
In a stmt of an interactive GHCi command: print it
 
  deriving
      keyword used to give typeclasses to datatypes
    data Point = Point Float Float deriving (Show)
How do we compute the area of a Shape?
area :: Shape -> Float
area s = ...
  Pattern matching to the rescue!
area :: Shape -> Float
area (Circle center radius) = pi * r ^ 2
area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
  myFavoriteShape :: Shape
...
doILikeCircles =
    case myFavoriteShape of
    Circle _ _ -> True
    Rectangle _ _ -> False
  
data Person = Person String String String String Int Float
  age :: Person -> Int
age (Person _ _ _ _ a _) = a
  Oh hell no. This is bad.
ghci> data Person = Person {
    firstName :: String,
    lastName :: String,
    phoneNumber :: String,
    emailAddress :: String,
    age :: Int,
    height :: Float
    } deriving (Show)
ghci> let chuck = Person {
    firstName = "Chuck",
    lastName = "Norris",
    phoneNumber = "(123) 456-7890",
    emailAddress = "chuck@norr.is",
    age = -5,
    height = 200
    }
ghci> height chuck
200
  data Tree = EmptyTree | Node Int Tree Tree
  Instead of defining a type, we define a Type constructor
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
  
      One caveat:
      Tree
      is NOT a type, it is a
      type constructor
    
This is an invalid type declaration
insert :: a -> Tree -> Tree
    This is correct
insert :: a -> Tree a -> Tree a
  data List a = Nil | Cons a (List a)
  Nil => []
      Cons x xs => (x:xs)
      Cons x Nil => [x]
      getLine
        and
        putStrLn
        ?
      
      If we try to declare
      getLine :: String
      it must always return the same string
    
This is not what we want
      If we try to declare
      putStrLn :: String -> ()
      it is not referentially transparent as it has a side effect
    
greet :: IO ()
greet = do
    putStr "What is your name? "
    name <- getLine
    putStrLn $ "Hi " ++ name ++ "!"
    return ()
  It’s a () wrapped in an IO
It’s a String wrapped in an IO
This may be a bit more useful
greet :: IO String
greet = do
    putStr "What is your name? "
    name <- getLine
    putStrLn $ "Hi " ++ name ++ "!"
    return name
  return
        in Haskell is unlike any other return you have seen before
      ghci> :t return
return :: Monad m => a -> m a
  That’s scary.
return
        wraps an object in an IO
      do
        block is the return value of the function
      What does this do?
helloWorld :: IO ()
helloWorld = do
    return ()
    putStrLn "Hello World!"
  main
      function
    main :: IO ()
main = ...