Friday, March 27, 2015

HASKELL UNWRAP WRAP INTRODUCTION

HASKELL UNWRAP WRAP INTRODUCTION

REVISED: Thursday, February 8, 2024




Haskell code shows copious amounts of (>>=) pronounced bind.

A Monad is a data structure which implements a Monad type class and satisfies Monad laws. A Monad typeclass defines two functions, the (>>=) and the return that know how to unwrap and wrap data. (>>=) bind is used to unwrap data and apply it to a function which takes the data as input and outputs a monad. (>>=) binds the unwrapped result of the computation on the left to the parameter of the one on the right. return is used to wrap data into a monad's type constructor.

Unwrap is the deconstructor in Haskell; destructing/unwrapping. Wrap is the constructor in Haskell; constructing/wrapping. You can also think of IO as a wrapper. The unwrapping of >>= cancels out the wrapping done by return, leaving only the function.

1. HASKELL WRAP UNWRAP EXAMPLE 1

The identity monad is a monad that does nothing special.

"Copy Paste" the following example into your text editor and "File Save As" WrapUnwrap.hs to your working directory.

module WrapUnwrap where

import Prelude hiding (Maybe(..))
import Control.Monad
import Control.Applicative

data Wrap a = Wrap a deriving Show

instance Functor Wrap where
   fmap f (Wrap a) = Wrap (f a)
   fmap _ Nothing  = Nothing

instance Monad Wrap where           
   return a = Wrap a
   Wrap a >>= f = f a   

instance Applicative Wrap where
   pure = Wrap
   Wrap f <*> Wrap a = Wrap (f a)
   _      <*> _      = Nothing

f :: Num a => a -> Wrap a
f a = Wrap (a + 1)                                -- Returns an incremented wrapped result.

(>>=) f (Wrap a) = f a                          -- unwrap does the exact opposite of wrap.

Load the example into GHCi.

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

As shown below we can take data and wrap it inside a data type and then increment it while it is wrapped in that data type:

Prelude>  f 2
Wrap 3
Prelude>

2. HASKELL UNWRAP WRAP EXAMPLE 2

Consider the following Functor:

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

instance Functor Maybe where
     fmap _ Nothing = Nothing
     fmap f (Just x)   = Just (f x)

If a value is wrapped in Just the fmap calls the function on the unwrapped value, and then rewraps it in Just.

3. HASKELL WRAP EXAMPLE 3

Wrap was easy to see in Example 1. You have to look closer to see wrap in Example 2.

"Copy Paste" the following example into your text editor and "File Save As" JustNothing.hs to your working directory.

module JustNothing where

import Prelude hiding (Maybe(..), lookup)

data Maybe a = Just a | Nothing
  deriving (Eq, Ord, Show)

pie :: [(String, String)]
pie = [("3.141592653589793", "pi")]

lookup key [] = Nothing
lookup key ((k, v) : rest) = if key == k then Just v else lookup key rest

main = do
  putStrLn "Please type pi to 15 decimal places then press Enter."
  word <- getLine  -- Notice getLine has type "getLine :: IO String",  <- is used to unwrap String from the IO action and bind it to word.
  print (lookup word pie)  -- Notice word has type "word :: String", not IO String; therefore, word is not an IO action. 
  if word == "3.141592653589793"
     then return ( "Congratulations!" )
     else main  

Load the example into GHCi:

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

Run the example in GHCi:

Prelude>  main
Please type pi to 15 decimal places then press Enter.
3.141592653589793
Just "pi"
"Congratulations!"
Prelude>

4. SUMMARY

The Haskell programming language is a functional language that makes heavy use of monads. A monad consists of a type constructor M and two operations, bind >>= and return. The return operation takes a value from a plain type and puts it into a monadic container using the constructor. The bind >>= operation performs the reverse process, extracting the original value from the container and passing it to the associated next function in the pipeline. This process effectively creates an action that chooses the next action based on the results of previous actions. Therefore, we should be able to determine our next action based on the results of previous actions. In other words, if x is a computation, and f is a function x >>= f is a computation which runs x, then applies f to its result, getting a computation which it then runs. Monads in Haskell can be thought of as composable computation descriptions.

5. CONCLUSION

Using return and bind we can wrap data and manipulate the wrapped data while keeping that data wrapped. We can also chain functions together that wrap. And in the process of doing these things we learn how monads work.

The unwrap wrap analogy is used to help you acquire intuition regarding how monads work. However, do not take unwrap wrap too literally. Unwrap wrap are mental tools to help you eventually gain the insight needed to think of monads in a computational context not in a unwrap wrap context.

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.




Monday, March 16, 2015

HASKELL LOOKUP TABLE DICTIONARY

HASKELL LOOKUP TABLE DICTIONARY

REVISED: Wednesday, January 24, 2024





1. HASKELL LOOKUP TABLE DICTIONARY

Shown below is a simple easy to understand Haskell lookup table dictionary program:

module Rhymes where

import Prelude hiding (Maybe(..), lookup)

{-
Representing failure using Maybe monad.
Using monads for error handling, also known as exception handling.
Data keyword introduces type Maybe a.
a is a place holder a generic variable.
Just and Nothing are constructors of type Maybe.
-}

data Maybe a = Just a | Nothing
deriving (Eq, Ord, Show)

{-
Lookup Table Dictionary.
A lookup table dictionary relates keys k to values v.
First tuple String is the key k.
Second tuple String is the value v.
-}

rhyme :: [(String, String)]
rhyme = [("fleece", "fleas")
           ,("snow", "go")
          ,("walk", "stalk")
          ,("jaws", "pause")
          ,("fair", "there")
          ,("there", "underwear")
          ,("nose", "toes")
  ,("nice", "lice")
  ,("toes", "blows")
          ,("lice", "ice")]

{-
Function for looking up keys k in Lookup Table Dictionary.
Found value v is returned wrapped in a Just.
You could unwrap Maybe with case statements.

rest is rest of Table.

-}

lookup key [] = Nothing   -- Empty String
lookup key ((k, v) : rest) = if key == k then Just v else lookup key rest

{-
No key match default value.
-}

fromMaybe def (Just a) = a
fromMaybe def Nothing = def

{-
getLine can be thought of as a monadic function of type () -> IO String a monadic action which reads a line of text from the terminal, returning the line of text read as a string. However, its type is IO String. 

putStrLn is a function which happens to be in the IO monad and takes a string as input and displays it on the terminal, also outputting a newline character at the end.

-}

main = do
  putStrLn "Type word to rhyme or type exit then press Enter."
  word <- getLine
  if word == "exit"
      then do 
             return ()
      else do  
              let poetry = lookup word rhyme
             print (fromMaybe "Not found! Update Poetry Lookup Table Dictionary!" poetry)
             main    

2. EXAMPLE PROGRAM OUTPUT

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

Prelude>  main
Type word to rhyme or type exit then press Enter.
fleece
"fleas"
Type word to rhyme or type exit then press Enter.
snow
"go"
Type word to rhyme or type exit then press Enter.
exit
Prelude>

3. EXAMPLE POEM

Mary had a little lamb,
its fleas were white as snow.
And everywhere that Mary went,
its fleas were sure to go.

4. lookup AND Maybe a

As you know a lookup table dictionary is a table which relates keys to values. As shown above the lookup function and the Maybe a features work very well with a lookup table dictionary. I was very impressed with how easy it was to create and use a lookup table dictionary.

Please share with us your comments concerning your successful and unsuccessful lookup table dictionary experiences.

5. CONCLUSION

In this tutorial you have been introduced to the Haskell lookup table dictionary.

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.




Monday, March 9, 2015

HASKELL EQUATIONAL REASONING

HASKELL EQUATIONAL REASONING

REVISED: Thursday, February 8, 2024




Haskell Equational Reasoning.

x + y = y + x                      -- Commutative Laws
x * y = y * x                

(x + y) + z = x + (y + z)     -- Associative Laws.
(x * y)  * z = x * (y * z) 

x * (y + z) = x * y + x * z  -- Distributive Laws.
(x + y) * z = x * z + y * z

I.  HASKELL EQUATIONAL REASONING EXAMPLES 

A. FUNCTION RECEIVES LIST RETURNS NUMBER

1. LIST LENGTH

"Copy, Paste" the following program into your text editor and "File, Save As" eqRes1.hs in your working directory.

eqRes1            :: [a] -> Int
eqRes1 []        = 0
eqRes1 (x:xs) = 1 + eqRes1 xs

Load the eqRes1 program into GHCi and call the function eqRes1 with the list [1,2,3]

GHCi, version 9.8.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude>

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

Prelude>  eqRes1 [1,2,3]
3
Prelude>

[1,2,3] is shorthand notation for 1 : (2 : (3 : [])).

Equational reasoning is replacing equals with equals; i.e., proving one expression is equal to another.

eqRes1 [1,2,3]  -- Total integers in list 1 + 1 + 1 + 0 = 3.
= 1 + eqRes1 [2,3]
= 1 + (1 + eqRes1 [3])
= 1 + (1 + (1 + eqRes1 []))
= 1 + (1 + (1 + 0))
= 3

2. LIST SUM

"Copy, Paste" the following program into your text editor and "File, Save As" eqRes2.hs in your working directory.

eqRes2            :: Num a => [a] -> a
eqRes2        [] = 0
eqRes2 (x:xs) = x + eqRes2 xs

Load the eqRes2 program into GHCi and call the function eqRes2 with the list [1,2,3]

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

Prelude>  eqRes2 [1,2,3]
6
Prelude>

eqRes2 [1,2,3]  -- List sum 1 + 2 + 3 + 0 = 6. 
= 1 + eqRes2 [2,3]
= 1 + (2 + eqRes2 [3])
= 1 + (2 + (3 + eqRes2 []))
= 1 + (2 + (3 + 0))
= 6

B. FUNCTION RECEIVES TWO LISTS RETURNS ONE LIST

1. APPEND

"Copy, Paste" the following program into your text editor and "File, Save As" eqRes3.hs in your working directory.

import qualified Prelude as P

(++)   :: [a] -> [a] -> [a]
[]        ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)

Load the eqRes3 program into GHCi and call the function (++) with the lists [1,2,3] [4,5,6].

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

Prelude>  (++) [1,2,3] [4,5,6]
[1,2,3,4,5,6]
Prelude>  

[1,2,3] ++ [4,5,6]
= 1 : ([2,3] ++ [4,5,6])
= 1 : (2 : ([3] ++ [4,5,6]))
= 1 : (2 : (3 : ([] ++ [4,5,6])))
= 1 : (2 : (3 : [4,5,6]))
= 1 : (2 : [3,4,5,6])
= 1 : [2,3,4,5,6]
= [1,2,3,4,5,6] 

2. ZIP

"Copy, Paste" the following program into your text editor and "File, Save As" eqRes4.hs in your working directory.

import qualified Prelude as P

zip :: [a] -> [b] -> [(a,b)]
zip [] ys = []
zip xs [] = []
zip (x:xs) (y:ys) = (x,y) : zip xs ys

Load the eqRes4 program into GHCi and call the function zip with the lists [1,2,3] [4,5,6,7].

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

Prelude>  zip [1,2,3] [4,5,6,7] 
[(1,4),(2,5),(3,6)]
Prelude> 

zip [1,2,3] [4,5,6,7]  -- Notice, lists are of different lengths.
= (1,4) : zip [2,3] [5,6,7]
= (1,4) : ((2,5) : zip [3] [6,7])
= (1,4) : ((2,5) : ((3,6) : zip [] [7]))  -- zip stops at first empty list.
= (1,4) : ((2,5) : ((3,6) : []))
= (1,4) : ((2,5) : [(3,6)])
= (1,4) : [(2,5), (3,6)]
= [(1,4), (2,5), (3,6)]  -- Output list length is shortest input list.

II. CONCLUSION

In this tutorial you have been introduced to Haskell Equational Reasoning.

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.