Demonstrate in your programming language the following:

Construct a Maybe Monad by writing the 'bind' function and the 'unit' (sometimes known as 'return') function for that Monad (or just use what the language already has implemented)
Make two functions, each which take a number and return a monadic number, e.g. Int -> Maybe Int and Int -> Maybe String
Compose the two functions with bind


A Monad is a single type which encapsulates several other types, eliminating boilerplate code. In practice it acts like a dynamically typed computational sequence, though in many cases the type issues can be resolved at compile time.

A Maybe Monad is a monad which specifically encapsulates the type of an undefined value.

property e : 2.71828182846
 
on run {}
 
    -- Derive safe versions of three simple functions
    set sfReciprocal to safeVersion(reciprocal, notZero)
    set sfRoot to safeVersion(root, isPositive)
    set sfLog to safeVersion(ln, aboveZero)
 
 
    -- Test a composition of these function with a range of invalid and valid arguments
 
    -- (The safe composition returns missing value (without error) for invalid arguments)
 
    map([-2, -1, -0.5, 0, 1 / e, 1, 2, e, 3, 4, 5], safeLogRootReciprocal)
 
    -- 'missing value' is returned by a safe function (and threaded up through the monad) when the input argument is out of range
    --> {missing value, missing value, missing value, missing value, 0.5, 0.0, -0.346573590279, -0.499999999999, -0.549306144333, -0.69314718056, -0.804718956217}
end run
 
 
-- START WITH SOME SIMPLE (UNSAFE) PARTIAL FUNCTIONS:
 
-- Returns ERROR 'Script Error: Can’t divide 1.0 by zero.' if n = 0
on reciprocal(n)
    1 / n
end reciprocal
 
-- Returns ERROR 'error "The result of a numeric operation was too large." number -2702'
-- for all values below 0
on root(n)
    n ^ (1 / 2)
end root
 
-- Returns -1.0E+20 for all values of zero and below
on ln(n)
    (do shell script ("echo 'l(" & (n as string) & ")' | bc -l")) as real
end ln
 
-- DERIVE A SAFE VERSION OF EACH FUNCTION 
-- (SEE on Run() handler)
 
on safeVersion(f, fnSafetyCheck)
    script
        on call(x)
            if sReturn(fnSafetyCheck)'s call(x) then
                sReturn(f)'s call(x)
            else
                missing value
            end if
        end call
    end script
end safeVersion
 
on notZero(n)
    n is not 0
end notZero
 
on isPositive(n)
    n ≥ 0
end isPositive
 
on aboveZero(n)
    n > 0
end aboveZero
 
 
-- DEFINE A FUNCTION WHICH CALLS A COMPOSITION OF THE SAFE VERSIONS
on safeLogRootReciprocal(x)
 
    value of mbCompose([my sfLog, my sfRoot, my sfReciprocal], x)
 
end safeLogRootReciprocal
 
 
-- UNIT/RETURN and BIND functions for the Maybe monad
 
-- Unit / Return for maybe
on maybe(n)
    {isValid:n is not missing value, value:n}
end maybe
 
-- BIND maybe
on mbBind(recMaybe, mfSafe)
    if isValid of recMaybe then
        maybe(mfSafe's call(value of recMaybe))
    else
        recMaybe
    end if
end mbBind
 
-- lift 2nd class function into 1st class wrapper 
-- handler function --> first class script object
on sReturn(f)
    script
        property call : f
    end script
end sReturn
 
-- return a new script in which function g is composed
-- with the f (call()) of the Mf script
-- Mf -> (f -> Mg) -> Mg
on sBind(mf, g)
    script
        on call(x)
            sReturn(g)'s call(mf's call(x))
        end call
    end script
end sBind
 
on mbCompose(lstFunctions, value)
    reduceRight(lstFunctions, mbBind, maybe(value))
end mbCompose
 
-- xs: list, f: function, a: initial accumulator value
-- the arguments available to the function f(a, x, i, l) are
-- v: current accumulator value
-- x: current item in list
-- i: [ 1-based index in list ] optional
-- l: [ a reference to the list itself ] optional
on reduceRight(xs, f, a)
    set mf to sReturn(f)
 
    repeat with i from length of xs to 1 by -1
        set a to mf's call(a, item i of xs, i, xs)
    end repeat
end reduceRight
 
-- [a] -> (a -> b) -> [b]
on map(xs, f)
    set mf to sReturn(f)
    set lst to {}
    set lng to length of xs
    repeat with i from 1 to lng
        set end of lst to mf's call(item i of xs, i, xs)
    end repeat
    return lst
end map
 