Data Types

CS119 – Module 8: Data Types

Purpose

  • The purpose of this module is to introduce the concept of defining custom data types in Haskell, allowing users to create tailored data structures to meet specific needs.

Knowledge Objectives

This module will help you become familiar with the following content knowledge:

  • Defining data types: Understanding how to create and use new data types.

  • Writing functions to manipulate data types: Learning to write functions that operate on these custom types.

Activities

  • Group work: Perform the following tasks and answer the questions within 30 minutes. Then report your findings back to the class.

Task 1: Creating Custom Data Types
  • Definition: We can create our own data types by simply listing the possible values that the type may have.

  • Example: Consider the following declaration:

  data Thing = Shoe | Ship | SealingWax | Cabbage | King deriving Show
  • This declares a new type called Thing with five possible values: Shoe, Ship, SealingWax, Cabbage, and King. These values are the only values of type Thing.

  • The phrase deriving Show instructs Haskell to automatically generate the default code for printing values of type Thing.

Task 2: Pattern Matching on Custom Types
  • Function Definition: We can write functions that operate on the type Thing using pattern matching.

  isSmall :: Thing -> Bool
  isSmall Shoe = True
  isSmall Ship = False
  isSmall SealingWax = True
  isSmall Cabbage = True
  isSmall King = False
  • Task: Predict the result of the expression:

  > isSmall Cabbage
Task 3: Using Default Patterns in Functions
  • Shortened Function Definition: In a function, cases are evaluated from top to bottom. The definition of isSmall can be made shorter using a default pattern, represented by _ which matches anything else.

  isSmall2 :: Thing -> Bool
  isSmall2 Ship = False
  isSmall2 King = False
  isSmall2 _ = True
  • Task: Verify the result of:

  > isSmall2 Cabbage
Task 4: Combining Data Types with Tuples
  • Combining Types: We can combine previously defined data types into a new type using tuples.

  • Example Declaration:

  type Quantity = (Int, Thing)
  • Function Definition: To determine if we have enough of our Thing, we use:

  haveEnough :: Quantity -> Bool
  haveEnough (n, King) = True
  haveEnough (n, _) = n >= 42
  • Task: Verify the following results:

  > haveEnough (0, King) 
  > haveEnough (3, Shoe)  
  > haveEnough (42, Shoe)
  • Modification Task: Modify this function such that we only have enough shoes if we have an even number of them.

Task 5: Data Types with Arguments
  • Complex Types: Data type values need not be simple lists; they can also include arguments.

  • Example Declaration:

  data FailableDouble = Failure | OK Double deriving Show
  • This indicates that FailableDouble may be either Failure or OK which takes an argument of type Double.

  • Example of using FailableDouble: OK 3.4 is a value of type FailableDouble.

    • Function Definition: Here's one way to utilize the new FailableDouble type:

  safeDiv :: Double -> Double -> FailableDouble
  safeDiv _ 0 = Failure
  safeDiv x y = OK (x / y)
  • Task: Try the following expressions and analyze the results:

  > safeDiv 2 0
  > safeDiv 3 4
  • Discussion: What happened and why?

Task 6: Converting FailableDouble to Regular Double
  • Function Completion: Convert a FailableDouble to a regular double by transforming Failure values to zero, while keeping OK values as is.

  failureToZero :: FailableDouble -> Double
  failureToZero \_\_\_\_\_\_\_\_\_\_ = 0
  failureToZero (OK d) = \_\_\_\_\_\_\_\_\_\_
  • Testing: You can test your function with:

  > failureToZero (safeDiv 2 0)
  > failureToZero (safeDiv 3 4)
Assignments for Grading
  • Complete the following assignments individually, although discussing strategies with classmates is allowed. Implement all functions in the file Shape.hs within the lab8 directory. You should consider starting by creating shapes and calculating their areas.

Assignment 1: Right Triangle Area Calculation
  • Task: Add another case to the Shape data type to create a RightTriangle by providing the two sides that meet at the right angle. Modify the area function to compute the area of this new shape.

  • Criteria for Success: Calculate and verify the area of a couple of right triangles.

Assignment 2: Scaling Shapes
  • Task: Write a function:

  scale :: Float -> Shape -> Shape
  • Purpose: The expression scale factor s should return a new shape that is scaled by the given factor.

  • Criteria for Success: Successfully scale shapes of all three types and verify the results.

Assignment 3: Locatable Shape
  • Task: Define another data type LocatableShape that includes values for the x and y coordinates of the center of the shape, along with the shape itself, structured as a tuple with three components.

  • Function: Write a function:

  translate :: (Int, Int) -> LocatableShape -> LocatableShape
  • Purpose: This function should move the shape; for instance, passing in (10, 10) would imply increasing both x and y coordinates of the shape's center by 10.

  • Criteria for Success: Translate a LocatableShape value and verify that the location has changed.

  • Submission: Submit your Shape.hs file in Canvas for grading.