diff --git a/polymorphic-optics.ipynb b/polymorphic-optics.ipynb
new file mode 100644
index 0000000..4a460f8
--- /dev/null
+++ b/polymorphic-optics.ipynb
@@ -0,0 +1,1766 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Simple vs Polymorphic Optics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Lens :: forall s t a b. Lens s t a b -> ReifiedLens s t a b"
+ ],
+ "text/plain": [
+ "Lens :: forall s t a b. Lens s t a b -> ReifiedLens s t a b"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {},
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "lens :: forall (f :: * -> *) s a b t. Functor f => (s -> a) -> (s -> b -> t) -> (a -> f b) -> s -> f t"
+ ],
+ "text/plain": [
+ "lens :: forall (f :: * -> *) s a b t. Functor f => (s -> a) -> (s -> b -> t) -> (a -> f b) -> s -> f t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "ename": "",
+ "evalue": "",
+ "output_type": "error",
+ "traceback": [
+ ":1:1: error:\n • Variable not in scope: lens'\n • Perhaps you meant ‘lens’ (imported from Control.Lens)"
+ ]
+ }
+ ],
+ "source": [
+ "{-# LANGUAGE TemplateHaskell #-}\n",
+ "{-# LANGUAGE FlexibleInstances #-}\n",
+ "{-# LANGUAGE FlexibleContexts #-}\n",
+ "{-# LANGUAGE RankNTypes #-}\n",
+ "{-# LANGUAGE ScopedTypeVariables #-}\n",
+ "{-# LANGUAGE TypeApplications #-}\n",
+ "{-# LANGUAGE TypeFamilies #-}\n",
+ "{-# LANGUAGE InstanceSigs #-}\n",
+ "\n",
+ "import Control.Lens\n",
+ "import Numeric.Lens\n",
+ "import Data.Bits.Lens\n",
+ "import Data.Data.Lens\n",
+ "\n",
+ "import Control.Applicative\n",
+ "import Data.Char as C\n",
+ "import qualified Data.Map as M\n",
+ "import qualified Data.Set as S\n",
+ "import qualified Data.Text as T\n",
+ "import qualified Data.List as L\n",
+ "\n",
+ "-- Lens' Person Address\n",
+ "-- Lens' (a, b) a\n",
+ "-- Lens' Pet Name\n",
+ "\n",
+ "-- Lens' s a\n",
+ "-- s is the structure\n",
+ "-- a is the focus\n",
+ "\n",
+ ":t Lens\n",
+ "-- Lens s t a b\n",
+ ":i Lens'\n",
+ "\n",
+ "-- type Lens' s a = Lens s s a a\n",
+ ":t lens"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Polymorphic lenses are type changing focuses"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "_1 :: forall s t a b (f :: * -> *). (Field1 s t a b, Functor f) => (a -> f b) -> s -> f t"
+ ],
+ "text/plain": [
+ "_1 :: forall s t a b (f :: * -> *). (Field1 s t a b, Functor f) => (a -> f b) -> s -> f t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "set :: forall s t a b. ASetter s t a b -> b -> s -> t"
+ ],
+ "text/plain": [
+ "set :: forall s t a b. ASetter s t a b -> b -> s -> t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t"
+ ],
+ "text/plain": [
+ "over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "view :: forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a"
+ ],
+ "text/plain": [
+ "view :: forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ ":t _1\n",
+ ":t set\n",
+ ":t over\n",
+ ":t view\n",
+ "\n",
+ "-- _1 :: Lens (a, other) (b, other) a b\n",
+ "-- over :: Lens s t a b -> (a -> b) -> s -> t\n",
+ "-- over _1 :: (a -> b) -> (a, other) -> (b, other)\n",
+ "-- over _1 show :: (Int, other) -> (String, other)\n",
+ "\n",
+ "set :: Lens s t a b -> b -> s -> t"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "peachPromo :: Promotion [Char]"
+ ],
+ "text/plain": [
+ "peachPromo :: Promotion [Char]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "buffyFigurines :: [[Char]]"
+ ],
+ "text/plain": [
+ "buffyFigurines :: [[Char]]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Promotion {_item = [\"Buffy\",\"Angel\",\"Willow\",\"Giles\"], _discountPercentage = 25.0}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "buffyPromo :: Promotion [[Char]]"
+ ],
+ "text/plain": [
+ "buffyPromo :: Promotion [[Char]]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "data Promotion a =\n",
+ " Promotion { _item :: a\n",
+ " , _discountPercentage :: Double \n",
+ " } deriving (Show)\n",
+ " \n",
+ "item :: Lens (Promotion a) (Promotion b) a b\n",
+ "item = lens getter setter\n",
+ " where\n",
+ " getter :: Promotion a -> a\n",
+ " getter = _item\n",
+ " setter :: Promotion a -> b -> Promotion b\n",
+ " setter promo newItem = promo { _item = newItem }\n",
+ " \n",
+ "let peachPromo = Promotion \"A really delicious Peach\" 25.0\n",
+ "\n",
+ ":t peachPromo\n",
+ "\n",
+ "let buffyFigurines = [\"Buffy\", \"Angel\", \"Willow\", \"Giles\"]\n",
+ "\n",
+ ":t buffyFigurines\n",
+ "\n",
+ "let buffyPromo = set item buffyFigurines peachPromo\n",
+ "\n",
+ "buffyPromo\n",
+ "\n",
+ ":t buffyPromo"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data Preferences a =\n",
+ " Preferences { _best :: a\n",
+ " , _worst :: a\n",
+ " } deriving (Show)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Exercises - Polymorphic Lenses"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "-- 1.\n",
+ "-- Lens (Vorpal x) (Vorpal y) x y\n",
+ "\n",
+ "-- 2.\n",
+ "-- someLens :: Lens (Preferences a) (Preferences b) (a, a) (b, b)\n",
+ "\n",
+ "-- 3.\n",
+ "\n",
+ "data Result' e =\n",
+ " Result' { _lineNumber :: Int\n",
+ " , _result :: Either e String\n",
+ " } deriving (Show)\n",
+ "-- -- Lens (Result' e) (Result' f) (Either e String) (Either f String)\n",
+ "\n",
+ "-- 4.\n",
+ "data ParseResult e a = Error e | Result a deriving (Show)\n",
+ "\n",
+ "result :: Lens (ParseResult e a) (ParseResult f b) (Either e a) (Either f b)\n",
+ "result = lens getter setter\n",
+ " where\n",
+ " getter (Error e) = Left e\n",
+ " getter (Result a) = Right a\n",
+ " setter _ (Left e) = Error e\n",
+ " setter _ (Right a) = Result a\n",
+ " \n",
+ "-- 5.\n",
+ "data Predicate a = Predicate (a -> Bool)\n",
+ "\n",
+ "-- Not sure how this works\n",
+ "-- Lens (Predicate a) (Predicate b) (a -> Bool) (b -> Bool)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Composing Lenses"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "address :: forall (f :: * -> *). Functor f => (Address -> f Address) -> Person -> f Person"
+ ],
+ "text/plain": [
+ "address :: forall (f :: * -> *). Functor f => (Address -> f Address) -> Person -> f Person"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "streetAddress :: forall (f :: * -> *). Functor f => (StreetAddress -> f StreetAddress) -> Address -> f Address"
+ ],
+ "text/plain": [
+ "streetAddress :: forall (f :: * -> *). Functor f => (StreetAddress -> f StreetAddress) -> Address -> f Address"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "streetNumber :: forall (f :: * -> *). Functor f => (String -> f String) -> StreetAddress -> f StreetAddress"
+ ],
+ "text/plain": [
+ "streetNumber :: forall (f :: * -> *). Functor f => (String -> f String) -> StreetAddress -> f StreetAddress"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\"221B\""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Person {_name = \"S. Holmes\", _address = Address {_streetAddress = StreetAddress {_streetNumber = \"221B\", _streetName = \"I am at Baker Street\"}, _city = \"London\", _country = \"England\"}}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "(address . streetAddress) :: forall (f :: * -> *). Functor f => (StreetAddress -> f StreetAddress) -> Person -> f Person"
+ ],
+ "text/plain": [
+ "(address . streetAddress) :: forall (f :: * -> *). Functor f => (StreetAddress -> f StreetAddress) -> Person -> f Person"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "(address . streetAddress . streetNumber) :: forall (f :: * -> *). Functor f => (String -> f String) -> Person -> f Person"
+ ],
+ "text/plain": [
+ "(address . streetAddress . streetNumber) :: forall (f :: * -> *). Functor f => (String -> f String) -> Person -> f Person"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "data Person =\n",
+ " Person { _name :: String\n",
+ " , _address :: Address \n",
+ " } deriving (Show)\n",
+ "\n",
+ "data Address =\n",
+ " Address { _streetAddress :: StreetAddress\n",
+ " , _city :: String\n",
+ " , _country :: String\n",
+ " } deriving (Show)\n",
+ "\n",
+ "data StreetAddress = \n",
+ " StreetAddress { _streetNumber :: String\n",
+ " , _streetName :: String\n",
+ " } deriving (Show)\n",
+ " \n",
+ "makeLenses ''Person\n",
+ "makeLenses ''Address\n",
+ "makeLenses ''StreetAddress\n",
+ "\n",
+ "sherlock :: Person\n",
+ "sherlock = \n",
+ " Person { _name = \"S. Holmes\"\n",
+ " , _address = Address\n",
+ " { _streetAddress = StreetAddress\n",
+ " { _streetNumber = \"221B\"\n",
+ " , _streetName = \"Baker Street\"\n",
+ " }\n",
+ " , _city = \"London\"\n",
+ " , _country = \"England\"\n",
+ " }\n",
+ " }\n",
+ "\n",
+ ":t address -- Lens' Person Address\n",
+ ":t streetAddress -- Lens' Address StreetAddress\n",
+ ":t streetNumber -- Lens' StreetAddress String\n",
+ "\n",
+ "view (address . streetAddress . streetNumber) sherlock\n",
+ "\n",
+ "over (address . streetAddress . streetName) (\"I am at \" ++) sherlock\n",
+ "\n",
+ "\n",
+ ":t (address . streetAddress)\n",
+ ":t (address . streetAddress . streetNumber)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Player,Item {_material = Sweater, _amount = 5})"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "(_2 . material) :: forall s t a1 a2 (f :: * -> *). (Field2 s t (Item a1) (Item a2), Functor f) => (a1 -> f a2) -> s -> f t"
+ ],
+ "text/plain": [
+ "(_2 . material) :: forall s t a1 a2 (f :: * -> *). (Field2 s t (Item a1) (Item a2), Functor f) => (a1 -> f a2) -> s -> f t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "data Player = Player deriving Show\n",
+ "data Wool = Wool deriving Show\n",
+ "data Sweater = Sweater deriving Show\n",
+ "\n",
+ "data Item a =\n",
+ " Item { _material :: a\n",
+ " , _amount :: Int\n",
+ " } deriving Show\n",
+ "makeLenses ''Item\n",
+ "\n",
+ "weave :: Wool -> Sweater\n",
+ "weave Wool = Sweater\n",
+ "\n",
+ "gameState :: (Player, Item Wool)\n",
+ "gameState = (Player, Item Wool 5)\n",
+ "\n",
+ "over (_2 . material) weave gameState\n",
+ "\n",
+ ":t (_2 . material)\n",
+ "\n",
+ "-- (_2 . material) :: Lens (other, Item a) (other, Item b) a b\n",
+ "-- (_2 . material) :: Lens (Player, Item Wool) (Player, Item Sweater) Wool Sweater"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Exercises - Lens Composition"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\"Waldo\""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "-- 1.\n",
+ "view (_2 . _1 . _2) (\"Ginerva\", ((\"Galileo\", \"Waldo\"), \"Malfoy\"))\n",
+ "-- \"Waldo\"\n",
+ "\n",
+ "-- 2.\n",
+ "-- fiveEightDomino :: Lens' Five Eight\n",
+ "-- mysteryDomino :: Lens' Eight Two\n",
+ "-- twoThreeDomino :: Lens' Two Three\n",
+ "\n",
+ "-- dominoTrain :: Lens' Five Three\n",
+ "-- dominoTrain = fiveEightDomino . mysteryDomino . twoThreeDomino\n",
+ "\n",
+ "-- 3.\n",
+ "-- Functor f => (Armadillo -> f Hedgehog) -> (Platypus -> f BabySloth)\n",
+ "-- Lens Platypus BabySloth Armadillo Hedgehog\n",
+ "-- s -> Platypus t -> BabySloth a -> Armadillo b -> Hedgehog"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Haskell",
+ "language": "haskell",
+ "name": "haskell"
+ },
+ "language_info": {
+ "codemirror_mode": "ihaskell",
+ "file_extension": ".hs",
+ "name": "haskell",
+ "pygments_lexer": "Haskell",
+ "version": "8.6.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}