Sunday, October 19, 2014

Haskell - Expressions, Basic Types, Composite Data Types

Every expression and function in Haskell has a type.
Types in Haskell are:
  1. Strong
  2. Static
  3. Can be automatically inferred.
  • True has the type Bool
  • 'foo' is of type String
  • 1 has type Num
Type are important for abstraction. To add meaning to some bytes. The meaning cannot change after the type has been defined. 
The benefit is that you can ignore or forget about the low level details.

Type systems are not all equal. Haskell's type system allows us to think at a very abstract level.

  1. Strong Types - the type system guarantees that a program cannot contain certain kinds of errors - Trying to write expressions that don't make sense, such as using an integers as a function.
    1. an expression that obeys a languages type rules is well typed
    2. an expression that disobeys the type rules is ill typed and will cause a type error
    3. It will not automatically coerce values (also known as casting or conversion)
  2. Static types - means that the compiler knows the type of every value and expression at compile time, before any code is executed
  3. Type inference - a Haskell compiler can automatically deduce the type of almost all expressions in program. This process is knows as type inference. Haskell allows us to explicitly declare the type of any value, but the presence of type inference means that this is almost always optional.
I. Basic Types
  • Char value represent a Unicode character
  • Bool value represents a value in Boolean Logic. The possible values of type Bool are True and False
  • The Int type is used for signed, fixed-width integer values. (32 bit or 64 bit wide depending on architecture)
  • An Integer values is a signed integer of unbounded size.
  • Values of type Double are used for floating point numbers. 
Types in a nutshell

"Hello " ++ " World" is an expression
Its value is "Hello World" 
Its type is String 
Types are declared using the reserved operator :: (read as "has type")

xs = "Hello World" :: String Here xs is a variable.
  • Variables and types names are case sensitive. 
  • Variable names begin with a lowercase character and type names begin with an uppercase character.
  • Type declarations are optional. In their absence, Haskell will infer the types. If it can't, you'll be asked to provide them.
  • Type variables live in type signatures, and regular variables live in normal expressions.  
  • Common Haskell practice to keep the names of type variables very short
  • Type signatures are usually brief 
  • If a type contains type parameters, we say that it is a parameterised type, or a polymorphic type. If a function or value's type contains type parameters, we call it polymorphic
This type signature contains a type variable:

ghci> :type last
last :: [a] -> a
 'last' is a function, '[a] -> a' is the type of 'last', 'last :: [a] -> a' is the type declaration of last

Here, a is the type variable. We can read the signature as “takes a list, all of whose elements have some type a, and returns a value of the same type a

ghci> let xs = "Hello World" :: String
ghci> xs
"Hello World"
ghci> :t xs
xs :: String

II. Composite data types
  • Constructed from other types
  • Lists and tuples are most common examples.
- the head function returns the first element of a list
- the tail returns all but the head of a list

- we can apply head and tail to lists of different types. Applying head to a [Char] value returns a Char value, while applying it to a [Bool] value returns a Bool value. The head function doesn't care what type of list it deals with.
ghci> head [1,2,3,4]
ghci> head ['a','b','c']
Because the values in a list can have any type we call the list type polymorphic.
-- If we want to write a polymorphic type we use a type variable, which must begin with a lowercase letter. 
-- A type variable is a placeholder, where eventually we'll substitute a real type
-- we can write the type "list of a" by enclosing the type variable in square brackets [a]
- think of it as a "variable within a type signature" aka a "type variable"

List functions: take and drop take two arguments. Given a number n and a list, take returns the first n elements of the list, while drop returns all but the first n elements of the list.
ghci> take 2 [1,2,3,4,5]
ghci> drop 3 [1,2,3,4,5]
A tuple is a fixed-size collection of values, where each value can have a different type. This distinguishes them from a list, which can have any length, but whose elements must all have the same type.
  •  Haskell does not have the notion of a 1 element tuple.
  •  Often referred to using the number of elements as a prefix. 
  •  A 2-tuple has two elements; and is usually called a pair. , 3 elements - triple.
  • () - Tuple of zero-elements.
  • Haskell tuples are not immutable lists
  • all the elements of a list have to be of the same type, whereas in Python they can be of different types too
Tuples functions: fst and snd functions return the first and second element of a pair, respectively.
ghci> fst (1,'a')
ghci> snd (1,'a')
Passing an expression to a function
ghci> head (drop 4 "azerty")
We can read this as “pass the expression drop 4 "azerty" as the argument to head.
When we want to write a polymorphic type, we use a type variable, which must begin with a lowercase letter. 


No comments:

Post a Comment