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 +}