From b22ec6de8428e540da79a6dffcb316542bf84fff Mon Sep 17 00:00:00 2001 From: Nadia Polikarpova Date: Fri, 24 May 2024 14:15:57 -0700 Subject: [PATCH] update page --- docs/lectures/07-classes.html | 412 +++++++++++++++++----------------- lectures/07-classes.md | 224 +++++++++--------- 2 files changed, 314 insertions(+), 322 deletions(-) diff --git a/docs/lectures/07-classes.html b/docs/lectures/07-classes.html index 682bab9..0d52875 100644 --- a/docs/lectures/07-classes.html +++ b/docs/lectures/07-classes.html @@ -260,7 +260,7 @@

Type Classes: Outline

  • Why type classes?
  • Standard type classes
  • Creating new instances
  • -
  • Using type classes
  • +
  • Typeclasses and Polymorphism
  • Creating new type classes

  • @@ -497,7 +497,7 @@

    Type Classes: Outline

  • Why type classes? [done]
  • Standard type classes
  • Creating new instances
  • -
  • Using type classes
  • +
  • Typeclasses and Polymorphism
  • Creating new type classes

  • @@ -552,16 +552,43 @@

    The

    +

    The Ord Typeclass

    +

    The type class Ord is for totally ordered values:

    +
    class Eq a => Ord a where
    +  (<)  :: a -> a -> Bool
    +  (<=) :: a -> a -> Bool
    +  (>)  :: a -> a -> Bool
    +  (>=) :: a -> a -> Bool
    +

    For example:

    +
    λ> 2 < 3
    +True
    +
    +λ> "cat" < "dog"
    +True
    +


    +

    +

    Note Eq a => in the class definition!

    +

    A type T is an instance of Ord if

    +
      +
    1. T is also an instance of Eq, and
    2. +
    3. It defines functions for comparing values for inequality
    4. +
    +


    +
    +
    +
    +
    +

    The Num Type Class

    The type class Num requires that instances define a bunch of arithmetic operations

    -
    class Num a where
    -  (+) :: a -> a -> a
    -  (-) :: a -> a -> a
    -  (*) :: a -> a -> a
    -  negate :: a -> a
    -  abs :: a -> a
    -  signum :: a -> a
    -  fromInteger :: Integer -> a
    +
    class Num a where
    +  (+) :: a -> a -> a
    +  (-) :: a -> a -> a
    +  (*) :: a -> a -> a
    +  negate :: a -> a
    +  abs :: a -> a
    +  signum :: a -> a
    +  fromInteger :: Integer -> a




    @@ -570,49 +597,80 @@

    The The Show Type Class

    The type class Show requires that instances be convertible to String

    -
    class Show a  where
    -  show :: a -> String
    +
    class Show a  where
    +  show :: a -> String

    Indeed, we can test this on different (built-in) types

    -
    λ> show 2
    -"2"
    -
    -λ> show 3.14
    -"3.14"
    -
    -λ> show (1, "two", ([],[],[]))
    -"(1,\"two\",([],[],[]))"
    +
    λ> show 2
    +"2"
    +
    +λ> show 3.14
    +"3.14"
    +
    +λ> show (1, "two", ([],[],[]))
    +"(1,\"two\",([],[],[]))"






    +
    +
    +
    +

    -

    The Ord Typeclass

    -

    The type class Ord is for totally ordered values:

    -
    class Eq a => Ord a where
    -  (<)  :: a -> a -> Bool
    -  (<=) :: a -> a -> Bool
    -  (>)  :: a -> a -> Bool
    -  (>=) :: a -> a -> Bool
    -

    For example:

    -
    λ> 2 < 3
    -True
    -
    -λ> "cat" < "dog"
    -True
    +

    The Read Typeclass

    +
    -- Not the actual definition, but almost:
    +class Read a where
    +  read :: String -> a
    +

    Read is the opposite of Show

    +
      +
    • It requires that every instance T can parse a string and turn it into T

    • +
    • Just like with Show, most standard type are instances of Read:

      +
        +
      • Int, Integer, Double, Char, Bool, etc
      • +
    • +


    +
    +
    +
    +
    +
    +

    +

    -

    Note Eq a => in the class definition!

    -

    A type T is an instance of Ord if

    -
      -
    1. T is also an instance of Eq, and
    2. -
    3. It defines functions for comparing values for inequality
    4. -
    - +

    QUIZ

    +

    What does the expression read "2" evaluate to?

    +

    (A) Type error

    +

    (B) "2"

    +

    (C) 2

    +

    (D) 2.0

    +

    (E) Run-time error

    +


    +
    +
    +
    +
    +

    +

    Haskell is foxed!

    +
      +
    • Doesn’t know what type to convert the string to!
    • +
    • Doesn’t know which of the read functions to run!
    • +
    +

    Did we want an Int or a Double or maybe something else altogether?

    +


    +

    +

    Thus, here an explicit type annotation is needed to tell Haskell +what to convert the string to:

    +
    λ> (read "2") :: Int
    +2
    +
    +λ> (read "2") :: Float
    +2.0
    +
    +λ> (read "2") :: String
    +???
    +

    Note the different results due to the different types.




    @@ -642,7 +700,7 @@

    Type Classes: Outline

  • Why type classes? [done]
  • Standard type classes [done]
  • Creating new instances
  • -
  • Using type classes
  • +
  • Typeclasses and Polymorphism
  • Creating new type classes

  • @@ -657,19 +715,19 @@

    Type Classes: Outline

    Showing Your Colors

    Let’s create a new datatype:

    -
    data Color = Red | Green
    +
    data Color = Red | Green

    and play with it in GHCi:

    -
    λ> let col = Red
    -λ> :type col
    -x :: Color
    +
    λ> let col = Red
    +λ> :type col
    +x :: Color

    So far, so good… but we cannot view them!

    -
    λ> col
    -
    -<interactive>:1:0:
    -    No instance for (Show Color)
    -      arising from a use of `print' at <interactive>:1:0
    -    Possible fix: add an instance declaration for (Show Color)
    -    In a stmt of a 'do' expression: print it
    +
    λ> col
    +
    +<interactive>:1:0:
    +    No instance for (Show Color)
    +      arising from a use of `print' at <interactive>:1:0
    +    Possible fix: add an instance declaration for (Show Color)
    +    In a stmt of a 'do' expression: print it

    Why is this happening?



    @@ -687,14 +745,14 @@

    Showing Your Colors



    We also cannot compare colors!

    -
    λ> col == Green
    -
    -<interactive>:1:0:
    -    No instance for (Eq Color)
    -      arising from a use of `==' at <interactive>:1:0-5
    -    Possible fix: add an instance declaration for (Eq Color)
    -    In the expression: col == Green
    -    In the definition of `it': it = col == Green
    +
    λ> col == Green
    +
    +<interactive>:1:0:
    +    No instance for (Eq Color)
    +      arising from a use of `==' at <interactive>:1:0-5
    +    Possible fix: add an instance declaration for (Eq Color)
    +    In the expression: col == Green
    +    In the definition of `it': it = col == Green



    How do we add an instance declaration for Show Color and Eq Color?

    @@ -713,12 +771,12 @@

    Creating Instances

    • create instances of Eq and Show for that type:
    -
    instance Show Color where
    -  show Red   = "Red"
    -  show Green = "Green"
    -  
    -instance Eq Color where
    -  ???
    +
    instance Show Color where
    +  show Red   = "Red"
    +  show Green = "Green"
    +  
    +instance Eq Color where
    +  ???




    @@ -731,15 +789,15 @@

    Creating Instances


    EXERCISE: Creating Instances

    Create an instance of Eq for Color:

    -
    data Color = Red | Green
    -  
    -instance Eq Color where
    -  ???
    -
    --- Reminder:
    -class  Eq a  where
    -  (==) :: a -> a -> Bool
    -  (/=) :: a -> a -> Bool
    +
    data Color = Red | Green
    +  
    +instance Eq Color where
    +  ???
    +
    +-- Reminder:
    +class  Eq a  where
    +  (==) :: a -> a -> Bool
    +  (/=) :: a -> a -> Bool




    @@ -750,23 +808,23 @@

    EXERCISE: Creating Instances




    -

    QUIZ

    +

    QUIZ

    Which of the following Eq instances for Color are valid?

    -
    -- (A)
    -instance Eq Color where
    -  (==) Red   Red   = True
    -  (==) Green Green = True
    -  (==) _     _     = False
    -
    --- (B)
    -instance Eq Color where
    -  (/=) Red   Red   = False
    -  (/=) Green Green = False
    -  (/=) _     _     = True
    -
    --- (C) Neither of the above
    -
    --- (D) Either of the above
    +
    -- (A)
    +instance Eq Color where
    +  (==) Red   Red   = True
    +  (==) Green Green = True
    +  (==) _     _     = False
    +
    +-- (B)
    +instance Eq Color where
    +  (/=) Red   Red   = False
    +  (/=) Green Green = False
    +  (/=) _     _     = True
    +
    +-- (C) Neither of the above
    +
    +-- (D) Either of the above




    @@ -780,12 +838,12 @@

    QUIZ


    Default Method Implementations

    The Eq class is actually defined like this:

    -
    class  Eq a  where
    -  (==) :: a -> a -> Bool
    -  (==) x y = not (x /= y) -- Default implementation!
    -  
    -  (/=) :: a -> a -> Bool
    -  (/=) x y = not (x == y) -- Default implementation!
    +
    class  Eq a  where
    +  (==) :: a -> a -> Bool
    +  (==) x y = not (x /= y) -- Default implementation!
    +  
    +  (/=) :: a -> a -> Bool
    +  (/=) x y = not (x == y) -- Default implementation!



    The class provides default implementations for its methods

    @@ -793,11 +851,11 @@

    Default Method Implementations

  • An instance can define any of the two methods and get the other one for free

  • Use :info to find out which methods you have to define:

  • -
    λ> :info Eq
    -class  Eq a  where
    -  (==) :: a -> a -> Bool
    -  (/=) :: a -> a -> Bool
    -  {-# MINIMAL (==) | (/=) #-} -- HERE HERE!!!
    +
    λ> :info Eq
    +class  Eq a  where
    +  (==) :: a -> a -> Bool
    +  (/=) :: a -> a -> Bool
    +  {-# MINIMAL (==) | (/=) #-} -- HERE HERE!!!




    @@ -805,12 +863,12 @@

    Default Method Implementations




    -

    QUIZ

    +

    QUIZ

    If you define:

    -
    instance Eq Color where
    -  -- Nothing here!
    +
    instance Eq Color where
    +  -- Nothing here!

    what will the following evaluate to?

    -
    λ> Red == Green
    +
    λ> Red == Green

    (A) Type error

    (B) Runs forever / stack overflow

    (C) Other runtime error

    @@ -831,16 +889,16 @@

    Automatic Derivation

    This is silly: we should be able to compare and view Colors “automatically”!

    Haskell lets us automatically derive functions for some classes in the standard library.

    To do so, we simply dress up the data type definition with

    -
    data Color = Red | Green
    -  deriving (Eq, Show) -- please generate instances automatically!
    +
    data Color = Red | Green
    +  deriving (Eq, Show) -- please generate instances automatically!

    Now we have

    -
    λ> let col = Red
    -
    -λ> col
    -Red
    -
    -λ> col == Red
    -True
    +
    λ> let col = Red
    +
    +λ> col
    +Red
    +
    +λ> col == Red
    +True




    @@ -856,7 +914,7 @@

    Type Classes: Outline

  • Why type classes? [done]
  • Standard type classes [done]
  • Creating new instances [done]
  • -
  • Using type classes
  • +
  • Typeclasses and Polymorphism
  • Creating new type classes

  • @@ -874,10 +932,10 @@

    Using Typeclasses



    Let’s build a small library for dictionaries mapping keys k to values v

    -
    data Dict k v
    -  = Empty                -- empty dictionary
    -  | Bind k v (Dict k v)  -- bind key `k` to the value `v`
    -  deriving (Show)
    +
    data Dict k v
    +  = Empty                -- empty dictionary
    +  | Bind k v (Dict k v)  -- bind key `k` to the value `v`
    +  deriving (Show)




    @@ -887,27 +945,27 @@

    Using Typeclasses


    The API

    We want to be able to do the following with Dict:

    -
    >>> let dict0 = add "cat" 10.0 (add "dog" 20.0 empty)
    -
    ->>> get "cat" dict0
    -10
    -
    ->>> get "dog" dict0
    -20
    -
    ->>> get "horse" dict0
    -error: key not found
    +
    >>> let dict0 = add "cat" 10.0 (add "dog" 20.0 empty)
    +
    +>>> get "cat" dict0
    +10
    +
    +>>> get "dog" dict0
    +20
    +
    +>>> get "horse" dict0
    +error: key not found



    Okay, lets implement!

    -
    -- | 'add key val dict' returns a new dictionary
    --- | that additionally maps `key` to `val`
    -add :: k -> v -> Dict k v -> Dict k v
    -add key val dict = ???
    -
    --- | 'get key dict' returns the value of `key` 
    -get :: k -> Dict k v -> v
    -get key dict = ???
    +
    -- | 'add key val dict' returns a new dictionary
    +-- | that additionally maps `key` to `val`
    +add :: k -> v -> Dict k v -> Dict k v
    +add key val dict = ???
    +
    +-- | 'get key dict' returns the value of `key` 
    +get :: k -> Dict k v -> v
    +get key dict = ???




    @@ -931,8 +989,8 @@

    The API


    Constraint Propagation

    Lets delete the types of add and get and see what Haskell says their types are!

    -
    λ> :type get
    -get :: (Eq k) => k -> v -> Dict k v -> Dict k v
    +
    λ> :type get
    +get :: (Eq k) => k -> v -> Dict k v -> Dict k v

    Haskell tells us that we can use any k type as a key as long as this type is an instance of the Eq typeclass.

    How, did GHC figure this out?

    @@ -963,76 +1021,12 @@

    EXERCISE: A Faster Dictionary




    -

    Explicit Type Annotations

    -

    Consider the standard typeclass Read:

    -
    -- Not the actual definition, but almost:
    -class Read a where
    -  read :: String -> a
    -

    Read is the opposite of Show

    -
      -
    • It requires that every instance T can parse a string and turn it into T

    • -
    • Just like with Show, most standard type are instances of Read:

      -
        -
      • Int, Integer, Double, Char, Bool, etc
      • -
    • -
    -


    -
    -
    -
    -
    -
    -

    -
    -

    -

    QUIZ

    -

    What does the expression read "2" evaluate to?

    -

    (A) Type error

    -

    (B) "2"

    -

    (C) 2

    -

    (D) 2.0

    -

    (E) Run-time error

    -


    -
    -
    -
    -
    -

    -

    Haskell is foxed!

    -
      -
    • Doesn’t know what type to convert the string to!
    • -
    • Doesn’t know which of the read functions to run!
    • -
    -

    Did we want an Int or a Double or maybe something else altogether?

    -


    -

    -

    Thus, here an explicit type annotation is needed to tell Haskell -what to convert the string to:

    -
    λ> (read "2") :: Int
    -2
    -
    -λ> (read "2") :: Float
    -2.0
    -
    -λ> (read "2") :: String
    -???
    -

    Note the different results due to the different types.

    -


    -
    -
    -
    -
    -
    -
    -
    -
    -

    Type Classes: Outline

    1. Why type classes? [done]
    2. Standard type classes [done]
    3. Creating new instances [done]
    4. -
    5. Using type classes [done]
    6. +
    7. Typeclasses and Polymorphism [done]
    8. Creating new type classes


    diff --git a/lectures/07-classes.md b/lectures/07-classes.md index b659ec5..900a1d5 100644 --- a/lectures/07-classes.md +++ b/lectures/07-classes.md @@ -36,7 +36,7 @@ Will help us add cool features to the Nano interpreter! 1. **Why type classes?** 2. Standard type classes 3. Creating new instances -4. Using type classes +4. Typeclasses and Polymorphism 5. Creating new type classes
    @@ -361,7 +361,7 @@ What would be a reasonable type for the equality operator? 1. Why type classes? [done] 2. **Standard type classes** 3. Creating new instances -4. Using type classes +4. Typeclasses and Polymorphism 5. Creating new type classes
    @@ -425,6 +425,46 @@ instance Eq Double ... ``` + +
    +
    +
    +
    +
    +
    + +## The `Ord` Typeclass + +The type class `Ord` is for totally ordered values: + +```haskell +class Eq a => Ord a where + (<) :: a -> a -> Bool + (<=) :: a -> a -> Bool + (>) :: a -> a -> Bool + (>=) :: a -> a -> Bool +``` + +For example: + +```haskell +λ> 2 < 3 +True + +λ> "cat" < "dog" +True +``` + +
    +
    + +Note `Eq a =>` in the class definition! + +A type `T` _is an instance of_ `Ord` if + +1. `T` is *also* an instance of `Eq`, and +2. It defines functions for comparing values for inequality +


    @@ -454,6 +494,7 @@ class Num a where

    + ## The `Show` Type Class The type class `Show` requires that instances be convertible to `String` @@ -482,44 +523,83 @@ Indeed, we can test this on different (built-in) types


    +
    +
    +
    +
    -## The `Ord` Typeclass - -The type class `Ord` is for totally ordered values: +## The `Read` Typeclass ```haskell -class Eq a => Ord a where - (<) :: a -> a -> Bool - (<=) :: a -> a -> Bool - (>) :: a -> a -> Bool - (>=) :: a -> a -> Bool +-- Not the actual definition, but almost: +class Read a where + read :: String -> a ``` -For example: +`Read` is the _opposite_ of `Show` + + - It requires that every instance `T` can parse a string and turn it into `T` + + - Just like with `Show`, most standard type are instances of `Read`: + + - `Int`, `Integer`, `Double`, `Char`, `Bool`, etc -```haskell -λ> 2 < 3 -True +
    +
    +
    +
    +
    +
    +
    +
    +
    -λ> "cat" < "dog" -True -``` +## QUIZ + +What does the expression `read "2"` evaluate to? +**(A)** Type error + +**(B)** `"2"` + +**(C)** `2` + +**(D)** `2.0` + +**(E)** Run-time error + +
    +
    +
    +


    -Note `Eq a =>` in the class definition! +Haskell is foxed! -A type `T` _is an instance of_ `Ord` if +- Doesn't know _what type_ to convert the string to! +- Doesn't know _which_ of the `read` functions to run! -1. `T` is *also* an instance of `Eq`, and -2. It defines functions for comparing values for inequality +Did we want an `Int` or a `Double` or maybe something else altogether? + +
    +
    + +Thus, here an **explicit type annotation** is needed to tell Haskell +what to convert the string to: + +```haskell +λ> (read "2") :: Int +2 + +λ> (read "2") :: Float +2.0 - +λ> (read "2") :: String +??? +``` + +Note the different results due to the different types.

    @@ -528,6 +608,8 @@ A type `T` _is an instance of_ `Ord` if

    + + ## Standard Typeclass Hierarchy Haskell comes equipped with a rich set of built-in classes. @@ -553,7 +635,7 @@ because for something to be an `Ord` it must also be an `Eq`. 1. Why type classes? [done] 2. Standard type classes [done] 3. **Creating new instances** -4. Using type classes +4. Typeclasses and Polymorphism 5. Creating new type classes
    @@ -859,7 +941,7 @@ True 1. Why type classes? [done] 2. Standard type classes [done] 3. Creating new instances [done] -4. **Using type classes** +4. **Typeclasses and Polymorphism** 5. Creating new type classes
    @@ -987,91 +1069,7 @@ Write an optimized version of _(How) do you need to change the types of `get` and `add`?_ -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -## Explicit Type Annotations - -Consider the standard typeclass `Read`: - -```haskell --- Not the actual definition, but almost: -class Read a where - read :: String -> a -``` - -`Read` is the _opposite_ of `Show` - - - It requires that every instance `T` can parse a string and turn it into `T` - - - Just like with `Show`, most standard type are instances of `Read`: - - - `Int`, `Integer`, `Double`, `Char`, `Bool`, etc -
    -
    -
    -
    -
    -
    -
    -
    -
    - -## QUIZ - -What does the expression `read "2"` evaluate to? - -**(A)** Type error - -**(B)** `"2"` - -**(C)** `2` - -**(D)** `2.0` - -**(E)** Run-time error - -
    -
    -
    -
    -
    -
    - -Haskell is foxed! - -- Doesn't know _what type_ to convert the string to! -- Doesn't know _which_ of the `read` functions to run! - -Did we want an `Int` or a `Double` or maybe something else altogether? - -
    -
    - -Thus, here an **explicit type annotation** is needed to tell Haskell -what to convert the string to: - -```haskell -λ> (read "2") :: Int -2 - -λ> (read "2") :: Float -2.0 - -λ> (read "2") :: String -??? -``` - -Note the different results due to the different types.

    @@ -1089,7 +1087,7 @@ Note the different results due to the different types. 1. Why type classes? [done] 2. Standard type classes [done] 3. Creating new instances [done] -4. Using type classes [done] +4. Typeclasses and Polymorphism [done] 5. **Creating new type classes**