Monday, January 22, 2024

HASKELL LOGARITHMS

HASKELL LOGARITHMS

REVISED: Saturday, Febuary 3, 2024


1. INTRODUCTION

As mentioned in previous tutorials, 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 where 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>

Haskell provides various approaches to solving logarithmic equations, depending on the complexity and desired accuracy.

2. OVERVIEW
 
The following are three common methods which can be used to solve logarithmic equations.

2.1. Using Logarithmic Properties:

This method exploits the logarithmic properties, such as product rule, quotient rule, and power rule, to manipulate the equation into a form where the unknown variable can be isolated.

2.2. Using Numerical Methods:

For more complex equations or when analytical solutions are difficult, numerical methods like bisection method or Newton-Raphson method can be applied. These methods iteratively refine an initial guess until the desired accuracy is reached.

2.3. Using Symbolic Libraries:

Libraries like "symbolic" or "polyglot" allow symbolic manipulation of expressions, enabling you to solve equations for exact solutions without numerical approximations.

3. EXAMPLES

3.1. Using Logarithmic Properties:

import Prelude hiding ((**))

-- Function to apply a logarithmic property
applyProperty :: (Double -> Double) -> Double -> Double -> Double
applyProperty f x y = f (x * y)

-- Example equation: 3^x = 81
solveEquation :: Double -> Double
solveEquation x =
  let
    leftSide = exp (x * logBase 10 3)  -- Apply power rule
    rightSide = 81
  in
    logBase 10 rightSide / logBase 10 3  -- Apply quotient rule

main :: IO ()
main = do
  let solution = solveEquation 1.0  -- Starting with a guess of 1.0
  print solution

Explanation:

Import Prelude: This module provides basic functions and types, including logBase and exp for logarithms and exponents.

applyProperty: This function demonstrates how to apply a logarithmic property to two numbers. It's not used directly in this example, but it illustrates the concept.

solveEquation: Takes a guess for x as input. Calculates the left side of the equation using exp (x * logBase 10 3), applying the power rule of logarithms. Compares the left side to the right side (81). Applies the quotient rule of logarithms to isolate x and return its value.

main: Calls solveEquation with an initial guess of 1.0. Prints the solution, which should be 4.0 (since 3^4 = 81).

Key Points:

The program uses logBase 10 for base-10 logarithms. You can use log for natural logarithms (base e).

It assumes a simple equation with known values, but this approach can be applied to more complex equations as well.

In more sophisticated cases, you might need to use numerical methods for solving equations or finding roots. 

3.2. Using the Bisection Method:

import Prelude hiding ((**))

-- Function representing the logarithmic equation
eqn :: Double -> Double
eqn x = log x - 2  -- Example: log(x) = 2

-- Bisection method
bisection :: Double -> Double -> Double -> Double -> Double
bisection a b tolerance iterations =
  let mid = (a + b) / 2
      fmid = eqn mid
      error = abs (b - a)
  in
    if error < tolerance || iterations == 0
      then mid
      else if fmid * eqn a < 0
          then bisection a mid tolerance (iterations - 1)
          else bisection mid b tolerance (iterations - 1)

main :: IO ()
main = do
  let solution = bisection 1.0 10.0 1e-6 100  -- Initial interval, tolerance, max iterations
  print solution

Explanation:

Import Prelude: Provides basic functions and types, including log for logarithms.

eqn: Represents the logarithmic equation to be solved.

bisection: Implements the bisection algorithm: Takes the initial interval (a, b), tolerance, and maximum iterations as input. Recursively halves the interval based on the sign of fmid * eqn a. Checks for convergence based on error or maximum iterations.

main: Calls bisection with an initial interval of (1.0, 10.0), tolerance of 1e-6, and maximum iterations of 100. Prints the solution, which should be approximately 7.389065 (since log(7.389065) ≈ 2).

Key Points:

The bisection method is generally more robust than the Newton-Raphson method, as it doesn't require calculating a derivative and can handle a wider range of equations. It converges slower than Newton-Raphson but is guaranteed to converge if the equation has a root within the initial interval. You can adjust the initial interval, tolerance, and maximum iterations to suit your specific problem.

3.3. Newton-Raphson Method:

import Prelude hiding ((**))

-- Function representing the logarithmic equation
eqn :: Double -> Double
eqn x = log x - 2  -- Example: log(x) = 2

-- Derivative of the equation
eqnDeriv :: Double -> Double
eqnDeriv x = 1 / x

-- Newton-Raphson method
newtonRaphson :: Double -> Double -> Double -> Double
newtonRaphson x0 tolerance iterations =
  let x1 = x0 - eqn x0 / eqnDeriv x0
      error = abs (x1 - x0)
  in
    if error < tolerance || iterations == 0
      then x1
      else newtonRaphson x1 tolerance (iterations - 1)

main :: IO ()
main = do
  let solution = newtonRaphson 1.0 1e-6 100  -- Initial guess, tolerance, max iterations
  print solution

Explanation:

Import Prelude: Provides basic functions and types, including log for logarithms.

eqn: Represents the logarithmic equation to be solved.

eqnDeriv: Calculates the derivative of the equation, needed for the Newton-Raphson method.

newtonRaphson: Implements the Newton-Raphson algorithm: Takes the initial guess, tolerance, and maximum iterations as input. Recursively updates the guess using the formula x1 = x0 - eqn x0 / eqnDeriv x0. Checks for convergence based on error or maximum iterations.

main: Calls newtonRaphson with an initial guess of 1.0, tolerance of 1e-6, and maximum iterations of 100. Prints the solution, which should be approximately 7.389056 (since log(7.389056) ≈ 2).

Key Points:

You can adjust the equation (eqn), derivative (eqnDeriv), tolerance, and maximum iterations to solve different logarithmic equations.

The method might not converge for all equations or initial guesses.

Other numerical methods, like the bisection method, can also be implemented in Haskell using similar techniques.

3.4. Symbolic Libraries:

While Haskell doesn't have a library named "symbolic" specifically for symbolic computation, it does have several libraries that offer symbolic capabilities:

3.4.1. SBV (Satisfiability Modulo Theories):

Provides symbolic reasoning for expressions and constraints. Can be used to solve equations, prove theorems, and model systems.

Example:

import Data.SBV

solveEquation :: SymExpr Solver -> IO ()
solveEquation expr = do
    model <- getModel expr
    print (eval model expr)

main :: IO ()
main = do
    let x = free "x" :: SymExpr Solver
    solveEquation (log x .== 2)

3.4.2. Grisette:

Offers symbolic evaluation of Haskell expressions. Useful for constraint solving, testing, and analysis.

Example:

import Data.Grisette.Crucible.Core

solveEquation :: Expr -> IO ()
solveEquation expr = do
    result <- evaluate expr
    print result

main :: IO ()
main = do
    let x = mkVar "x" :: Expr
    solveEquation (log x .== 2)

3.4.3. Polyglot:

A frontend for various symbolic backends (e.g., Mathematica, SymPy).  Allows interaction with these systems from Haskell.

Example:

import Language.Polyglot

solveEquation :: String -> IO ()
solveEquation expr = do
    result <- runSession $ runMathematica $ expr
    print result

main :: IO ()
main = do
    solveEquation "Solve[Log[x] == 2, x]"

Choosing the right library depends on your specific requirements and the complexity of the symbolic tasks you need to perform.

4. CONCLUSION

Choose the method based on the equation's complexity and desired accuracy.

Numerical methods may require fine-tuning initial guess and tolerance parameters.

Symbolic libraries offer exact solutions but might not be efficient for all cases.

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

Saturday, November 18, 2023

HASKELL AI DEVELOPMENT

HASKELL AI DEVELOPMENT

REVISED: Wednesday, January 24, 2024


1. INTRODUCTION

Haskell, a purely functional programming language, holds significant relevance in the realm of artificial intelligence (AI) due to its unique characteristics that align well with AI principles and applications.

2. OVERVIEW

Here's a closer look at the key reasons why Haskell is considered a valuable tool for AI development:

Type System and Safety: Haskell's strong static typing system ensures that programs are rigorously checked for type errors at compile time, significantly reducing runtime errors and enhancing code reliability. This is crucial for AI applications, where complex algorithms and data structures require a high degree of precision.

Purity and Modularity: Haskell's pure functional programming paradigm promotes modularity and composability, making it easier to break down complex AI problems into smaller, well-defined functions. This modular approach simplifies reasoning about code, improves maintainability, and facilitates collaboration among developers.

Abstraction and Expressiveness: Haskell's expressive typing and higher-order functions allow for the creation of concise and abstract code, capturing the essence of AI problems without getting bogged down in implementation details. This abstraction leads to more maintainable and adaptable code.

Laziness and Efficiency: Haskell's lazy evaluation mechanism ensures that expressions are evaluated only when their values are needed, leading to efficient memory usage and performance optimization. This is particularly beneficial for AI applications that deal with large datasets and computationally intensive algorithms.

Concurrency and Parallelism: Haskell's support for concurrency and parallelism makes it well-suited for developing AI algorithms that can utilize multicore processors and distributed computing systems. This is essential for handling the growing demands of real-time AI applications.

Domain-Specific Languages (DSLs): Haskell's ability to define DSLs enables AI developers to create specialized languages tailored to specific AI domains, such as machine learning, natural language processing, and robotics. This customization enhances the expressiveness and efficiency of AI code.

Research and Innovation: Haskell's active research community and growing adoption in academia contribute to the development of new tools, libraries, and techniques specifically designed for AI applications. This fosters innovation and continuous improvement in AI development using Haskell.

3. CONCLUSION

While Haskell may not be as widely used in industry as other languages like Python or R for AI development, its unique strengths and the growing interest in functional programming make it a promising choice for tackling the challenges of modern AI. As AI continues to evolve, Haskell's potential to contribute to the development of robust, reliable, and efficient AI systems is likely to grow.

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

Thursday, June 1, 2023

HASKELL IS A TOOL

HASKELL MONAD OVERVIEW

REVISED: Friday, February 9, 2024


1. INTRODUCTION

Haskell is a powerful programming language that is well-suited for a variety of tasks.

2. OVERVIEW

For example Haskell is well-suited for tasks including:

Functional programming: Haskell is a purely functional language, which means that it does not have side effects. This makes it ideal for tasks that require a high degree of mathematical precision, such as symbolic computation and artificial intelligence.

Concurrent programming: Haskell has built-in support for concurrent programming, which makes it ideal for tasks that require multiple threads of execution, such as web servers and distributed systems.

Data analysis: Haskell has a rich set of libraries for data analysis, making it ideal for tasks such as data mining and machine learning.

However, Haskell is not without its drawbacks. It can be difficult to learn, and it is not as widely used as other programming languages, such as Java and Python. This can make it difficult to find help and resources when you are using Haskell.

Here are some tasks that are better suited for other programming languages:

Web development: Haskell is not a good choice for web development. There are few web frameworks available for Haskell, and the language's performance can be a bottleneck for high-traffic websites.

Graphics programming: Haskell is not a good choice for graphics programming. The language does not have built-in support for graphics libraries, and its performance can be a bottleneck for graphics-intensive applications.

Game development: Haskell is not a good choice for game development. The language does not have built-in support for game engines, and its performance can be a bottleneck for games with complex graphics and physics.

3. CONCLUSION

Overall, Haskell is a powerful programming language that is well-suited for a variety of tasks. However, it is important to choose the right tool for the job. If you are working on a task that requires a high degree of mathematical precision, concurrent programming, or data analysis, then Haskell is a good choice. However, if you are working on a task that is better suited for a different programming language, then you should choose that language instead.

4. 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, May 30, 2023

HASKELL MONAD OVERVIEW

HASKELL MONAD OVERVIEW

REVISED: Wednesday, January 24, 2024


1. INTRODUCTION

What is a monad?

A monad is a type constructor M that comes with two operations:

return: This operation takes a value of type a and returns a value of type M a.

bind: This operation takes a value of type M a and a function of type a -> M b, and returns a value of type M b.

The return operation is used to create new monadic values, and the bind operation is used to chain together monadic computations.

2. OVERVIEW

Why use monads?

Monads are a powerful tool for structuring computations. They can be used to represent a wide variety of computational concepts, such as:

State: Monads can be used to represent computations that have side effects, such as reading or writing to a file.

Sequencing: Monads can be used to represent computations that need to be executed in a specific order.

Exceptions: Monads can be used to represent computations that can fail.

Haskell has a number of built-in monads, including:

Maybe: This monad represents computations that can fail.

IO: This monad represents computations that have side effects.

State: This monad represents computations that have mutable state.

3. EXAMPLE

Here is an example of how to use the Maybe monad to represent a computation that can fail:

import Control.Monad

{-
This function returns a Maybe Integer, representing the result of dividing two numbers.
-}

divide :: Integer -> Integer -> Maybe Integer
divide x y =
  if y == 0 then Nothing else Just (x `div` y)

{-
This function uses the `Maybe` monad to print the result of dividing two numbers.
-}

main :: IO ()
main = do
  x <- readLn
  y <- readLn
  result <- divide x y
  case result of
    Just z -> print z
    Nothing -> putStrLn "Division by zero!"

4. CONCLUSION

Monads are a powerful tool for structuring computations in Haskell. They can be used to represent a wide variety of computational concepts, such as state, sequencing, and exceptions.

This tutorial has helped you to learn how to program using Haskell monads.

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

Saturday, May 20, 2023

HASKELL APPLICATIVE STYLE

HASKELL APPLICATIVE STYLE

REVISED: Wednesday, January 24, 2024


1. INTRODUCTION

You are probably familiar with imperative style programming. This tutorial introduces applicative style programming.

In this tutorial, we'll take a look at applicative functors, which are beefed up functors, represented in Haskell by the Applicative typeclass, found in the Control.Applicative module.

The definition of Functor is:

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

GHCi, version 9.8.1: https://www.haskell.org/ghc/  :? for help
ghci> fmap (+1) (Just 1)
Just 2
ghci>

The definition of Applicative is:

class (Functor f) => Applicative f where  
    pure :: a -> f a  
    (<*>) :: f (a -> b) -> f a -> f b  

If we want to make a type constructor part of the Applicative typeclass, it has to be in Functor first. That's why if we know that a type constructor is part of the Applicative typeclass, it's also in Functor, so if we want to we can use fmap on it.

The first method defined above is called pure. Its type declaration is pure :: a -> f a. f plays the role of an applicative functor instance. pure takes a value of any type and returns an applicative functor with that value inside it.

The <*> function has a type declaration of  (<*>) :: f (a -> b) -> f a -> f b. Which should remind you of fmap :: (a -> b) -> f a -> f b.  <*> is a sort of beefed up fmap. However, where fmap takes a function and a functor and applies the function inside the functor, <*> takes a functor that has a function in it and another functor and extracts that function from the first functor and then maps it over the second one.

Haskell Applicative style <*> is left-associative; and <*> is read as "applied to".

2. OVERVIEW

Imperative style tells the computer what to do step-by-step.

Applicative style tells the computer what you want the final result to be, and the computer figures out how to get there. The Applicative type class provides a way to combine functions that take multiple arguments into a single function that takes a single argument. To use the Applicative type class, we first need to create an instance of the type class for our function. An instance of a type class is a definition that tells the compiler how to use the type class with our function. Once we have an instance of the Applicative type class, we can write a function; for example, an addTwoNumbers function in applicative style. The addTwoNumbers function in applicative style would be much more concise and easier to read than the imperative version of the function. It will also be more efficient, because the computer doesn't have to figure out how to get the final result step-by-step.

3. HASKELL EXAMPLES

Following are two Haskell programs.

The first program is written in Imperative Style Haskell.

The second program rewrites the first program into Applicative Style Haskell.

-- First Program:  Imperative Style Haskell Programming

addTwoNumbers :: Int -> Int -> Int
addTwoNumbers x y = x + y

main :: IO ()
main = do
    a <- readLn
    b <- readLn
    print $ addTwoNumbers a b

GHCi, version 9.8.1: https://www.haskell.org/ghc/  :? for help
Prelude> :cd c:\users\tinnel\haskell2024\
Prelude> :l imperative.hs
[1 of 1] Compiling Main             ( imperative.hs, interpreted )
Ok, one module loaded.
*Main> main
1
2
3
*Main>

-- Second Program:  Applicative Style Haskell Computer Programming

import Control.Applicative ()

addTwoNumbers :: Int -> Int -> Maybe Int
addTwoNumbers x y = Just $ x + y

main :: IO ()
main = do
    a <- readLn
    b <- readLn
    print $ addTwoNumbers a b

GHCi, version 9.8.1: https://www.haskell.org/ghc/  :? for help
ghci> :cd c:\users\tinnel\haskell2024\
ghci> :l applicative.hs
[1 of 2] Compiling Main             ( applicative.hs, interpreted )
Ok, one module loaded.
ghci> main
1
2
Just 3
ghci>

The first program is written in imperative style, which means that it tells the computer what to do step-by-step.

The second program is written in applicative style, which means that it tells the computer what to do with the values, rather than how to do it.

The first program works by first reading two numbers from the user, then adding them together, and finally printing the sum.

The second program works by first creating two applicative functors, one for each number, then applying the addTwoNumbers function to the two applicative functors, and finally printing the result.

The main difference between the two programs is that the second program does not specify how the numbers are added together. Instead, it specifies that the numbers should be added together, and leaves it up to the compiler to figure out how to do it. This makes the second program more efficient, because the compiler can optimize the code to use the most efficient method of adding the numbers together.

Maybe is a form of applicative programming. Applicative programming is a style of programming that uses applicative functors to represent computations. Applicative functors are like monads but they do not have side effects. This makes them more efficient, because the compiler can optimize the code to avoid running computations that are not needed.

In the Maybe example, the addTwoNumbers function is an applicative functor. It takes two values as input and returns a value. The Just constructor is used to create an applicative functor with a value, and the Nothing constructor is used to create an applicative functor that is empty.

In this example, we use the readLn function to read two numbers from the user. We then use the addTwoNumbers function to add them. If the addition is successful, the addTwoNumbers function will return a Just containing the result. If the addition is not successful, the addTwoNumbers function will return Nothing.

Finally, we use the print function to print the result of the addition. If the addition was successful, the print function will print the result. If the addition was not successful, the print function will not print anything.

Applicative style is a way of writing Haskell code that makes use of the Applicative type class. The Applicative type class provides a way to combine functions that return values of different types. This can be useful for a variety of tasks, such as composing functions, creating pipelines, and working with data that is represented as a tree.

4. CONCLUSION

In order to use Applicative style, we first need to create an instance of the Applicative type class for our function. This can be done by providing implementations of the following methods:

pure: This method takes a value of any type and returns an Applicative instance that wraps the value.

(<*>): This method takes two Applicative instances and returns an Applicative instance that represents the composition of the two functions.

Once we have created an instance of the Applicative type class for our function, we can use it to write code in Applicative style.

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

Thursday, February 28, 2019

HASKELL COMMAND LINE ARGUMENTS

HASKELL COMMAND LINE ARGUMENTS

REVISED: Wednesday, January 24, 2024


1. INTRODUCTION

Haskell code can be run interactively using GHCi or compiled to an executable using GHC. A command-line is a line of code used to compile a Haskell program using the GHC compiler.

2. OVERVIEW

In Haskell, you can access the command-line arguments with the function getArgs. Import System.Environment to get access to the getArgs function. The getArgs function is not interactive. It will just return the arguments supplied from the command-line, if any were supplied. If you do not supply any arguments at the command-line, then the returned list will be empty as shown in Example 1 below.

Command-line arguments used in GHC are either options or file names. Command-line options begin with -. Command-line options are order-dependent, with arguments being evaluated from left-to-right.

3. EXAMPLE 1

GHCi, version 9.8.1: http://www.haskell.org/ghc/  :? for help
Prelude> :m + System.Environment
Prelude System.Environment> :t getArgs
getArgs :: IO [String]
Prelude System.Environment> do a <- getArgs; print a
[]     -- Empty, because we did not provide any arguments.
Prelude System.Environment> 

4. EXAMPLE 2

This is an example of a program loaded into GHCi and run interactively.

-- Program Name: Interactive.hs

add x y = x + y

total [] = 0
total [x] = x
total (x:xs) = add x (total xs)

compute xs = show $ total $ map read xs

main = do
    putStrLn "Enter first number."
    num1 <- getLine
    putStrLn "Enter second number."
    num2 <- getLine
    putStrLn "Enter last number."
    num3 <- getLine
    putStrLn $ "Total is: " ++ compute [num1, num2, num3]

Prelude> :l Interactive.hs
[1 of 1] Compiling Main             ( Interactive.hs, interpreted )
Ok, one module loaded.
*Main> main
Enter first number.
3
Enter second number.
5
Enter last number.
7
Total is: 15
*Main> 


5. CONCLUSION

A programmer can automate the execution of a program by using command-line arguments in GHC when they compile their Haskell program.


6. 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, January 27, 2017

HASKELL PROOF BY MATHEMATICAL INDUCTION EXAMPLE 1

HASKELL PROOF BY MATHEMATICAL INDUCTION EXAMPLE 1

REVISED: Thursday, February 8, 2024


1. INTRODUCTION

This tutorial introduces using Haskell for proof by Mathematical Induction that the left hand side (LHS) of an infinite equation equals the right hand side (RHS).

Recursive proofs are called induction. Mathematical Induction is a method of formal proof in which a statement is proved for one step in a process, and it is shown that if the statement holds for that step, it holds for the next. The beauty of induction is that it allows a theorem to be proven true where an infinite number of cases exist without exploring each case individually.

Step 1. Show that the statement is true for the initial lowest value of n, which is often n = 1.

Step 2. Assume that the statement is true for n = k.

Step 3. Use the assumption in "Step 2." to prove that the statement is true for n = k + 1.

Then it follows the statement must be true for all values of n.

2. GHCi RUN

GHCi, version 9.8.1: http://www.haskell.org/ghc/  :? for help
Prelude> :l mathematicalInduction
[1 of 1] Compiling Main             ( mathematicalInduction.hs, interpreted )
Ok, modules loaded: Main.
*Main> main

==========================================================

Prove: 2 + 4 + 6 +...+ (2*n) = n*(n+1) by mathematical induction.

Step 1: Show it is True for n = 1.

LHS = 2*n and RHS = n*(n+1).

LHS = 2 and RHS = 2.

LHS = RHS; therefore, it is True for n = 1.

==========================================================

Prove: 2 + 4 + 6 +...+ (2*n) = n*(n+1) by mathematical induction.

Step 2: Assume it is True for n = k.

That is: 2 + 4 + 6 +...+ (2*k) = k*(k+1).

==========================================================

Prove: 2 + 4 + 6 +...+ (2*n) = n*(n+1) by mathematical induction.

Step 3: Show it is True for n = k + 1.

That is: 2 + 4 + 6 +...+ (2 * k) + 2 * (k + 1) = (k + 1) * (k + 2).

LHS = 2 + 4 + 6 + ... + (2 * k) + 2 * (k + 1)
= k * (k + 1) + 2 * (k + 1)
= (k + 1) * ( (k * 1) + (2 * 1))
= (k + 1) * (k + 2) = RHS

Therefore, it is True for n = k + 1.

Therefore, the statement is True for n >= 1.

Q.E.D.

==========================================================

*Main>

3. HASKELL PROGRAM

The Haskell program is as follows:

-- C:\Users\Tinnel\Haskell2024\mathematicalInduction.hs

{-

LHS is left hand side of the = sign.
RHS is right hand side of the = sign.

Prove 2+4+6+...+(2*n) = n * (n+1) by mathematical induction.

Step 1. Show that the statement is true for the initial value of n = 1.

LHS = 2 * 1 = 2
RHS = 1 * (1 + 1) = 2

LHS == RHS

-}

import System.IO
import Data.List

l :: Num t => t
l = 1

r :: Num t => t
r = 1

lHs :: Num a => a -> a
lHs l = 2 * l

rHs :: Num a => a -> a
rHs r = r * (r + 1)

main :: IO ()
main = do {  putStrLn ""  -- putStrLn Has type I/O action.
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "Prove: 2 + 4 + 6 +...+ (2*n) = n*(n+1) by mathematical induction."
           ; putStrLn ""
           ; putStrLn "Step 1: Show it is True for n = 1."
           ; putStrLn ""
           ; putStrLn ("LHS = 2*n and " ++ "RHS = n*(n+1).")
           ; putStrLn ""
           ; let lS = show (lHs l)  -- Type converted from Integer z to String z.
           ; let rS = show (rHs r)  -- Type converted from Integer z to String z.
           ; putStrLn ("LHS = " ++ lS ++ " and RHS = " ++ rS ++ ".")
           ; putStrLn ""
           ; let i = if (lHs l == rHs r) then "True" else "False"
           ; putStrLn ("LHS = RHS; therefore, it is " ++ i ++ " for n = 1.")
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "Prove: 2 + 4 + 6 +...+ (2*n) = n*(n+1) by mathematical induction."
           ; putStrLn ""
           ; putStrLn "Step 2: Assume it is True for n = k."
           ; putStrLn ""
           ; putStrLn "That is: 2 + 4 + 6 +...+ (2*k) = k*(k+1)."
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "Prove: 2 + 4 + 6 +...+ (2*n) = n*(n+1) by mathematical induction."
           ; putStrLn ""
           ; putStrLn "Step 3: Show it is True for n = k + 1."
           ; putStrLn ""
           ; putStrLn "That is: 2 + 4 + 6 +...+ (2 * k) + 2 * (k + 1) = (k + 1) * (k + 2)."
           ; putStrLn ""
           ; putStrLn "LHS = 2 + 4 + 6 + ... + (2 * k) + 2 * (k + 1)"
           ; putStrLn ""
           ; putStrLn "= k * (k + 1) + 2 * (k + 1)"
           ; putStrLn ""
           ; putStrLn "= (k + 1) * ( (k * 1) + (2 * 1))"
           ; putStrLn ""
           ; putStrLn "= (k + 1) * (k + 2) = RHS"
           ; putStrLn ""
           ; putStrLn "Therefore, it is True for n = k + 1."
           ; putStrLn ""
           ; putStrLn "Therefore, the statement is True for n >= 1."
           ; putStrLn ""
           ; putStrLn "Q.E.D."
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
          }
--

4. CONCLUSION

Using Haskell and Mathematical Induction we have proven 2+4+6+...+(2*n) = n * (n+1).

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