Records and Type Classes

Slides:



Advertisements
Similar presentations
Functional Programming Lecture 10 - type checking.
Advertisements

Types in Ruby and other languages….  Classes and objects (vs prototypes)  Instance variables/encapsulation  Object creation  Object equality/comparison.
Haskell Chapter 7. Topics  Defining data types  Exporting types  Type parameters  Derived instances  Type synonyms  Either  Type classes  Not.
Computer Science 209 Software Development Equality and Comparisons.
Haskell Chapter 5, Part I. Topics  Higher Order Functions  map, filter  Infinite lists Get out a piece of paper… we’ll be doing lots of tracing.
ML: a quasi-functional language with strong typing Conventional syntax: - val x = 5; (*user input *) val x = 5: int (*system response*) - fun len lis =
C#: Data Types Based on slides by Joe Hummel. 2 UCN Technology: Computer Science Content: “.NET is designed around the CTS, or Common Type System.
Using Types Slides thanks to Mark Jones. 2 Expressions Have Types: The type of an expression tells you what kind of value you might expect to see if you.
A Lightning Tour of Haskell Lecture 1, Designing and Using Combinators John Hughes.
ML: a quasi-functional language with strong typing Conventional syntax: - val x = 5; (*user input *) val x = 5: int (*system response*) - fun len lis =
Advanced Programming Handout 9 Qualified Types (SOE Chapter 12)
0 PROGRAMMING IN HASKELL Chapter 3 - Types and Classes.
Type Inference: CIS Seminar, 11/3/2009 Type inference: Inside the Type Checker. A presentation by: Daniel Tuck.
Chapter 12 Qualified Types. Motivation  What should the principal type of (+) be? Int -> Int -> Int-- too specific a -> a -> a-- too general  It seems.
Using Types Slides thanks to Mark Jones. 2 Expressions Have Types: The type of an expression tells you what kind of value you might expect to see if you.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
PrasadCS7761 Haskell Data Types/ADT/Modules Type/Class Hierarchy Lazy Functional Language.
Operators, Functions and Modules1 Pattern Matching & Recursion.
Haskell. 2 GHC and HUGS Haskell 98 is the current version of Haskell GHC (Glasgow Haskell Compiler, version 7.4.1) is the version of Haskell I am using.
1 COSC3557: Object-Oriented Programming Haibin Zhu, Ph. D. Associate Professor of CS, Nipissing University.
1 Functional Programming Lecture 6 - Algebraic Data Types.
Object-Oriented Program Development Using Java: A Class-Centered Approach, Enhanced Edition.
Overview of the Haskell 98 Programming Language
What is a Type? A type is a name for a collection of related values. For example, in Haskell the basic type Bool contains the two logical values: True.
© M. Winter COSC 4P41 – Functional Programming Modules in Haskell Using modules to structure a large program has a number of advantages: Parts of.
Classes. Student class We are tasked with creating a class for objects that store data about students. We first want to consider what is needed for the.
Object Oriented Programming
Defining Classes Modules and ADTs CSCE 314 Spring 2016.
1 Objective Caml (Ocaml) Aaron Bloomfield CS 415 Fall 2005.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
6-Jul-16 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
Object Oriented Programming Some Interesting Genes.
Set Comprehensions In mathematics, the comprehension notation can be used to construct new sets from old sets. {x2 | x  {1...5}} The set {1,4,9,16,25}
Set Comprehensions In mathematics, the comprehension notation can be used to construct new sets from old sets. {x2 | x  {1...5}} The set {1,4,9,16,25}
Polymorphic Functions
Functional Programming
Haskell Chapter 7.
Conditional Expressions
PROGRAMMING IN HASKELL
Types CSCE 314 Spring 2016.
ML: a quasi-functional language with strong typing
Haskell Chapter 2.
A lightening tour in 45 minutes
Haskell.
CSE 3302 Programming Languages
Haskell Strings and Tuples
Computer Science 312 Haskell Lists 1.
PROGRAMMING IN HASKELL
Extending Classes.
PROGRAMMING IN HASKELL
CSE 341 Section 2 Winter 2018 Adapted from slides by Nick Mooney, Nicholas Shahan, Patrick Larson, and Dan Grossman.
CSE 341 Section 5 Winter 2018.
PROGRAMMING IN HASKELL
Type & Typeclass Syntax in function
Types and Classes in Haskell
CSCE 314: Programming Languages Dr. Dylan Shell
CSE 341 Section 2 Nick Mooney Spring 2017
Haskell Types, Classes, and Functions, Currying, and Polymorphism
PROGRAMMING IN HASKELL
CSE-321 Programming Languages Introduction to Functional Programming
Records and Type Classes
CIS 199 Final Review.
Defining New Data Types
PROGRAMMING IN HASKELL
Functions and patterns
Type Systems Terms to learn about types: Related concepts: Type
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Presentation transcript:

Records and Type Classes Computer Science 312 Records and Type Classes 1

Defining Structured Types In C: struct Student { char* name; int scores[10]; } In Java: class Student { private String name; private int [] scores; }

Defining Structured Types In C: struct Student { char* name; int scores[10]; } In Java: class Student { private String name; private int [] scores; } In Haskell: data Student = Student String [Int]

What Is Missing In most languages, structured types include the names of the components (fields) as well as their types Some languages also automatically generate accessors for the components It would be nice to selectively transform one or more of the components while automatically retaining the values of the rest of the components

The Solution: Record Types In Java: class Student { private String name; private int [] scores; } In Haskell (algebraic type): data Student = Student String [Int] In Haskell (record type): data Student = Student { studentName :: String studentScores :: [Int] }

Using Record Types: Initialization Algebraic type: data Student = Student String [Int] newStudent :: String -> Int -> Student newStudent name numberOfScores = Student name map (\x -> 0) [1..numberOfScores] Record type: data Student = Student { studentName :: String studentScores :: [Int] } newStudent :: String -> Int -> Student newStudent name numberOfScores = Student { studentName = name studentScores = map (\x -> 0) [1..numberOfScores] }

Using Record Types: Accessors Algebraic type: data Student = Student String [Int] getName :: Student -> String getName (Student name _) = name Record type: data Student = Student { studentName :: String studentScores :: [Int] } getName :: Student -> String getName student = studentName student You really don’t need to define your own accessors

Using Record Types: “Mutators” Algebraic type: data Student = Student String [Int] setName :: String -> Student -> String setName newName (Student _ scores) = Student newName scores Record type: data Student = Student { studentName :: String studentScores :: [Int] } setName :: String -> Student -> Student setName newName student = student {studentName = newName} Reuses structure for simplicity and efficiency!

Records vs Algebraic Product Types Records are closer to conventional notation Records give you named accessors Records make initializers and transformations easier Can still use pattern matching with records if desired, because they are semantically equivalent to product types

What’s in a Type? For generic (polymorphic) types, such as lists and tuples, the type of the structure is independent of its item types For quite specific types, like strings, the item type is essential to the type of the structure Is there a way of defining a set of types that aren’t totally specific or totally general, but might belong together by family resemblance?

Examples: Sorting To guarantee that a list can be sorted, its items must recognize the comparison operators <, >, <=, and >= To guarantee this, they must belong to the Ord type class This type class is like the Comparable interface in Java, which requires that implementing classes include the compareTo method, so that methods like Collections.sort can do their work correctly Many data types are already instances of one or more type classes

Type Classes and Their Instances

3 Ways to Bring Type Classes to Bear Derive them in algebraic data type definitions Include them in type signatures of functions Create new type instances to override the default behavior of functions in the type class

Type Class Derivation module BST where data BST k v = EmptyNode | InteriorNode k v (BST k v) (BST k v) deriving (Eq, Show) We derive Eq for equality tests and Show for printing in the GHCI

Include in Function Signatures module BST where data BST k v = EmptyNode | InteriorNode k v (BST k v) (BST k v) deriving (Eq, Show) bstLookup :: Ord k => k -> (BST k v) -> v bstLookup key EmptyNode = error "Key not found" bstLookup key (InteriorNode k v left right) | key < k = bstLookup key left | key > k = bstLookup key right | key == k = v We add Ord for comparisons specifically of the keys in functions for searching, insertions, etc.

To Derive or Not to Derive module Student where data Student = Student String [Int] deriving (Show) newStudent :: String -> Int -> Student newStudent name numberOfScores = let scores = map (\x -> 0) [1..numberOfScores] in Student name scores *Student> newStudent "Ken" 5 Student "Ken" [0,0,0,0,0] deriving uses the “shows” of the nested components But we might like a string that’s better formatted

Create a Type Instance of Show module Student where import Data.String (unwords) data Student = Student String [Int] instance Show Student where show (Student name scores) = "Name: " ++ name ++ "\n" ++ "Scores: " ++ unwords (map (\score -> show score) scores) *Student> newStudent "Ken" 5 Name: Ken Scores: 0 0 0 0 0 Just like implementing a Java interface, except that you need to define only the operations that your app needs

Add Instances of Eq and Ord module Student where data Student = Student String [Int] instance Eq Student where (==) (Student name1 _) (Student name2 _) = name1 == name2 instance Ord Student where (<=) (Student name1 _) (Student name2 _) = name1 <= name2 *Student> s1 = newStudent "Ken" 5 *Student> s2 = newStudent "Martin" 5 *Student> s1 == s2 False *Student> s1 < s2 True

Getting Code for Free class Eq a where (==), (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y) If you include a definition of == in your type instance, then you automatically get a definition of /=, or conversely module Student where data Student = Student String [Int] instance Eq Student where (==) (Student name1 _) (Student name2 _) = name1 == name2

Getting Code for Free class Eq a => Ord where blah, blah, blah If you include a definition of <= in your type instance, then you automatically get definitions of all of the other Ord operations (<, >, >=, max, and min) Note that any Ord type must also be an Eq type module Student where data Student = Student String [Int] instance Ord Student where (<=) (Student name1 _) (Student name2 _) = name1 <= name2

Overloading vs Polymorphism Functions in type classes are overloaded, which means that they can be implemented by different algorithms if different type instance (integer addition is different from floating-point addition, but they both use + to add their operands) Functions on generic types, like lists, are polymorphic, which means that they use the same algorithm on different types of data (the length, head, and tail functions use the same implementations for lists of whatever item types)

Some Annoyances Shouldn’t (/) take two Nums and return a Float? Prelude> let scores = [100, 88, 77] Prelude> sum scores / length scores <interactive>:3:12: No instance for (Fractional Int) arising from a use of ‘/’ In the expression: sum scores / length scores In an equation for ‘it’: it = sum scores / length scores Shouldn’t (/) take two Nums and return a Float?

Some Annoyances Shouldn’t (/) take two Nums and return a Float? Prelude> let scores = [100, 88, 77] Prelude> sum scores / length scores <interactive>:3:12: No instance for (Fractional Int) arising from a use of ‘/’ In the expression: sum scores / length scores In an equation for ‘it’: it = sum scores / length scores Prelude> :type sum :: (Num a, Foldable t) => t a -> a Prelude> :type length :: Foldable t => t a -> Int Shouldn’t (/) take two Nums and return a Float?

Some Annoyances Shouldn’t (/) take two Nums and return a Float? Prelude> let scores = [100, 88, 77] Prelude> sum scores / length scores <interactive>:3:12: No instance for (Fractional Int) arising from a use of ‘/’ In the expression: sum scores / length scores In an equation for ‘it’: it = sum scores / length scores Prelude> :type sum :: (Num a, Foldable t) => t a -> a Prelude> :type length :: Foldable t => t a -> Int Prelude> :type (/) :: Fractional a => a -> a -> a Shouldn’t (/) take two Nums and return a Float?

Some Annoyances Prelude> 3 / 2 1.5 Prelude> :type 2 2 :: Num a => a Prelude> let x = 2 :: Int Prelude> :type x x :: Int Prelude> 3 / x <interactive>:14:3: No instance for (Fractional Int) arising from a use of ‘/’ In the expression: 3 / x In an equation for ‘it’: it = 3 / x If x is explicitly an Int, its type is not an instance of Fractional

The Numeric Type Class Hierarchy Fractional is not connected to Integral, but it is connected to Num So, if one can convert an Integral to a Num, one can make the connection to Fractional

Some Annoyances Prelude> 3 / 2 1.5 Prelude> :type 2 2 :: Num a => a Prelude> let x = 2 :: Int Prelude> :type x x :: Int Prelude> :type fromIntegral fromIntegral :: (Integral a, Num b) => a -> b Prelude> 3 / fromIntegral x We must coerce an explicit Int into a Num, with fromIntegral

Whew, success! Prelude> :type sum :: (Num a, Foldable t) => t a -> a Prelude> :type length :: Foldable t => t a -> Int Prelude> :type (/) :: Fractional a => a -> a -> a Prelude> :type fromIntegral fromIntegral :: (Integral a, Num b) => a -> b Prelude> let scores = [100, 88, 77] Prelude> sum scores / length (fromIntegral scores) 88.33333333333333 sum already yields a Num, and we raise the type of length to a Num with fromIntegral

Introducing code with side effects: monads For next time Introducing code with side effects: monads