Saturday 30 April 2016

Haskell: Custom types


You can define custom types in Haskell using data, type, newtype declaration.

Declaration
Description
data
Define new data type
type
Give alternative names to existing types
newtype
Define new types equivalent to existing ones.

Syntax to define custom type
data type tv1 ... tvi = con1  c1t1 c1t2... c1tn |
                      ... | conm cmt1 ... cmtq
                    [deriving]

Define custom types using data
Suppose you want to declare an Employee type, which has properties like id, firstName, lastName, salary.

data Employee = Employee Int String String Double

Above statement defines a custom data type Employee. In Haskell, type names must start with a capital letter.
Type Constructor and value constructor (also called data constructor) can have different names. Type constructor is used in type declaration and type signatures, but value constructor is use in actual code.

let emp1 = Employee 1 "Hari Krishna" "Gurram" 12345.6

Above statement defines a variable emp1 with id 1, firstName "Hari Krishna", lastName "Gurram" and salary 12345.6.
Prelude> data Employee = Employee Int String String Double
Prelude> 
Prelude> :t Employee
Employee :: Int -> String -> String -> Double -> Employee
Prelude> 
Prelude> 
Prelude> let emp1 = Employee 1 "Hari Krishna" "Gurram" 12345.6


Algebraic Data type
An algebraic data type can have more than one value constructor associated with it. You can specify multiple constructors for a custom type using | operator.

data Employee = Engineer Int String String | Manager Int String String Double

Above statement declares new data type Employee, which can be either an Engineer or a Manager. Engineer, Manager are the data constructors for the type Employee. Where as Employee is called Type constructor. Engineer contains one integer and two strings and a Manager contains one integer, two strings and a double. The vertical bar separates the definitions of the two possibilities.

Syntax
data NewDataType = Constructor1 Type11 Type12 .... Type1N
                 | Constructor2 Type21 Type22 .... Type2N
                 | Constructor3 Type31 Type32 .... Type3N
                 | Constructor4 Type41 Type42 .... Type4N
                 ......
                 ......
                 | ConstructorM Typem1 Typem2 .... TypemN


Here types for the constructors are optional. Remember that types and constructor names must always start with capital letter, variables and function names must always start with lower case letter.
Prelude> data Employee = Engineer Int String String | Manager Int String String Double
Prelude> 
Prelude> let emp1 = Engineer 1 "PTR" "Nayan"
Prelude> let emp2 = Manager 1 "Sailaja" "Nayan" 9876543.12
Prelude> 
Prelude> :t emp1
emp1 :: Employee
Prelude> 
Prelude> :t emp2
emp2 :: Employee
Prelude>
Prelude> :t Engineer
Engineer :: Int -> String -> String -> Employee
Prelude> 
Prelude> :t Manager
Manager :: Int -> String -> String -> Double -> Employee


Extract contents of custom type
customType.hs
{-Define custom type-}
data Employee = Engineer Int String String 
                | Manager Int String String Double

showBasicInfo id firstName lastName = "id = " ++ (show id) ++ " firstName = " ++ firstName ++ " lastName = " ++ lastName

getEngineer (Engineer id firstName lastName) = showBasicInfo id firstName lastName

getManager (Manager id firstName lastName salary) = showBasicInfo id firstName lastName ++ " salary = " ++ (show salary)

*Main> let engineer1 = Engineer 1 "Hari Krishna" "Gurram"
*Main> 
*Main> let manager1 = Manager 2 "PTR" "Nayan" 12345678.90
*Main> 
*Main> getEngineer engineer1
"id = 1 firstName = Hari Krishna lastName = Gurram"
*Main> 
*Main> getManager manager1
"id = 2 firstName = PTR lastName = Nayan salary = 1.23456789e7"


Above example shows how to extract contents of custom type. I define two functions getEngineer, getManager. getEngineer takes an Engineer type as an argument and return the Engineer details. getManager function takes Manager type as an argument and return the Manager details.

Function Overloading
Function overloading is a feature, where you can define a multiple functions with same name and different arguments. For example, customType.hs is rewritten like below using function overloading.

customType.hs
{-Define custom type-}
data Employee = Engineer Int String String 
                | Manager Int String String Double

showBasicInfo id firstName lastName = "id = " ++ (show id) ++ " firstName = " ++ firstName ++ " lastName = " ++ lastName

getEmployee (Engineer id firstName lastName) = showBasicInfo id firstName lastName

getEmployee (Manager id firstName lastName salary) = showBasicInfo id firstName lastName ++ " salary = " ++ (show salary)

*Main> let engineer1 = Engineer 1 "Hari Krishna" "Gurram"
*Main> 
*Main> let manager1 = Manager 2 "PTR" "Nayan" 12345678.90
*Main> 
*Main> getEmployee engineer1
"id = 1 firstName = Hari Krishna lastName = Gurram"
*Main> 
*Main> getEmployee manager1
"id = 2 firstName = PTR lastName = Nayan salary = 1.23456789e7"


Note
a.   Types defined by data declarations are often referred to as algebraic data types.
b.   Types, constructors, type classes must start with a capital letter.




Previous                                                 Next                                                 Home

No comments:

Post a Comment