Thursday, January 31, 2013

HASKELL INPUT AND OUTPUT (IO)

HASKELL INPUT AND OUTPUT (IO)




REVISED: Friday, February 9, 2024




Haskell Input and Output (IO).

Good Haskell style involves separating pure code from code that performs IO.

I.  HASKELL IMPORT

I am asking you to input the following imports so I can use them in examples "I. A." and "I. B." shown below. I also want to demonstrate the dangers of using imports without knowing their contents.

Prelude> import Control.Arrow
Prelude>

Prelude> import Control.Monad
Prelude>

Prelude> import Data.ByteString
Prelude>

Prelude> import Data.Char
Prelude>

Prelude> import Data.List 
Prelude>

Prelude> import System.IO  
Prelude>

Prelude> import System.Directory
Prelude>

Prelude> import System.Environment 
Prelude>

Prelude> import System.IO.Error
Prelude>

Prelude> import System.Random 
Prelude>

A. :SHOW IMPORTS

Prelude> :show imports
import Prelude -- implicit
import Control.Arrow
import Control.Monad
import Data.ByteString
import Data.Char
import Data.List
import System.IO
import System.Directory
import System.Environment
import System.IO.Error
import System.Random
:module +*Main -- added automatically
Prelude>

Notice Data.ByteString is in the above list of imports.

B. :MODULE -M

Where M is the name of the import you want to remove, imports can be removed from the current scope, using the syntax :module -M as shown below:

Prelude> :module -Data.ByteString
Prelude>

Prelude> :show imports
import Prelude -- implicit
import Control.Arrow
import Control.Monad
import Data.Char
import Data.List
import System.IO
import System.Directory
import System.Environment
import System.IO.Error
import System.Random
:module +*Main -- added automatically
Prelude>

Notice Data.ByteString is not in the above list of imports.

The full syntax of the :module command is: 

:module [+|-] [*]mod1 ... [*]modn

Using the + form of the module command adds modules to the current scope, and - removes them.

You cannot add a module to the scope if it is not loaded.

II.  HASKELL "IO ACTIONS"

If you did:

Prelude> import Data.ByteString
Prelude>

Prelude> import System.IO
Prelude>

and did not do:

Prelude> :module -Data.ByteString
Prelude>

as shown above in I., you will receive an "ambiguous occurrence" error message from GHCi when you do the examples shown below. GHCi will not be able to determine which import you are referring to. Therefore, you have to be very careful when using multiple imports. It is a good idea to know everything contained in an import before you use it.

The GHCi prompt operates as if the lines were being typed into a do block in the IO monad.

Prelude> :type putStrLn
putStrLn :: String -> IO ()
Prelude>

putStrLn gives back nothing, ().

Prelude>  :t getLine
getLine :: IO String
Prelude>

getLine gives back a String to use. 

Prelude> :type readFile
readFile :: FilePath -> IO String
Prelude>

IO is Haskell’s way of representing that  putStrLn and readFile are not really functions, in the pure mathematical sense, they are “IO Actions”. Typical actions include reading and setting global variables, writing files, reading input, and opening windows.

The -> notation is a way to get the value out of an action. The (), pronounced “unit”, is an empty tuple indicating that there is no return value from putStrLn. This is similar to "void" in Java or C.

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 -> arrow function. Variables bound by the -> 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. Therefore, when you want to bind results of IO actions to names, use the -> arrow function.

The only way to use things with an IO type is to combine them with functions using do notation which can include  if/then/else and case/of. In a do expression, every line is a monadic value. We code do and then we lay out a series of steps, like we would in an imperative program chaining computations. Each of these steps is an IO action, a control flow expression. A statement is either an action, a pattern bound to the result of an action using <-, or a set of local definitions introduced using letBy putting them together with do syntax, we glue them into one IO action. do works with any monad, the action that we get has a type of IO (), because that is the type of the last IO action inside the doWhen sequencing actions with do notation, each “bare” line, lines that do not have a <- in them, must have type IO ().

do can replace the  >> pronounced "then" operator.

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

We can use do syntax to glue together several IO actions into one.  The value from the last action in a do block is bound to the do block result.

You always do IO inside a do statement, using the IO monad. This way you are guaranteed that IO actions are executed in order.

$ is pronounced "apply." When a $ is encountered, the expression on its right is applied as the parameter to the function on its left.

A. REVIEW

First, we will review GHCi "ambiguous occurrence" error messages

Try doing the following examples. You will receive another GHCi "ambiguous occurrence" error message. The point I am repeatedly trying to make is you should understand the contents of imports before using them.

Exit out of GHCi and then reload GHCi. Use the following commands to see what you start out with in GHCi when it is first loaded.

Prelude>  :show
options currently set: +t   -- +t prints type after evaluation
base language is: Haskell2010
with the following modifiers:
  -XNoDatatypeContexts
  -XNondecreasingIndentation
GHCi-specific dynamic flag settings:
other dynamic, non-language, flag settings:
  -fimplicit-import-qualified
warning settings:
Prelude>

Prelude>  :show imports
import Prelude -- implicit
Prelude>  

Second, we will show a basic example of putStrLn:

Prelude> :{
Prelude| do {
Prelude| putStrLn "Hello, World!"
Prelude| }
Prelude| :}
Hello, World!
it :: ()
Prelude>

Third, we will show an example of using getLine and $ with putStrLn:

Prelude> :{
Prelude| let prRev = do {
Prelude|      inp <- getLine;
Prelude|      putStrLn $ reverse inp;
Prelude| }
Prelude| :}
Prelude| 
Prelude>

Prelude> :type prRev
prRev :: IO ()
Prelude>

Prelude> prRev
Hello, World!
!dlroW ,olleH
Prelude>

B. OUTPUT FUNCTIONS

These functions write to the standard output device, which is normally the user's terminal.

Prelude> import Data.Char
Prelude>

Prelude> :type print
print :: Show a => a -> IO ()
Prelude>

Prelude> :type putChar
putChar :: Char -> IO ()
Prelude>

The unit type (), which is similar to void in other languages, is used by actions which return no values.  return packs up a value into an IO box. <- extracts the value out of an IO box and is read as "comes from". In other words, return turns a value into an IO action and <- turns an IO action into a regular value.

"Copy paste" the following Haskell script into your text editor and "save as" TestReturn.hs  to your working directory:

{-

Keep lines to no more than 80 columns.
Do not use tabs.
Use CamelCase, do not use underscores, for variable names.
Do not leave trailing white space in your lines of code.
Do not use braces and semicolons.
Use spaces for indenting.
Indent code blocks 4 spaces (let, where, do and of).
Indent "where" keyword 2 spaces.
Indent "where" definitions 2 spaces.
Indent "guards" 2 spaces.

-}

module TestReturn where

main = do putStrLn "Shall I quit the program? y/n"
          ans <- getLine
          if ans /= "y"
             then do putStrLn "Thank you! I enjoy working with you!"
                     main
             else do putStrLn "Nice working with you my friend! Happy trails, until we meet again!"
                     return ()  -- We created an IO that does not do anything so the program can exit.

As shown below, load the TestReturn program, then run the module TestReturn function main, in GHCi:

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

Prelude>  main
Shall I quit the program? y/n
n
Thank you! I enjoy working with you!
Shall I quit the program? y/n
y
Nice working with you my friend! Happy trails, until we meet again!
it :: ()
Prelude>  

putStrLn is a function that takes a single argument of type String and produces a value of type IO (). The IO () signifies an executable action that returns a value of type (). When we supply putStrLn with a String argument we get an executable IO action which will print the supplied String.

Prelude> :type putStr
putStr :: String -> IO ()
Prelude>

Prelude> putStr "Hello"
Helloit :: ()   -- Notice that two lines combine without a \n newline escape sequence!
Prelude> 

Prelude> putStr "Hello\n"
Hello   -- The \n newline escape sequence does a carriage return.
it :: ()Prelude>

Prelude> :type putStrLn
putStrLn :: String -> IO ()
Prelude>

Prelude> :type putStrLn "abcdefghijklmnopqrstuvwxyz"
putStrLn "abcdefghijklmnopqrstuvwxyz" :: IO ()
Prelude>

C. INPUT FUNCTIONS

These functions read input from the standard input device, which is normally the user's keyboard. 

Prelude> :type getChar
getChar :: IO Char
Prelude>

When the function getChar is invoked, it will perform an action which returns a character.

Prelude> :type getLine
getLine :: IO String
Prelude>

Should be read as, "getLine is an action that, when performed, produces a string".

Prelude> :type getContents
getContents :: IO String
Prelude>

Prelude> :type interact
interact :: (String -> String) -> IO ()
Prelude>

Prelude> :type readIO
readIO :: Read a => String -> IO a
Prelude>

Prelude> :type readLn
readLn :: Read a => IO a
Prelude>

Use let bindings to bind pure expressions, normal non-IO expressions, to names. For example:

Prelude> let y = 12
y :: Num a => a
Prelude>

Prelude> y
12
it :: Num a => a
Prelude>

As shown above, let bindings do not automatically print the value bound.

As shown below, when we type out a monadic IO action in GHCi and press return, the IO action will be performed:

Prelude> putStrLn "Hello, World!" 
Hello, World!
it :: ()
Prelude>

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. 

D. IO EXAMPLE 1

"Copy, Paste" the following program into your text editor and "File, Save As" point.hs to your working directory:

-- Function point.

point :: IO (Char,Char)
point = do {  x <- getChar
                    ; getChar
                   ; y <- getChar
                   ; return (x,y)
                 }

Load point.hs into GHCi as follows:

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

From GHCi call the point program as follows:

Prelude>  point
8  -- You will be prompted twice. At each prompt type an Integer then press Enter.
2
('8','2')  -- The output will return a tuple point :: IO (Char,Char).
Prelude>

E. IO EXAMPLE 2

"Copy, Paste" the following program into your text editor and "File, Save As" name.hs to your working directory:

-- Program name.

import Data.List
import System.IO

main :: IO ()
main = do {  putStrLn "What is your name?"
                    ; yn 
 <- getLine
<- getline="" span="">                     ; putStrLn ("Hello " ++ yn ++ "!" ) 
                  }

Load name.hs into GHCi as follows:

Prelude>  :load name
[1 of 1] Compiling Main             ( name.hs, interpreted )
Ok, one module loaded.
*Main>

From GHCi call the name program as follows:

*Main>  main
What is your name?
Ron
Hello Ron!
*Main> 

III. CONCLUSION

In this tutorial, you have received an introduction to Haskell input and output (IO).

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.


Tuesday, January 29, 2013

HASKELL CONTROL STRUCTURE INTRODUCTION

HASKELL CONTROL STRUCTURE INTRODUCTION


REVISED: Friday, February 9, 2024




In this tutorial, you will receive an introduction to Haskell control structure.

I.  HASKELL CONTROL STRUCTURE

Without mutable variables, recursion is the only way to implement control structures.

A. HASKELL IF EXPRESSION

if condition
    then trueValue
    else  falseValue      

An expression is a piece of code that returns a value.

Haskell's "if expression" syntax is as follows:

if <condition> then <trueValue> else <falseValue>

<condition> is an expression which evaluates to a Boolean. If the <condition> is True then the <trueValue> is returned, otherwise the <falseValue> is returned.

In Haskell the else is mandatory.

The <trueValue> and <falseValue> must evaluate to the same type, which will be the type of the whole if expression.

Semicolons ; are not allowed in an if/then/else.

then and else must be indented deeper than the if statement.

The expressions after the then and else keywords are branches. The branches must have the same types. if expressions must also have the same types.

B. HASKELL GUARDS

Pattern matching limits us to performing fixed tests of a value's shape. We can use pattern matching to ensure we are looking at values of the right shape. We can use guards to compare pieces of a values shape.

| (guard boolean expression) = (guard function body expression)

A pattern can be followed by zero or more guards. Guards must be expressions of type Bool. A guard begins with a | pipe symbol, followed by the Boolean guard expression. Then followed by an = equal symbol, or -> to symbol if we are in a case expression. Then followed by the body to use if the Boolean guard expression evaluates to True. If a pattern matches, each guard associated with that pattern is evaluated, in the order in which the guards are written. If a Boolean guard expression evaluates to True, the body affiliated with that guard is used as the result of the function. If no guard evaluates to True, pattern matching continues to the next pattern.

The -> function arrow, read "to", 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. 

When a guard expression evaluates to True, all of the variables mentioned in the pattern with which it is associated are bound and can be used.

Guards are a sequence of logical expressions used to choose between a sequence of results of the same type. If the first guard is True then the first result is chosen, otherwise if the second guard is True then the second result is chosen, and so on.

Guards are a way of testing whether some property of a value are True or False.

A guard is a Boolean expression. If it evaluates to True, the corresponding function body is used. If it evaluates to False, checking drops through to the next guard; etc.

Always use an otherwise guard as the last guard in order to have a match for all remaining cases.  otherwise is defined as otherwise = True and catches everything you did not code in the other guards.

Guards can be used instead of if-then-else expressions. Guards are evaluated in order and indicate various cases in the computation. The first guard that is True controls the result.

Module:

module BooleanXY where

booleanXY :: (Ord a1, Ord a, Num a1, Num a) => a -> a1 -> [Char]
booleanXY x y
    | x < 50      = "No"
    | y >= 50    = "Yes"
    | otherwise = "Maybe"

GHCi:

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

Prelude>  :type booleanXY
booleanXY :: (Ord a1, Ord a, Num a1, Num a) => a -> a1 -> [Char]
Prelude>

Prelude>  booleanXY 10 50
"No"
Prelude>

Prelude>  booleanXY 50 50
"Yes"
Prelude>

Prelude>  booleanXY 60 30
"Maybe"
Prelude> 

Module:

module MyReplicate where

myReplicate :: (Ord a, Num a) => a -> t -> [t]
myReplicate n x
        | n <= 0      = []
| otherwise = x:myReplicate (n-1) x

GHCi:

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

Prelude>  myReplicate 5 47
[47,47,47,47,47]
Preluce>

Prelude>  myReplicate 47 5
[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5]
Prelude>

Prelude>  myReplicate (-47) (-5)
[]
Prelude>

II. CONCLUSION

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

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.




HASKELL MATH INTRODUCTION

HASKELL MATH INTRODUCTION
REVISED: Friday, February 9, 2024



Mathematics is a purely functional language.

I.  HASKELL IT

An expression is a piece of code that returns a value.

Whenever a non-binding statement, is typed at the prompt, GHCi implicitly binds its value to the name it. For example:

Prelude> 2 + 10
12
it :: Num a => a
Prelude>

Prelude>  it
12
it :: Num a => a
Prelude>

Prelude> it * 6
72
it :: Num a => a
Prelude>

Prelude>  :type it
it :: Num a => a
Prelude>

Prelude>  :info it
it :: Num a => a -- Defined at <interactive>:10:1
Prelude>  

The special variable it is shadowed by the new value each time you evaluate a new expression, and the old value of it is lost. The special variable it is actually the name of a special variable, in which GHCi stores the result of the last expression evaluated. The special variable it is not a Haskell language feature; it is specific to GHCi.

Turn GHCi off and restart GHCi. After the Prelude> prompt type :t it press Enter and think about what you see.

Prelude>  :type it
<interactive>:1:1: error:
    Variable not in scope: it
    Perhaps you meant `id’ (imported from Prelude)
Prelude>

You receive the error message because you have not yet input anything which creates an it.

II.  HASKELL ARITHMETIC

A race condition occurs when 2 or more threads are able to access shared data and they try to change it at the same time. Imperative programs will always be vulnerable to data races because they contain mutable variables. There are no data races in Haskell because Haskell does not have mutable variables. Data is immutable, unable to be changed, in Haskell.

In Haskell lazy evaluation, the expression 1 + 2 is not reduced to the value 3. Instead, we create a “promise” that when the value of the expression 1 + 2 is needed, we will be able to compute it. The record that we use to track an unevaluated expression is referred to as a thunk, deferred expression. This is all that happens; we create a thunk, and defer the actual evaluation until it is really needed. If the result of this expression is never subsequently used, we will not compute its value at all.

In Haskell you never assign to a variable, instead you bind a name to a value.

A. ADD +

Prelude> 1 + 1
2
it :: Num a => a
Prelude>

In general, any function such as + which is used infix (meaning in the middle of two arguments rather than before them) must be put in parentheses (+) when getting its type.

Prelude>  :type (+)
(+) :: Num a => a -> a -> a  -- Works for any type 'a', provided 'a' is an instance of class Num.
Prelude>

Prelude>  :info (+)
class Num a where
  (+) :: a -> a -> a
  ...
  -- Defined in `GHC.Num'
infixl 6 +
Prelude>

B. SUBTRACT -

Prelude> 6 - 2
4
it :: Num a => a
Prelude> 

Prelude>  :type (-)
(-) :: Num a => a -> a -> a
Prelude>

Prelude>  :info (-)
class Num a where
  ...
  (-) :: a -> a -> a
  ...
       -- Defined in `GHC.Num'
infixl 6 -
Prelude>  

C. MULTIPLY *

One is the identity for multiplication. That is, 1 * x = x and x * 1 = x for any integer x.

Multiplication can be reduced to repeated addition.

Prelude> 2 * 3     -- 6 = 2 + 2 + 2
6
it :: Num a => a
Prelude> 

Prelude>  :type (*)
(*) :: Num a => a -> a -> a
Prelude>

Prelude>  :info (*)
class Num a where
  ...
  (*) :: a -> a -> a
  ...
       -- Defined in `GHC.Num'
infixl 7 *
Prelude>  

Prelude> 3 * -2
<interactive>:8:1: error:
    Precedence parsing error
          cannot mix ‘*’ [infixl 7] and prefix - [infixl 6] in the same infix expression
Prelude>

Prelude> 3 * (-2)     -- -6 = (-2) + (-2) + (-2)
-6
it :: Num a => a
Prelude>

As shown above, if you want to use a negative number surround the negative number with parentheses.

D. DIVIDE

/ performs floating-point division only. For integer division we can use `div`.

Prelude> 4 / 2
2.0
it :: Fractional a => a
Prelude>

Prelude>  :type (/)
(/) :: Fractional a => a -> a -> a
Prelude>

Prelude>  :info (/)
class Num a => Fractional a where
   (/) :: a -> a -> a
   ...
        -- Defined in `GHC.Real'
infixl 7 /
Prelude>  

Operator        Description
/                Performs integer division, including the remainder.

quot  Performs integer division, discarding the remainder.

div                Performs integer division, rounding towards negative infinity.

quotRem       Performs integer division and returns a tuple containing the quotient and remainder.

The quot keyword is the most efficient way to perform integer division in Haskell. It is also the most concise, which makes it easier to read and write code.

E. EXPONENT

Haskell has three exponentiation operators: (^), (^^), and (**). ^ is non-negative integral exponentiation, ^^ is integer exponentiation, and ** is floating-point exponentiation.

Use the ^ exponent operator when you need a non-negative integer as the exponent.

Prelude>  2 ^ 5
32
it :: Num a => a
Prelude>

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

Prelude>  :info (^)
(^) :: (Num a, Integral b) => a -> b -> a -- Defined in `GHC.Real'
infixr 8 ^
Prelude>    

Prelude>  2 ^ (-5)
*** Exception: Negative exponent
Prelude>

Use the ^^ exponent operator when you need a positive or negative integer as the exponent.

Prelude>  2 ^^ 5
32.0
Prelude>

Prelude>  :type (^^)
(^^) :: (Integral b, Fractional a) => a -> b -> a
Prelude>  

Prelude>  :info (^^)
(^^) :: (Fractional a, Integral b) => a -> b -> a
  -- Defined in ‘GHC.Real’
infixr 8 ^^
Prelude>  

Prelude>  2 ^^ (-5)
3.125e-2
Prelude>

Use the ** exponent operator when you need a positive or negative floating point number as the exponent.

Prelude> 2 ** 5.0
32.0
it :: Floating a => a
Prelude> 

Prelude>  :type (**)
(**) :: Floating a => a -> a -> a
Prelude>

Prelude>  :info (**)
class Fractional a => Floating a where
  ...
  (**) :: a -> a -> a
  ...
         -- Defined in `GHC.Float'
infixr 8 **
Prelude>  

Prelude>  2 ** (-5.0)
3.125e-2
Prelude>

Use the exp exponent operator to use Euler's number e,  the base of the Natural Logarithms.

Logarithms are another way of thinking about exponents. For example, in exponential form 2 3 = 8 and in logarithmic form log 2 8 = 3. In other words if b = y then log b y = x and the base is b and the exponent is x.

Furthermore:

log b (xy) = log b x + log b y

log b (x/y) = log b x - log b y

log b (x y) = y (log b x)

Prelude>  exp 1
2.718281828459045
it :: Floating a => a
Prelude> 

Prelude>  :type exp
exp :: Floating a => a -> a
Prelude>

Prelude>  :info exp
class Fractional a => Floating a where
  ...
  exp :: a -> a
  ...
  -- Defined in `GHC.Float'
Prelude>  

Prelude>  let e = exp 1
e :: Floating a => a
Prelude>

= denotes definition, like it does in mathematics; e.g., e "is defined as" exp 1.

Prelude>  e
2.718281828459045
it :: Floating a => a
Prelude>   

F. CONSTANTS

Prelude>  pi
3.141592653589793
it :: Floating a => a
Prelude>

Prelude>  :type pi
pi :: Floating a => a
Prelude>

Prelude>  :info pi
class Fractional a => Floating a where
  pi :: a
  ...
           -- Defined in `GHC.Float'
Prelude>    

G. MOD

mod is the standard modulo function.

Prelude>  :type mod
mod :: Integral a => a -> a -> a
Prelude>

Prelude>  :info mod
class (Real a, Enum a) => Integral a where
  ...
  mod :: a -> a -> a
  ...
  -- Defined in `GHC.Real'
infixl 7 'mod'
Prelude>  

H. PRODUCT

product is the standard list element product function.

Prelude>  :type product
product :: (Num a, Foldable t) => t a -> a
Prelude>

Prelude>  :info product
class Foldable (t :: * -> *) where
  ...
  product :: Num a => t a -> a
  ...
   -- Defined in `Data.Foldable'
Prelude>  

product is often used to compute factorial as shown below:

Prelude> let prodFact n = product [1..n]
Prelude>

Prelude> prodFact 3    -- 1*2*3 = 6
6
Prelude> 

III.  HASKELL BOOLEAN ALGEBRA

A. BOOLEAN and &&

Prelude>  :type (&&)
(&&) :: Bool -> Bool -> Bool
Prelude>

Prelude>  :info (&&)
(&&) :: Bool -> Bool -> Bool -- Defined in ‘GHC.Classes’
infixr 3 &&
Prelude> 

Prelude>  :type and
and :: [Bool] -> Bool
Prelude>

Prelude>  :info and
and :: [Bool] -> Bool -- Defined in `GHC.List'
Prelude>

Prelude>  and [True, False]
False
it :: Bool
Prelude>

Prelude>  and [True, True]
True
it :: Bool
Prelude>

Prelude> True && False
False
it :: Bool
Prelude>

Prelude> True && True
True
it :: Bool
Prelude> 

True  && b = b
False && _ = False

B. BOOLEAN or ||

Prelude>  :type (||)
(||) :: Bool -> Bool -> Bool
Prelude> 

Prelude>  :info (||)
(||) :: Bool -> Bool -> Bool -- Defined in ‘GHC.Classes’
infixr 2 ||
Prelude>

Prelude>  :type or
or :: [Bool] -> Bool
Prelude>

Prelude>  :info or
or :: [Bool] -> Bool  -- Defined in `GHC.List'
Prelude>

Prelude>  or [True, False]
True
it :: Bool
Prelude>

Prelude>  or [False, False]
False
it :: Bool
Prelude>

Prelude>  or [True, True]
True
it :: Bool
Prelude>  

Prelude> True || False
True
it :: Bool
Prelude> 

C. BOOLEAN NEGATE not

Prelude> not True
False
it :: Bool
Prelude> 

Prelude>  :type not
not :: Bool -> Bool
Prelude>

Prelude>  :info not
not :: Bool -> Bool -- Defined in `GHC.Classes'
Prelude>  

Prelude> not (False && False)
it :: Bool
True
Prelude>

Prelude> not (True && True)
False
it :: Bool
Prelude>

Haskell does not treat zero as False and non-zero as True.

IV.  HASKELL COMPARISON OPERATORS

A. LESS THAN

Prelude> 8 < 9
True
it :: Bool
Prelude> 

Prelude>  :type (<)
(<) :: Ord a => a -> a -> Bool
Prelude>

Prelude>  :info <
class Eq a => Ord a where
  ...
  (<) :: a -> a -> Bool
  ...
  -- Defined in `GHC.Classes'
infix 4 <
Prelude>  

B. LESS THAN OR EQUAL TO

Prelude> 9 <= 10
True
it :: Bool
Prelude> 

Prelude>  :type (<=)
(<=) :: Ord a => a -> a -> Bool
Prelude>

Prelude>  :info <=
class Eq a => Ord a where
  ...
  (<=) :: a -> a -> Bool
  ...
  -- Defined in `GHC.Classes'
infix 4 <=
Prelude> 

C. GREATER THAN

Prelude> 10 > 6
True
it :: Bool
Prelude> 

Prelude>  :type (>)
(>) :: Ord a => a -> a -> Bool
Prelude>

Prelude>  :info >
class Eq a => Ord a where
  ...
  (>) :: a -> a -> Bool
  ...
  -- Defined in `GHC.Classes'
infix 4 >
Prelude> 

D. GREATER THAN OR EQUAL TO

Prelude> 3 >= 3 
True
it :: Bool
Prelude> 

Prelude>  :type (>=)
(>=) :: Ord a => a -> a -> Bool
Prelude>

Prelude>  :info >=
class Eq a => Ord a where
  ...
  (>=) :: a -> a -> Bool
  ...
  -- Defined in `GHC.Classes'
infix 4 >=
Prelude>  

E. IDENTITY

The == operator requires its arguments to have the same type.

Prelude> 8 == 8
True
it :: Bool
Prelude> 

Prelude>  :type (==)
(==) :: Eq a => a -> a -> Bool
Prelude>

Prelude>  :info ==
class Eq a where
  (==) :: a -> a -> Bool
  ...
  -- Defined in `GHC.Classes'
infix 4 ==
Prelude>  

F. NOT EQUAL TO

Prelude> 8 /= 9
True
it :: Bool
Prelude> 

Prelude>  :type (/=)
(/=) :: Eq a => a -> a -> Bool
Prelude>

Prelude>  :info /=
class Eq a where
  ...
  (/=) :: a -> a -> Bool
  -- Defined in `GHC.Classes'
infix 4 /=
Prelude>  

G. COMPARE

Prelude>  compare 12 2
GT
it :: Ordering
Prelude>  

Prelude>  compare 12 2 == GT
True
it :: Bool
Prelude> 

Prelude>  :type compare
compare :: Ord a => a -> a -> Ordering
Prelude>

Prelude>  :info compare
class Eq a => Ord a where
  compare :: a -> a -> Ordering
  ...
  -- Defined in `GHC.Classes'
Prelude> 

V. NO HASKELL NULL OR VOID

There is no null and no void in Haskell. Every Haskell name has to have a value, even if it is a placeholder. The standard Haskell placeholder value is the empty tuple, (), also known as “unit”. The type of () is also ().

However, the following function named null, defined in the Prelude, tells you whether or not a list is empty.

Prelude> null []
True
it :: Bool
Prelude> 

Prelude>  :type null
null :: [a] -> Bool
Prelude>

Prelude>  :info null
null :: [a] -> Bool -- Defined in `GHC.List'
Prelude>

Prelude>  :info null []
null :: [a] -> Bool -- Defined in `GHC.List'
data [] a = [] | a : [a] -- Defined in `GHC.Types'
instance Eq a => Eq [a] -- Defined in `GHC.Classes'
instance Monad [] -- Defined in `GHC.Base'
instance Functor [] -- Defined in `GHC.Base'
instance Ord a => Ord [a] -- Defined in `GHC.Classes'
instance Read a => Read [a] -- Defined in `GHC.Read'
instance Show a => Show [a] -- Defined in `GHC.Show'
Prelude>  

Prelude> null [1,2,3,4]
False
it :: Bool
Prelude>

A. MAYBE

The Prelude defines a type named Maybe. We can use this to represent a value that could be either present or missing; e.g., a field in a database row that could be null.

Prelude>  :module +Data.Maybe
Prelude>

Prelude>  :module +GHC.Show
Prelude>

Prelude>  :type Maybe
Maybe :: b -> (a -> b) -> Maybe a -> b
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>  

B. NOTHING

Prelude>  Nothing
Nothing
it :: Maybe a
Prelude>

Prelude>  :type Nothing
Nothing :: Maybe a
Prelude>

Prelude>  :info Nothing
data Maybe a = Nothing | ... -- Defined in `Data.Maybe'
Prelude>  

C. JUST

Prelude>  import Data.Maybe
Prelude>

Prelude>  :type Just
Just :: a -> Maybe a
Prelude>

Prelude>  :info Just
data Maybe a = ... | Just a -- Defined in `Data.Maybe'
Prelude>

VI. HASKELL LET

We can use the let keyword to define a name right in GHCi. Doing let a = 1 inside GHCi is the equivalent of writing a = 1 in a script and then loading it.

VII. HASKELL PRED

The pred, predecessor function, takes anything that has a defined predecessor and returns that predecessor.

Prelude> :type pred
pred :: Num a => a -> a
Prelude> 

Prelude>  :info pred
class Enum a where
  ...
  pred :: a -> a
  ...
  -- Defined in `GHC.Enum'
Prelude>  

The above pred signature says the function pred "has type" Num, and  a is an instance of the Num typeclass. 

Prelude>  let pred x = x-1
pred :: Num a => a -> a
Prelude>  

Prelude> pred 1
0
it :: Num a => a
Prelude>

Prelude> pred 4.5
3.5
it :: Fractional a => a
Prelude>

VIII. HASKELL SUCC

The succ, successor function, takes anything that has a defined successor and returns that successor.

Prelude> :type succ
succ :: Enum a => a -> a
Prelude> 

Prelude>  :info succ
class Enum a where
  succ :: a -> a
  ...
  -- Defined in `GHC.Enum'
Prelude>  

The above succ signature says the function succ "has type" Enum, and  a is an instance of the Enum enumeration class.  Enum starts with a capital letter, in Haskell, this means Enum is a type class. a is written with a lower case letter, in Haskell, this means a can be any type. Therefore, a can be any type of the Enum type class.

Prelude>  let succ x = x + 1
succ :: Num a => a -> a
Prelude>

Prelude> succ 1
2
it :: Num a => a
Prelude>

Prelude> succ 3.5
4.5
it :: Fractional a => a
Prelude>

IX. FORMATTING NUMBERS

A. DECIMALS

Prelude>  :module Numeric  -- Functions for reading and showing RealFloat-like kind of values.
Prelude>

Prelude>  let formatFloatN floatNum numOfDecimals = showFFloat (Just numOfDecimals) floatNum ""
formatFloatN :: RealFloat a => a -> Int -> String
Prelude>

Prelude>  :type formatFloatN
formatFloatN :: RealFloat a => a -> Int -> String
Prelude>

Prelude>  formatFloatN (1.33 / 3) 2
"0.44"
it :: String
Prelude> 

B. COMMAS

First, "copy paste" the following module into your text editor and "save as" FormatDecimal.hs to your working directory:

-- Haskell FormatDecimal Module

module FormatDecimal where

import Data.Graph.Inductive.Query.Monad (mapFst)
import Text.Printf
import Data.List

formatDecimal d
    | d < 0.0   = "-" ++ (formatPositiveDecimal (-d)) 
    | otherwise = formatPositiveDecimal d 
    where formatPositiveDecimal = uncurry (++) . mapFst addCommas . span (/= '.') . printf "%0.2f" 
          addCommas = reverse . concat . intersperse "," . unfoldr splitIntoBlocksOfThree . reverse 
          splitIntoBlocksOfThree l = case splitAt 3 l of ([], _) -> Nothing; p -> Just p

Second, if you have not done so already, change your GHCi directory to your working directory:

Prelude>  :cd C:\Users\Tinnel\Haskell2024\newProjects\
Prelude>

Third, load the FormatDecimal module into GHCi:

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

Fourth, call the formatDecimal function in GHCi:

Prelude>  formatDecimal 121212121212.125678
Loading package array-0.5.0.0 ... linking ... done.
Loading package deepseq-1.3.0.2 ... linking ... done.
Loading package containers-0.5.5.1 ... linking ... done.
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package mtl-2.1.3.1 ... linking ... done.
Loading package fgl-5.5.0.1 ... linking ... done.
"121,212,121,212.13"
it :: [Char]
Prelude>  

X. CONCLUSION

You have received an introduction to Haskell math, enjoy.

XI. 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.