{ "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 }