<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <script src="logger.js"></script>
    <script src="helpers.js"></script>
    <script src="Maybe.js"></script>
    <script src="script.js"></script>
  </body>

</html>
(function(e){const n=console.log;const o=document.querySelector(e.selector);const t=e.globalName||"logger";i(o,{background:e.colors.background,color:e.colors.foreground,fontFamily:"monospace"});function r(e){return{}.toString.call(e)==="[object Array]"}function l(e){return{}.toString.call(e)==="[object Object]"}function c(e){return e&&typeof e.inspect==="function"}function i(e,n){Object.assign(e.style,n);return e}function u(e){const n=document.createElement("span");if(e.tagName){n.appendChild(e)}else{n.innerText=e}return n}function a(n){const o=document.createElement("span");o.appendChild(u("{ "));Object.keys(n).reduce(function(o,t,r,l){o.appendChild(i(u(t+": "),{color:e.colors.key}));o.appendChild(s(n[t]));if(r<l.length-1){o.appendChild(u(", "))}return o},o);o.appendChild(u(" }"));return o}function d(e){const n=document.createElement("span");n.appendChild(u("[ "));e.reduce(function(n,o,t){n.appendChild(s(o));if(t<e.length-1){n.appendChild(u(", "))}return n},n);n.appendChild(u(" ]"));return n}function s(n){if(c(n)){return s(n.inspect())}else if(typeof n==="number"){return i(u(n),{color:e.colors.number})}else if(typeof n==="string"){return i(u("'"+n+"'"),{color:e.colors.string})}else if(typeof n==="boolean"){return i(u(n),{color:e.colors.boolean})}else if(typeof n==="function"){return i(u("Function"))}else if(r(n)){return u(d(n))}else if(l(n)){return u(a(n))}else if(n===undefined){return i(u("undefined"),{fontStyle:"italic",color:e.colors.boolean})}else if(n===null){return i(u("null"),{fontStyle:"italic",color:e.colors.boolean})}}function f(n,o){const t=document.createElement("dl");const r=document.createElement("dt");const l=document.createElement("dd");i(t,{padding:"0",margin:"0",marginBottom:"0.6em",fontSize:e.fontSize});i(r,{color:e.colors.label,fontWeight:600,fontSize:"1.1em",margin:"0"});i(l,{padding:"0 0.75em",margin:"0"});r.innerText=n+":";l.appendChild(s(o));t.appendChild(r);t.appendChild(l);return t}function p(n){return i(u(s(n)),{display:"block",margin:"0",marginBottom:"0.6em",fontSize:e.fontSize})}function g(){o.appendChild(arguments.length>1?f(arguments[0],arguments[1]):p(arguments[0]));n.apply(console,arguments)}e.root[t]=g;console.log=g})({
  globalName:"log",
  root:window,
  selector:"body",
  fontSize:"28px",
  colors: {
    background:"transparent",
    foreground:"gray",
    label:"blue",
    nil:"green",
    number:"violet",
    string:"red",
    key:"blue",
    "boolean":"green"
  }
});
(function(root) {
  
  // compose : ((b -> c), (a -> b)) -> a -> c
  const compose =
    (f, g) => x => f(g(x))
  
  // isValid : a -> Boolean
  const isValid =
    Number.isFinite
  
  // stringify : a -> String
  const stringify =
    JSON.stringify
 
  root.helpers = {
    compose,
    isValid,
    stringify
  }
})(window)
const { compose, isValid, stringify } = helpers
const { maybe, mapMaybe, optionMaybe } = Maybe

// maybeValid : * -> Maybe Number
const maybeValid =
  maybe(isValid)

// add10 : Number -> Number
const add10 =
  num =>  num + 10

// square : Number -> Number
const square =
  num => Math.pow(num, 2)

// doMath : Number -> Number
const doMath =
  compose(square, add10)

// safeMath : a -> Maybe Number
const safeMath =
  compose(mapMaybe(doMath), maybeValid)

// safeStringMath : a -> Maybe String
const safeStringMath =
  compose(mapMaybe(stringify), safeMath)

// stringMath : a -> String
const stringMath =
  compose(optionMaybe('None'), safeStringMath)

log('doMath with a Number', doMath(0))
log('doMath with a String', doMath('kitty cat'))

log('maybeValid with a Number (Just)', maybeValid(0))
log('maybeValid with a NaN (Nothing)', maybeValid(NaN))

log('safeMath with a Number (Just)', safeMath(0))
log('safeMath with a NaN (Nothing)', safeMath(NaN))

log('safeStringMath with a Number (Just)', safeStringMath(0))
log('safeStringMath with a NaN (Nothing)', safeStringMath(NaN))

log('stringMath with a Number (Just)', stringMath(0))
log('stringMath with a NaN (Nothing)', stringMath(NaN))
(function(root) {
  // maybe : (* -> Boolean) -> * -> Maybe a
  const maybe =
    pred => x => pred(x) ? [ x ] : []
  
  // mapMaybe : (a -> b) -> Maybe a -> Maybe b
  const mapMaybe =
    fn => m => m.map(fn)
  
  // optionMaybe : a -> Maybe a -> a
  const optionMaybe =
    def => m => m.length ? m[0] : def

  root.Maybe = {
    mapMaybe,
    maybe,
    optionMaybe
  }
})(window)