Tuesday, January 29, 2013

HASKELL MATH INTRODUCTION

HASKELL MATH INTRODUCTION
REVISED: Friday, October 18, 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" FormatCommas.hs to your working directory:

-- Haskell FormatCommas Module

module FormatCommas 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 FormatCommas module into GHCi:

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

Fourth, call the formatCommas function in GHCi:

Prelude>  formatCommas 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.

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.