<NME> Reader.ipynb
<BEF> {
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The Reader Monad\n",
    "\n",
    "The Reader monad pass the state you want to share between functions. Functions may read that state, but can't change it. The reader monad lets us access shared immutable state within a monadic context. In the Reader monad this shared state is called the environment.\n",
    "\n",
    "The Reader is just a fancy name for a wrapped function, so this monad could also be called the Function monad, or perhaps the Callable monad. Reader is all about composing wrapped functions.\n",
    "\n",
    "This [IPython](http://ipython.org) notebook uses the [OSlash](https://github.com/dbrattli/OSlash) library for Python 3.4, aka Ø. You can install Ø using:\n",
    "\n",
    "```bash\n",
    "> pip3 install oslash\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from oslash import Reader\n",
    "unit = Reader.unit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A Reader wraps a function, so it takes a callable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "r = Reader(lambda name: \"Hi %s!\" % name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Python you can call this wrapped function as any other callable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hi Dag!'"
      ]
     },
     "execution_count": 108,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r(\"Dag\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Unit\n",
    "\n",
    "Unit is a constructor that takes a value and returns a Reader that ignores the environment. That is it ignores any value that is passed to the Reader when it's called:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "42"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r = unit(42)\n",
    "r(\"Ignored\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Bind\n",
    "\n",
    "You can bind a Reader to a monadic function using the pipe `|` operator (The bind operator is called `>>=` in Haskell). A monadic function is a function that takes a value and returns a monad, and in this case it returns a new Reader monad:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Dag!'"
      ]
     },
     "execution_count": 110,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = a | (lambda x: unit(x.replace(\"Hi\", \"Hello\")))\n",
    "b(\"Dag\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Applicative\n",
    "\n",
    "Apply (`*`) is a beefed up `map`. It takes a Reader that has a function in it and another Reader, and extracts that function from the first Reader and then maps it over the second one (basically composes the two functions)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Dag!'"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r = Reader(lambda name: \"Hi %s!\" % name)\n",
    "\n",
    "a =  Reader(lambda x: unit(x + \"!\")) * r\n",
    "a(\"Dag\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MonadReader\n",
    "\n",
    "The MonadReader class provides a number of convenience functions that are very useful when working with a Reader monad."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from oslash import MonadReader\n",
    "asks = MonadReader.asks\n",
    "ask = MonadReader.ask"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ask\n",
    "\n",
    "Provides a way to easily access the environment. Ask lets us read the environment and then play with it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hi Dag!'"
      ]
     },
     "execution_count": 113,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r = ask() | (lambda x: unit(\"Hi %s!\" % x))\n",
    "r(\"Dag\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Asks\n",
    "\n",
    "Given a function it returns a Reader which evaluates that function and returns the result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r = asks(len)\n",
    "r(\"banana\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A Longer Example\n",
    "\n",
    "This example has been translated to Python from https://gist.github.com/egonSchiele/5752172."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, dag! Bye, dag!\n"
     ]
    }
   ],
   "source": [
    "from oslash import Reader, MonadReader\n",
    "ask = MonadReader.ask\n",
    " \n",
    "def hello():\n",
    "    return ask() | (lambda name: \n",
    "           unit(\"Hello, \" + name + \"!\"))\n",
    " \n",
    "def bye():\n",
    "    return ask() | (lambda name: \n",
    "           unit(\"Bye, \" + name + \"!\"))\n",
    " \n",
    "def convo():\n",
    "    return hello() | (lambda c1: \n",
    "           bye() | (lambda c2: \n",
    "           unit(\"%s %s\" % (c1, c2))))\n",
    "\n",
    "r = convo()\n",
    "print(r(\"dag\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_That is it, that's the Reader monad for you in Python and Ø!_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}

<MSG> Bugfix

<DFF> @@ -119,7 +119,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 110,
+   "execution_count": 117,
    "metadata": {
     "collapsed": false
    },
@@ -127,16 +127,18 @@
     {
      "data": {
       "text/plain": [
-       "'Dag!'"
+       "'Hello Dag!'"
       ]
      },
-     "execution_count": 110,
+     "execution_count": 117,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "b = a | (lambda x: unit(x.replace(\"Hi\", \"Hello\")))\n",
+    "r = Reader(lambda name: \"Hi %s!\" % name)\n",
+    "\n",
+    "b = r | (lambda x: unit(x.replace(\"Hi\", \"Hello\")))\n",
     "b(\"Dag\")"
    ]
   },
@@ -151,7 +153,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 111,
+   "execution_count": 122,
    "metadata": {
     "collapsed": false
    },
@@ -159,10 +161,10 @@
     {
      "data": {
       "text/plain": [
-       "'Dag!'"
+       "'Hi Dag!!!!'"
       ]
      },
-     "execution_count": 111,
+     "execution_count": 122,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -170,7 +172,7 @@
    "source": [
     "r = Reader(lambda name: \"Hi %s!\" % name)\n",
     "\n",
-    "a =  Reader(lambda x: unit(x + \"!\")) * r\n",
+    "a = Reader.pure(lambda x: x + \"!!!\") * r\n",
     "a(\"Dag\")"
    ]
   },

Bugfix