Tuesday, February 19, 2013

HASKELL TYPING

HASKELL TYPING

REVISED: Wednesday, February 7, 2024




Haskell Typing.

I.  HASKELL TYPING

In Haskell, we denote a function f that takes as input a type a and gives as output a type b, as follows:

f :: a -> b

Every well formed expression has a type which can be automatically calculated at compile time using a process called type inference.

Types always start with a capital letter.

Prelude>  :type True
True :: Bool
Prelude>  

Haskell supports polymorphism for both data types and functions. The word “polymorphic” means “having many forms”; something which is polymorphic works for multiple types. Because the values in a list can have any type, we call the list type polymorphic. When we want to write a parametric polymorphic type, we use a type variable, which must begin with a lowercase letter. A type variable is a placeholder, where eventually we will substitute a real type.

A collection of related values is a type. A type system gives us abstraction. We can write the type “list of a” by enclosing the type variable in square brackets [a]. This amounts to saying “I don't care what type I have; I can make a list with it”.

In other languages you describe type by pointer-linked data structures; however, Haskell provides an implementation of data types similar to trees.

The combination of :: and the type after it is called a type signature; a declaration of the types of the function arguments and the function result.

x :: Integer

The :: can be read "has type"; therefore, the function x has type Integer.

The -> function arrow, can be read as "to" or "returns" and can take two types; for example, Int and Bool and produce a new type Int -> Bool. The function arrow -> describes a function mapping from one type "to" another. 

-> associates to the right, this means:

r :: Int -> (Int -> (Int -> (Int -> Int)))

The -> function arrow is used to bind a value to an object. Anything left of a -> function arrow is a parameter into your function. The thing to the right of the -> function arrow is the return value of your function.  Haskell groups a chain of arrows from right to left;  -> is right-associative; therefore, parentheses can be omitted.

TYPE               MEANING

a -> a                     the type function from any type a to the same type a.

a -> a -> a             the type function of two arguments of any type a to the same type a.

a -> Int                  the type function from any type a to Int.

Bool                       a Bool is a Boolean type. It can have only two values: True and False.

Char                      Char represents a character denoted by single quotes.

Double                   Double is a real floating point with double the precision.

Float                      Float is a real floating point with single precision.

Float -> Int            the type function from Float to Int.

Int                          this type integer, has a minimum negative, and maximum positive value.

Int -> Int                the type function from Int to Int.

Int -> Int -> Int     the type function from an Int and returns something of the type Int -> Int; it returns a function that takes an Int and returns an Int.

Integer                   this type Integer has no size limit except the capacity of your computer.

Num a => a            a being an instance of Num implies a.

II.  HASKELL TYPE CLASSES

A collection of types that support methods, overloaded operations, is called a type class.

A. BOUNDED

Bounded type class members have an upper and a lower bound.

B. ENUM

Enum type class members are sequentially ordered types; i.e., they can be enumerated.

C. EQ

Any type where it makes sense to test for equality between two values of that type is a member of the Eq, equality types, type class.

instance (Eq m) => Eq (Maybe m) where  
     Just x == Just y = x == y  
     Nothing == Nothing = True  
     _ == _ = False  

Maybe in itself is not a concrete type, it is a type constructor that takes one type parameter, like Char, to produce a concrete type, like Maybe Charall the types in functions have to be concrete.

While Maybe is not a concrete type, Maybe m is. By specifying a type parameter, m, which is in lowercase, we said that we want all types that are in the form of Maybe m, where m is any type, to be an instance of Eq.

A Maybe value can either be Just something or Nothing. Much like a list can be either an empty list or a list with some elements, a Maybe value can be either no elements or a single element. And like the type of a list of integers is [Int], the type of maybe having an integer is Maybe Int.

Prelude>  :module +Data.Maybe
Prelude>  :module +GHC.Show
Prelude>

Prelude>  :type maybe
maybe :: b -> (a -> b) -> Maybe a -> b
Prelude>

Prelude>  :info maybe
maybe :: b -> (a -> b) -> Maybe a -> b  -- Defined in `Data.Maybe'
Prelude>  

The a here is the type parameter. And, because there is a type parameter involved, we call Maybe a type constructor. Depending on what we want this data type to hold when it is not Nothing, this type constructor can end up producing a type of Maybe Int, Maybe String, etc. No value can have a type of just Maybe, because that is not a type in itself, it is a type constructor. In order for this to be a real type, that a value can be part of, it has to have all its type parameters filled up.

If you want to see what the instances of a typeclass are, just do :info YourTypeClass in GHCi. Typing :info Num will show which functions the typeclass defines and it will give you a list of the types in the typeclass. :info also works for types and type constructors. If you do :info Maybe, it will show you all the typeclasses that Maybe is an instance of. :info can also show you the type declaration of a function.

Prelude>  :info Num
class Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a
  -- Defined in `GHC.Num'
instance Num Integer -- Defined in `GHC.Num'
instance Num Int -- Defined in `GHC.Num'
instance Num Float -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'
Prelude>  

Prelude>  :info Maybe
data Maybe a = Nothing | Just a  -- Defined in `Data.Maybe'
instance Eq a => Eq (Maybe a) -- Defined in `Data.Maybe'
instance Monad Maybe -- Defined in `Data.Maybe'
instance Functor Maybe -- Defined in `Data.Maybe'
instance Ord a => Ord (Maybe a) -- Defined in `Data.Maybe'
instance Read a => Read (Maybe a) -- Defined in `GHC.Read'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
Prelude>

Maybe represents an option of either having nothing or having one of something. It does not matter what the type of that something is.

D. FROMINTEGRAL

fromIntegral takes an integral number and turns it into a more general number. 

Prelude> :type fromIntegral
fromIntegral :: (Num b, Integral a) => a -> b
Prelude>

For all types a and b,

if a is an instance of Integral and b is an instance of Num,

then fromIntegral can take a type a and produce a type b.

E. FRACTIONAL

Fractional, fractional types, are instances of Num which also support methods of fractional division and fractional reciprocation.

F. FUNCTOR

The Functor typeclass, is for things that can be mapped over. Mapping over lists is a dominant idiom in Haskell. The list type is part of the Functor typeclass.

class Functor f where  
     fmap :: (a -> b) -> f a -> f b

fmap has type function (a -> b), and is passed function f a and returns function f b.

f is not a concrete type, a type that a value can hold, like Int, Bool or Maybe String, but a type constructor that takes one type parameter.

fmap takes a function from one type to another and a functor applied with one type and returns a functor applied with another type.

For lists, fmap is just map.

map :: (a -> b) -> [a] -> [b]

Prelude>  fmap (/3)[3,6,9]
[1.0,2.0,3.0]
it :: Fractional b => [b]
Prelude>

Prelude>  map (/3)[3,6,9]
[1.0,2.0,3.0]
it :: Fractional b => [b]
Prelude>  

G. INTEGRAL

Integral, integral types, is a numeric class Num which also supports the methods of integer division and integer remainder. Integral describes types whose values are mathematical integers.

H. NUM

Num, numeric types, is a type class.  Num contains only types which behave like numbers.

Num a  ::  a -> a -> a 

The above example says, let a be a type belonging to the Num type-class. This is a function from type a to (a -> a).  As previously mentioned, the -> function arrow is right associative; therefore, parentheses are normally omitted in the function signature.

Notice when there is more than one type, the types are separated by ->. The last type in the list is the type of the result of the function.

Adding a constraint to a type definition is essentially never a good idea. It has the effect of forcing you to add type constraints to every function that will operate on values of that type.

I. ORD

Ord, ordered types,  is a type class for types that have an ordering.

J. READ

Read, readable types, is the opposite type class of Show.

In Haskell no function has two arguments. Instead all Haskell functions have only one argument. Taking two arguments is equivalent to taking one argument and returning a function taking the second argument as a parameter.

K. SHOW

Members of the Show, showable types, type class can be presented as strings.

III.  HASKELL USER DEFINED TYPE CLASSES

Type classes define a set of functions that can have different implementations depending on the type of data they are given.  A type a -> b in Haskell is actually implicitly understood to mean  in mathematical notation ( a,b : a  b). For those of you who have been away from math for awhile,  in mathematical notation means "for every"; : in mathematical notation means "such that"; and  in mathematical notation means "maps the set a into the set b". Therefore, ( a,b : a  b) can me read "For every a,b such that a function maps the set a into the set b".

in mathematical notation means "is an element of".

Constructions like “∀ x : x ∈ S: T(x) → U(x)” are not really primitives in  logic, they are shorthand for a logical implication: ∀ x : (x ∈ S) → (T(x) → U(x)). That is exactly what Haskell does with type classes, it writes them as a predicate; e.g., Num(x) with an implication symbol =>. The reason for the separate implication symbol is just to visually distinguish the part of the type that is a constraint predicate on the type variables. So when you write something like (Eq a) => a -> a -> Bool, what you are really saying is for all types a such that a is in Eq, this function has type a -> a -> Bool.

If you are not defining a type class for something very specific to your application, there is a good chance that there is already a suitable type class in the libraries, and you should use the library one, rather than defining your own. Your code will be much more portable and reusable if you take advantage of the type classes in the standard libraries.

Whether you are only going to use library classes, or define your own, you will still need to be able to read type class declarations, and read and write instances.

The keyword to define a type class in Haskell is classA type class declaration consists of two basic parts. The first is a declaration of what operations, methods, an instance of the class must support. The second is a set of default implementations of those methods.

Class methods are treated as top level declarations in Haskell. They share the same namespace as ordinary variables; a name cannot be used to denote both a class method and a variable or methods in different classes.

IV. TYPE ANNOTATION

Type annotations are a way of explicitly saying what the type of an expression should be. We do that by adding :: at the end of the expression and then specifying a type.

Prelude> :type read
read :: Read a => String -> a
Prelude>

Can be read "For all types a, so long as a is an instance of Read, the function read takes one parameter of type String and returns an a". Read a is not a type expression, but rather it expresses a constraint on a type, and is called a context. Contexts are placed at the front of type expressions.  

Prelude> read "12" :: Int
12
it :: Int
Prelude>

Prelude> read "12" :: Float
12.0
it :: Float
Prelude>

Prelude> (read "12" :: Float) ** 12
8.9161e12
it :: Float
Prelude>

Prelude> (read "12" :: Float) ** 2
144.0
it :: Float
Prelude>

V. TYPING USER DEFINED FUNCTIONS

Defining the type of a function before its declaration is not mandatory. Haskell's type system is powerful enough to allow us to avoid writing any type signatures at all. However, type signatures are considered good practice, because type signatures are a very effective form of documentation; and help bring programming errors to light.

If you want to give your function a type signature declaration and you are unsure as to what the type signature should be, you can always write the function without a type signature and then check the function with :t.

The GHCi command :set +t gives us type information for every expression we enter. We can turn off +t at any time, using the GHCi command :unset +t.

VI. GHCI TYPE DECLARATIONS

[] is pronounced "list of" when it is not an "empty list". For example [a] is read "list of" a.

head :: [a] -> a                -- gets the first element of a list

tail :: [a] -> [a]                -- gets everything but the first element

last :: [a] -> a                  -- gets the last element of a list

init :: [a] -> [a]               -- gets everything but the last element

(++) :: [a] -> [a] -> [a]   -- concatenates two lists together

(:) :: a -> [a] -> [a]         -- prepends an element to a list

fst  :: (a,b) -> a               -- gets the first element of a tuple

snd  :: (a,b) -> b             -- gets the second element of a tuple

As shown below, GHCi can create either type Int integers or type Integer integers.

Prelude>  let x :: [Int]; x = [6,7,8]
x :: [Int]
Prelude> 

Prelude> let x :: [Integer]; x = [6,7,8]
x :: [Integer]
Prelude>

VII. CONCLUSION

In this tutorial, you have received an introduction to Haskell typing.

VIII. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.



Friday, February 15, 2013

HASKELL MONADS

HASKELL MONADS

REVISED: Wednesday, January 24, 2024




Haskell Monad.

The monad serves as the glue which binds together the actions in a program.

I.  FUNCTIONAL VERSUS IMPERATIVE

In functional programming, code is just like data; code and data are the same. In imperative programming, code and date, are two different things. For example, imperative programmers often access a function's data, via "table look ups".

The term "monad" comes from "category theory", which is a branch of algebra; or, depending on whom you talk to, algebra is a branch of "category theory."

Eugenio Moggi introduced the idea of using monads for programming in 1988, around the time the Haskell 1.0 standard was being developed. Many of the functions in today's Prelude date back to Haskell 1.0, which was released in 1990. In 1991, Philip Wadler started writing for a wider functional programming audience about the potential of monads, at which point they began to see some use. Not until 1996, and the release of Haskell 1.3, did the standard acquire support for monads.

Functional programming is not difficult; you do not need to know "category theory" to program "shared mutable state" with functions using  Haskell monads. Haskell functions are first-class data types, meaning that Haskell programs can work with them just as well as they can work with any other type of data.

x : int                   -- Asserts function x has type int.

f : int -> int      -- Asserts function f is a thing that takes an int and gives you an int.

x : a                      -- Asserts function x has type a, which is a generic, any type.

f : a -> a            -- Asserts function f takes an a of any type and gives you an a of any type.

g : a -> a           -- Asserts function g takes an a of any type and give you an a of any type.

We can combine the two functions f and g shown above.

One way would be to call the function g on a variable a of type a; for example, g(a); then call the function f on that result; for example, f(g(a))

Another way would be to call the function f on a variable a of type a; for example, f(a); then call the function g on that result; for example, g(f(a))

In Haskell, calling a function is the same as function application.

g a        -- Function application in Haskell; calling the function g with an argument of type a.

g(f a)  -- Calls function f first and then calls function g.

f(g a)  -- Calls function g first and then calls function f.

Function composition: composing two functions produces a new function that, when called with a parameter, a, is the equivalent of calling g with the parameter a, and then calling f with that result.

(f o g) a = f (g a)    

The little circle o is called function composition; it is a generic composition operator. The notation (f o g) is read as "f composed with g" or just "f of g". Composition operators are studied in the field of "operator theory".

Prelude>  :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Prelude> 

(f o g) = h

(f o g) = h : a -> a     -- The function h takes an a of any type and give you an a of any type.

II.  MONOID

Functions under composition are a monoid.

A monoid is a set or collection of things, plus a rule for combining those things, and that rule obeys some rules. 

One of the biggest problems in software today is controlling complexity. The world of side effects is very complicated. Monoids are the way to build complexity. Monoids allow you to create complexity starting with simplicity. We started with two functions and created a third function of the same type; i.e.:

f  : a -> a            
g : a -> a            
h : a -> a     

Compositionality is the way to control complexity.

Examples of monoids:

(+)     and 0
(*)     and 1
(||)    and False
(&&) and True
(++) and []
(>>) and done

III.  MONOID EXAMPLE

Consider a clock. The numbers on a clock form a monoid. The rule for combining them is take one number from the clock x, add another number from the clock y, and then cast out 12s; for example:

(x + y) % 12     -- % is "modulus" which in this case means the remainder after dividing by 12. 

(7 + 10) / 12 = 17/12 = 1 twelve and a remainder of 5. 

Prelude> (7 + 10) `mod` 12     -- `mod` is a modulus operator.
5
it :: Integral a => a
Prelude>

Prelude> (7 + 10) `rem` 12     -- `rem` is a modulus operator.
5
it :: Integral a => a
Prelude>

A. ASSOCIATIVITY

It does not matter how you group the applications; function composition is always associative.

⊕ (y ⊕ z) = (x ⊕ y) ⊕ z

(f o g) o h = f o (g o h)     -- (g o h) = g (h a) and  o (g o h) = f ( g(h a) )

B. EXISTENCE OF A UNIT OR A ZERO

The monoid must contain a special member such that:
 ⊕ 12 = x            -- In the clock example, 12 represents a "special member".
12 ⊕ x = x

There is a special function that lives in the monoid called id.


id : a -> a
id a = a

(f o id) = f (id a)
            = f a

In Haskell unit is:


return : a -> Ma

C. COMMUTATIVITY


A monoid does not have to satisfy the law of commutativity.

x ⊕ y != y ⊕ x 


f(g a) != g(f a)          -- For example, sin cos not same as cos sin.

If you are going to nest function calls, the types must line up; then compositionality makes sense.

IV.  MONADS

x : a

f : a -> Ma          -- Ma is a type constructor which creates a function of a generic type.            
g : a -> Ma         -- The function g takes an a and returns a Ma            
h : a -> Ma
>>= : a -> Ma     

\a -> [ (f a) >>=  \a -> (g a) ]        -- A function of a that does f a; >>= is  bind or shove
          Ma             a -> Ma            -- Ma is data living in a monad; or functions live in a monoid.

\a -> [ Ma >>=  a -> Ma ]

>>= ensures your functions are compositional.

g : a -> b
f : b -> c
(f o g) : a -> c

(f o g) a = f (g a)

V. CONCLUSION

In this tutorial, you have received an introduction to Haskell monads.

VI. REFERENCES

Brian Beckman: Don't fear the Monad.







Thursday, February 14, 2013

HASKELL BINDING OPERATORS

HASKELL BINDING OPERATORS

REVISED: Wednesday, January 24, 2024




Haskell Binding Operators.

We will be using the following import:

Prelude> import Control.Monad
Prelude Control.Monad>

As shown below the join, (>>=), and return binding operators all produce the same results.

Prelude Control.Monad> :t join
join :: Monad m => m (m a) -> m a

Prelude Control.Monad>

Prelude Control.Monad> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Prelude Control.Monad>


Prelude Control.Monad> :t return
return :: Monad m => a -> m a
Prelude Control.Monad>

I. BINDING OPERATORS


There are no variables in Haskell. In Haskell you never assign a variable, instead you bind a name to a value. However, you will often see the term variable used in describing Haskell programs as a result of its common usage.

In a pure functional language, a function can only read what is supplied to it in its arguments and the only way it can have an effect on the world is through the values it returns. Non-functional "IO actions," which have side effects, are hidden from the functional world of Haskell by the IO monad.

IO actions are defined within the IO monadIO actions resemble functions. IO actions do nothing when they are defined, but IO actions perform some task when they are invoked.

Monads allow us to express sequential execution of actions. We define our sequence of operations by placing IO operations inside of a monad.

Three Monad Laws
1. Left identity: return x >>= f is the same as f x
2. Right identity: m >>= return is no different than just m
3. Associativity: (m >>= f) >>= g is just like doing m >>= (\x -> f x >>= g)

The “glue” combinator >>= function is pronounced "bind."

Technically each Monad in Haskell is not a type, but a "type constructor." monads are in the category theory branch of mathematics. IO is a monad, so IO actions can be combined using either the do notation or the >> chevron function which is pronounced then and the >>= bind function operations from the Monad class.

Any IO procedure has one more parameter compared to what you see in its type signature. This parameter is hidden inside the definition of the type alias IO.

Binding operators combine two IO actions, executing them sequentially. Bind f x is normally written as x  >>=  fx >>= f is the action that first performs the action x, and captures its result, passing it to f, which then computes a second action to be performed. That action is then carried out, and its result is the result of the overall computation.

The <- kleisli arrow symbol desugars to >>= bind; the =<< bind function is exactly the same as the >>= bind function except it takes its arguments in the opposite order.

Prelude>  import Control.Monad
Prelude>

Prelude> :type (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
Prelude>

The >>= bind function binding operator implements sequential composition allowing us to use the result of the first action it gets passed as an additional parameter to the second one.

Prelude> :type (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Prelude>

The >>= bind operator takes as its input a monadic value also known as an action, unpacks a regular non-monadic value from it, the details of which are specific to the particular monad, and passes that value as the input to the monadic function, which produces a monadic value action as its final result.

There are two fundamental monadic operations, one named "bind" the >>= operator and one named return.

The bind (>>=) operator is a monadic apply operator. It can be used to define a monadic composition operator, which is written (>=>) and read as fish

Prelude>  :type (>=>)
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
Prelude>

The return operator transforms regular values into monadic values. It can be used to define a function to convert regular functions into monadic functions.

Bind takes two arguments, the left and right operands, and returns a compound action. The meaning of this new action is to first perform the action to the left. The left action produces a value of type a. Then the function to the right is applied with this value, which returns a second action. Finally the second action is performed. The value it produces becomes the result of the whole compound action. It is common to use the letter k for the second argument of (>>=) bind because k stands for “continuation”.

Prelude> :type (>>)
(>>) :: Monad m => m a -> m b -> m b
Prelude>

The >> function read as chevron is a binding operator that ignores the value of its first action and returns as an overall result the result of its second action only.

Prelude> :type return
return :: Monad m => a -> m a
Prelude>

Prelude> :type fail
fail :: Monad m => String -> m a
Prelude>

The kleisli arrow function <- pronounced "drawn from", indicates that the result of an action is being bound. The way the kleisli arrow  function <- binding operator is processed is that the name on the left-hand side of the kleisli arrow  function <- becomes a parameter of subsequent operations, represented as one large IO action.

Any IO action that you write in a do statement, or use as a parameter for either the >> chevron function or the >>= bind function operators, is an expression returning a result of type IO a for some type a.

The unit type () is an empty tuple which has both a value and type of (). The unit type is similar to a null type or void in other languages.

IO is a monad, which is a type class. An instance of the monad type class, must include the bind functions (>>=) and return. The monad serves as the glue which binds together the actions in a program.

The use of the name main is important. main is defined to be the entry point of a Haskell program. main always has a type signature of main :: IO something, where something is some concrete type. By convention, we do not usually specify a type declaration for main.

If we are taking data out of an IO action, we can only take it out when we are inside another IO action. In other words, to get the value out of an IO action, you have to perform it inside another IO action by binding it to a name with the <- kleisli arrow function. Variables bound by the <- kleisli arrow function are lambda bound and are thus monomorphic. IO actions will only be performed when they are given a name of main or when they are inside a bigger IO action that was composed with a do block. Use the <- kleisli arrow function when you want to bind results of IO actions to names. Use let bindings to bind pure expressions, normal non-IO expressions, to names. Within do blocks or list comprehensions let without in introduce local bindings.

Pure function application should use let instead of the binding kleisli arrow <-.

You are always writing code in the IO monad when you are using GHCi.  GHCi evaluates the IO action, then calls show on the IO action, and prints the string to the terminal using putStrLn implicitly. 

Prelude>  :type when
when :: Monad m => Bool -> m () -> m ()
Prelude>  

when takes a Boolean value and an IO action, if that Boolean value is True, it returns the same IO action that we supplied to it. However, if it's False, it returns the return () action, an IO action that does not do anything.

Prelude> :type sequence
sequence :: Monad m => [m a] -> m [a]
Prelude>

sequence takes a list of IO actions and returns an IO action that will perform those actions one after the other. The result contained in that IO action will be a list of the results of all the IO actions that were performed.

Prelude> :type mapM
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
Prelude>

mapM takes a function and a list, and maps the function over the list, and then sequences it.

Prelude> :type mapM_
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
Prelude>

mapM_ does the same as mapM; however, mapM_ throws away the result later.

Prelude> :type forever
forever :: Monad m => m a -> m b
Prelude>

forever takes an IO action and returns an IO action that just repeats the IO action it received forever.

Prelude> :type forM
forM :: Monad m => [a] -> (a -> m b) -> m [b]
Prelude>

forM  is like mapM, only it has its parameters switched around. The first forM parameter is the list and the second one is the function to map over that list, which is then sequenced.

To get a list of the bindings currently in scope, use the :show bindings command.

A. LOCAL VARIABLES

Haskell also allows for local bindings; which means we can create values inside of a function that only that function can see. Local bindings are created by using a let in declaration. You can provide multiple declarations inside a let; however, make sure they are indented the same amount, or you will have layout problems.

The keywords to look out for here are let, which starts a block of variable declarations, and in, which ends it. Each line introduces a new local variable. The name is on the left of the =, and the expression to which it is bound is on the right.

In general, we will refer to the places within our code where we can use a name as the name's scope. If we can use a name, it is in scope, otherwise it is out of scope. If a name is visible throughout a source file, we say it is at the top level, it is global.

We can use another mechanism to introduce local variables: the where clause. The definitions in a where clause apply to the code that precedes it. It lets us direct our reader's focus to the important details of an expression, with the supporting definitions following afterwards. For example, you can use where to define a local variable scoped over multiple guarded branches.

Haskell's syntax for defining a variable looks very similar to its syntax for defining a function. This symmetry is preserved in let and where blocks; we can define local functions just as easily as local variables. 

We can also define global variables, as well as global functions, at the top level of a source file.

II. CONCLUSION


In this tutorial, you have received an introduction to the Haskell binding operators.

III. REFERENCES


Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.

Wednesday, February 13, 2013

HASKELL USER INPUT

HASKELL USER INPUT

REVISED: Monday, October 21, 2024




Haskell user input.

Imperative programming is monadic; and, monadic do blocks look like imperative code.

I.  HASKELL USER INPUT

A. WRITE HASKELL PROGRAM

Haskell is a lazy language, the order in which operations are evaluated in it is unspecified. do allows us to specify the order of operations. Therefore, if we want to write a function that is interactive one way to do this is to use the do keyword. However, the last statement in a do block must be an expression. For example, as shown below the last statement is a putStrLn which starts an expression.

For example; "Copy Paste" the following Haskell program into your text editor:

module Food
    where

main = do  
    putStrLn "Type your favorite food or type exit and press Enter."  
    food <- getLine  
    if food == "exit"
      then do 
        return ()
      else do  
        putStrLn ("Amazing! My favorite food is also " ++ food ++ "!")
        main

From your text editor do a "File, Save As", and save the file as Food.hs to your working directory.

To get the value out of an I/O action, you have to perform it inside another I/O action by binding it to a name with <-, a function arrow pronounced: "drawn from".

Read "food <-  getLine" as, "Perform the I/O action getLine and then bind its result value to food". The getLine function works with <- and binds input to a variable. getLine has a type of IO String, so food will have a type of String. In other words, food is "drawn from" getline.

In a do block, the last action cannot be bound to a name. The value from the last action is extracted and bound by the do block to the result.

B. LOAD HASKELL PROGRAM INTO GHCi INTERPRETER

After the GHCi  Prelude> prompt type :load Food as shown below, then press Enter:

Prelude> :load Food
[1 of 1] Compiling Food             ( Food.hs, interpreted )
Ok, modules loaded: Food.

C. CALL MAIN FUNCTION IN GHCi

Prelude>  main
Type your favorite food or type exit and press Enter. 
Steak   -- Enter your favorite food at the prompt.
Amazing! My favorite food is also Steak!
Type your favorite food or type exit and press Enter.
exit
it :: ()   -- Appears because of options currently set: +t
Prelude>  

II. SUMMARY

Every line of a do structure must return some IO a.

The <- drawn from operator takes a function of type IO a and extracts the a value.

The last line of a do structure cannot use a <- drawn from operator.

Any function that calls an IO function must also be an IO function.

IO functions call pure functions.

Pure functions never ever call IO functions.

III. CONCLUSION

In this tutorial, you have received an introduction to Haskell user input.

IV. REFERENCES

Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.

Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.

Goerzen, J. & O'Sullivan, B. &  Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.

Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.

Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.

Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.