Functional Programming Types and Pattern Matching - PDF
Document Details
Uploaded by ThankfulViolet9030
University of Surrey
2024
Santanu Dash
Tags
Summary
This document is a presentation on Functional Programming in Haskell, focusing on types and pattern matching. It includes details about tuples, algebraic types, and the prelude library. Specific examples are included, such as defining a type for shop items and creating a basket with ShopItem values.
Full Transcript
Introduction Tuples Algebraic Types Prelude An Example Conclusion Functional Programming Types and Pattern Matching Santanu Dash University of Surrey...
Introduction Tuples Algebraic Types Prelude An Example Conclusion Functional Programming Types and Pattern Matching Santanu Dash University of Surrey 30th October 2024 Introduction Tuples Algebraic Types Prelude An Example Conclusion Table of Contents Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction Tuples Algebraic Types Prelude An Example Conclusion Learning Objectives Learn about tuples and pattern matching on tuples. Understand the concept of Algebraic Types (ATs) in Haskell. Get a first look at the Prelude library in Haskell which contains several useful types and methods. Discuss an example which a list of lists to modify and display images. Introduction Tuples Algebraic Types Prelude An Example Conclusion Table of Contents Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction Tuples Algebraic Types Prelude An Example Conclusion Defining a Type for Shop Items We can create a custom type alias for items in a shop: 1 type ShopItem = (String, Int) Here, ShopItem is a tuple containing: A String representing the name of the item. An Int representing the price in cents. Using ShopItem improves code readability by describing the tuple’s purpose. Introduction Tuples Algebraic Types Prelude An Example Conclusion Using ShopItem Type Now we can define items like salt and crisps as ShopItem values: 1 ("Salt: 1kg", 139) :: ShopItem 2 ("Plain crisps", 25) :: ShopItem This allows us to easily declare that ("Salt: 1kg", 139) is of type ShopItem. Type annotations like :: ShopItem clarify data types for both the compiler and the reader. Introduction Tuples Algebraic Types Prelude An Example Conclusion Creating a Basket with ShopItem We can create a list of items to represent a shopping basket: [("Salt: 1kg",139), ("Plain crisps",25), ("Gin: 1lt",1099)] This list is of type [(String, Int)] or simply [ShopItem]. Using a type alias, we can define a shopping basket as: type Basket = [ShopItem] Now, Basket represents a collection of items with prices, improving code clarity. Introduction Tuples Algebraic Types Prelude An Example Conclusion Component Types Each ShopItem has two components: A String for the item name An Int for the item price Knowing ShopItem :: (String, Int) allows us to predict component types. This enables type-checking to ensure each component is used correctly. For example, we can ensure the second component is treated as an Int, not a Bool. Haskell’s strong typing prevents type mismatches before runtime. Introduction Tuples Algebraic Types Prelude An Example Conclusion Type Consistency in Lists A Basket is a list of ShopItems: 1 type Basket = [ShopItem] All elements in a Basket are of the same type, ShopItem. This allows type-checking to verify the type of each element chosen from the list. If Haskell allowed lists with mixed types, we could not predict types at each position. Enforcing consistent types in lists preserves Haskell’s ability to type-check code before runtime. Introduction Tuples Algebraic Types Prelude An Example Conclusion Pattern Matching: countItems Function Function: countItems - Counts the number of items in a Basket. 1 type ShopItem = (String, Int) 2 type Basket = [ShopItem] 3 4 countItems :: Basket -> Int 5 countItems [] = 0 6 countItems (_:xs) = 1 + countItems xs countItems [] = 0: Returns 0 if the basket is empty. countItems (_:xs)= 1 + countItems xs: Matches and counts each item in the basket. Recursively processes the list, summing items as it moves through. Introduction Tuples Algebraic Types Prelude An Example Conclusion Pattern Matching: totalPrice Function Function: totalPrice - Calculates the total price of items in a Basket. 1 totalPrice :: Basket -> Int 2 totalPrice [] = 0 3 totalPrice ((_, price):xs) = price + totalPrice xs totalPrice [] = 0: Returns 0 for an empty basket. totalPrice ((_, price):xs)= price + totalPrice xs: Adds the price of each item. Recursively traverses the basket, summing all prices. Introduction Tuples Algebraic Types Prelude An Example Conclusion Table of Contents Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction Tuples Algebraic Types Prelude An Example Conclusion Algebraic Types (ATs) What are ATs? ATs allow us to define custom types with named constructors. They model data more meaningfully than primitive types. How are ATs defined? Defined using the data keyword. Example: data Person = Person { name :: String, age :: Int } Introduction Tuples Algebraic Types Prelude An Example Conclusion ATs are better than Tuples Clear Labeling: Each object of the algebraic type has an explicit label, such as Person, indicating its purpose. Controlled Construction: An element of the type, like a Person, must be created using the designated constructor, preventing accidental misuse of arbitrary pairs. Since type synonyms only serve as shorthand, they cannot be recursive, whereas data definitions can be recursive. Improved Error Messages: The type name appears in error messages, making debugging easier, as opposed to type synonyms which may be expanded out and disappear in type errors. Introduction Tuples Algebraic Types Prelude An Example Conclusion Enum and Product Types Enum Types: Enumerated (enum) types represent a finite set of values. Example: data Bool = True|False defines two possible values. Product Types: Product types combine multiple values into a single type. Example: data Person = Person { name :: String, age :: Int } represents a name and an age. Enum types are often used with pattern matching, allowing concise control flow. Product types help model data with more than one attribute, like a person’s name and age. Introduction Tuples Algebraic Types Prelude An Example Conclusion Enumerated Types Example: Rock-Paper-Scissors Move is an enumerated type representing three possible values. 1 data Move = Rock | Paper | Scissors Each value (Rock, Paper, Scissors) is a constructor of Move. Enumerated types are useful for representing fixed sets of values. Move can be used to represent choices in a game of rock-paper-scissors. Simplifies pattern matching in functions by handling all possible moves. Introduction Tuples Algebraic Types Prelude An Example Conclusion Pattern Matching Function: score - Determines the result of two moves. 1 score :: Move -> Move -> String 2 score Rock Scissors = "Rock wins!" 3 score Scissors Paper = "Scissors win!" 4 score Paper Rock = "Paper wins!" 5 score _ _ = "It’s a tie!" score uses pattern matching to evaluate outcomes based on two moves. Each pattern combination (e.g., Rock Scissors) specifies a unique result. The final pattern, _ _, is a fallback for all remaining cases. Ensures all combinations of Move are handled, maintaining safety and clarity. Introduction Tuples Algebraic Types Prelude An Example Conclusion Product Types 1 -- Sample usage 2 main : : IO ( ) 3 main = do 1 -- Define the Person data type 4 let p e r s o n 1 = P e r s o n { name = " 2 data P e r s o n = P e r s o n { name : : String Alice " , a g e = 25 } , a g e : : Int } 5 let p e r s o n 2 = P e r s o n { name = " 3 Bob " , a g e = 15 } 4 -- 1. Greeting method 6 5 g r e e t P e r s o n : : P e r s o n −> String 7 putStrLn $ greetPerson person1 6 g r e e t P e r s o n ( P e r s o n name _) = " Hello , 8 -- Output : " Hello , Alice !" " ++ name ++ " ! " 9 putStrLn $ greetPerson person2 7 10 -- Output : " Hello , Bob !" 8 -- 2. Check if a person is an adult 11 9 i s A d u l t : : P e r s o n −> Bool 12 print $ i s A d u l t person1 10 i s A d u l t ( P e r s o n _ a g e ) = a g e >= 18 13 -- Output : True 14 print $ i s A d u l t person2 15 -- Output : False Introduction Tuples Algebraic Types Prelude An Example Conclusion Type and Constructor Name In Haskell, it’s possible to use the same name for both a type and its constructor. Example: 1 data Person = Person Name Age Some Haskell libraries use this idiom, but it can lead to confusion. Using distinct names for related but different concepts can enhance readability. Example without naming overlap: 1 data Individual = Person Name Age Introduction Tuples Algebraic Types Prelude An Example Conclusion Shape Data Type: Enum and Product Custom type to represent shapes: 1 data Shape = Circle Float 2 | Rectangle Float Float Represents shapes using either: A Circle with radius. A Rectangle with height and width. Example instances: 1 Circle 3.0 2 Rectangle 45.9 87.6 Introduction Tuples Algebraic Types Prelude An Example Conclusion Pattern Matching Pattern matching allows defining functions by cases: 1 isRound :: Shape -> Bool 2 isRound (Circle _) = True 3 isRound (Rectangle _ _) = False Accessing components of Shape elements: 1 area :: Shape -> Float 2 area (Circle r) = pi * r * r 3 area (Rectangle h w) = h * w Introduction Tuples Algebraic Types Prelude An Example Conclusion General form of Data Definitions General Form: data Typename = Con1 t11... t1k1 | Con2 t21... t2k2 |... | ConN tn1... tnkn Each Con is a constructor with ki arguments. We build elements by applying constructors to arguments of types given in the definition. Example: Coni vi1... viki will be of type Typename if each vij is of type tij. Introduction Tuples Algebraic Types Prelude An Example Conclusion Constructors as Functions Constructors are functions with the following types: Coni :: ti1 →... → tiki → Typename Recursive Types: Typename can be used as a part of any tij , supporting complex structures like lists or trees. Polymorphic Types: Type variables can be used to make definitions reusable across types. Combining recursive and polymorphic types gives versatile structures like lists. Introduction Tuples Algebraic Types Prelude An Example Conclusion Error Handling with Maybe The Maybe type represents computations that might fail. Type signature: Maybe a = Nothing | Just a Introduction Tuples Algebraic Types Prelude An Example Conclusion The Maybe Type Definition: Maybe a is a type that represents an optional value of type a. It can either be: Nothing – representing the absence of a value. Just a – representing the presence of a value a. Syntax: 1 data Maybe a = Nothing | Just a Purpose: Avoids errors from null or nil values found in other languages. Encodes absence of values explicitly, improving code safety and readability. Introduction Tuples Algebraic Types Prelude An Example Conclusion Examples of Using Maybe Example 1: Safe Division 1 safeDivide :: Int -> Int -> Maybe Int 2 safeDivide _ 0 = Nothing 3 safeDivide x y = Just (x ‘div‘ y) Explanation: safeDivide 10 2 returns Just 5. safeDivide 10 0 returns Nothing to indicate a failed division. Example 2: Extracting Values with Pattern Matching 1 case safeDivide 10 2 of 2 Nothing -> "No result" 3 Just result -> "Result is " ++ show result Introduction Tuples Algebraic Types Prelude An Example Conclusion Table of Contents Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction The Haskell Prelude is a foundational library providing essential functions and types. It includes modules with functions for data manipulation, control structures, list operations, and more. Prelude functions allow concise, expressive code. This presentation covers core modules and functions, type signatures, and usage examples. Introduction Tuples Algebraic Types Prelude An Example Conclusion Core Modules in Prelude Basic types and functions for arithmetic and logic. List and character manipulation functions. Functions for higher-order programming (e.g., map, fold). I/O operations and monadic functions. Introduction Tuples Algebraic Types Prelude An Example Conclusion Basic Operations Arithmetic operators: +, -, *, / Logical operators: &&, ||, not Comparison operators: ==, b)-> [a] -> [b] filter :: (a -> Bool)-> [a] -> [a] Example map (+1)[1, 2, 3] --Result: [2, 3, 4] filter even [1, 2, 3, 4] --Result: [2, 4] Introduction Tuples Algebraic Types Prelude An Example Conclusion Folding Lists Folding reduces a list to a single value. foldr: Reduces from the right. foldl: Reduces from the left. Type signature: foldr :: (a -> b -> b)-> b -> [a] -> b Example foldr (+)0 [1, 2, 3] --Result: 6 Introduction Tuples Algebraic Types Prelude An Example Conclusion Higher-Order Functions Functions that take functions as arguments or return functions. Prelude includes several: map, filter, foldr, etc. Type signature examples: map :: (a -> b)-> [a] -> [b] Introduction Tuples Algebraic Types Prelude An Example Conclusion I/O Functions and Monads The Prelude includes I/O functions that utilise monads for sequencing actions. Type signatures: putStrLn :: String -> IO () Example putStrLn "Hello, Haskell" Introduction Tuples Algebraic Types Prelude An Example Conclusion Function Composition and Application. operator: Compose functions. $ operator: Apply functions without parentheses. Example (map (+1). filter even)[1, 2, 3, 4] --Result: [3, 5] Introduction Tuples Algebraic Types Prelude An Example Conclusion Table of Contents Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction Tuples Algebraic Types Prelude An Example Conclusion Picture Representation In Haskell, we can represent a picture as a 2D grid of characters. Define a picture as a list of strings: type Picture = [[Char]] Each [Char] represents a row of characters in the picture. Introduction Tuples Algebraic Types Prelude An Example Conclusion printPicture Function The printPicture function displays a picture. 1 printPicture :: Picture -> IO () 2 printPicture = mapM_ putStrLn Introduction Tuples Algebraic Types Prelude An Example Conclusion flipH Function The flipV function flips in a horizontal mirror. 1 flipH :: Picture -> Picture 2 flipH = reverse Introduction Tuples Algebraic Types Prelude An Example Conclusion flipV Function The flipV function flips in a vertical mirror. 1 flipV :: Picture -> Picture 2 flipV pic 3 = [ reverse line | line Picture -> Picture 2 above = (++) Introduction Tuples Algebraic Types Prelude An Example Conclusion beside Function The beside function places two pictures side-by-side. 1 beside :: Picture -> Picture -> Picture 2 beside = zipWith (++) Introduction Tuples Algebraic Types Prelude An Example Conclusion Inverting Colours 1 type P i c t u r e = [ [ Char ] ] 2 # represents a black pixel; space ( ) 3 -- Function to invert colors in a Picture represents a white pixel. 4 i n v e r t C o l o u r : : P i c t u r e −> P i c t u r e 5 i n v e r t C o l o u r = map i n v e r t L i n e invertColour uses map invertLine to 6 invert each row (line) of the picture. 7 -- Inverts colors in a single line 8 i n v e r t L i n e : : [ Char ] −> [ Char ] invertLine applies invertChar to each 9 i n v e r t L i n e = map i n v e r t C h a r character in the line: 10 where invertChar ’#’ changes black 11 i n v e r t C h a r ’# ’ = ’ ’ 12 -- Black to white pixels (#) to white ( ). 13 i n v e r t C h a r ’ ’ = ’# ’ invertChar ’ ’ changes white 14 -- White to black pixels ( ) to black (#). 15 invertChar c = c Other characters remain unchanged. 16 -- Other chars unchanged Introduction Tuples Algebraic Types Prelude An Example Conclusion Function Composition In Haskell, function composition allows combining functions by chaining them together with the composition operator ($). The expression f $ g $ h x applies h to x first, then g to the result, and finally f to the output. Example: 1 main = printPicture $ invertColour $ flipV myPicture This code performs three operations in sequence: flipV vertically flips the picture. invertColour inverts the colours of the flipped picture. printPicture displays the modified picture. Output: The picture is first flipped, then its colours are inverted, resulting in a transformed display. Introduction Tuples Algebraic Types Prelude An Example Conclusion Table of Contents Introduction Tuples Algebraic Types Prelude An Example Conclusion Introduction Tuples Algebraic Types Prelude An Example Conclusion Summary Tuples and Pattern Matching: Learnt how to use tuples for grouping values and applied pattern matching to decompose and work with tuple structures effectively. Algebraic Types (ATs): Gained an understanding of Algebraic Types, allowing us to define custom data structures and represent complex data models. Prelude Library: Looked at Haskell’s Prelude library, exploring essential types and functions. Image Modification Example: Covered an example involving a list of lists to show how Haskell could represent and manipulate structured data, such as images, through nested lists.