haskell-notebooks/lenses.ipynb

2008 lines
50 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Each type of **Optic** comes with a set of compatible **actions**.\n",
"\n",
"Lenses have the following concrete gaurantees.\n",
"\n",
"* A Lens focuses (i.e selects) a single piece of data within a larger structure.\n",
"* A Lens must **never fail** to **get** or **modify** that focus.\n",
"\n",
"These constraints unlock a few **actions** we can perform on lenses.\n",
"\n",
"* We can use a lens to **view** the **focus** within a structure.\n",
"* We can use a lens to **set** the **focus** within a structure.\n",
"* We can use a lens to **modify** the **focus** within a structure."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"hello\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"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",
"view (_2 . _1) (42, (\"hello\", False))\n",
"\n",
"-- view is the action\n",
"-- (_2 . _1) is the path\n",
"-- (42, (\"hello\", False)) is the structure\n",
"-- \"hello\" is the focus"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exercises - Optic Anatomy"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"(False,Left \"new\")"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"\"TESTING ONE two three\""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"\"supercalifragilisticexpialidocious\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view (_1 . _2) ((1, 2), 3)\n",
"\n",
"-- view is the action\n",
"-- (_1 . _2) is the path. Focus on the 1st member of tuple and then the 2nd member of 1st member\n",
"-- ((1, 2), 3) is the structure\n",
"-- 2 is the focus\n",
"\n",
"set (_2 . _Left) \"new\" (False, Left \"old\")\n",
"\n",
"-- set is the action\n",
"-- (_2 . _Left) is the path\n",
"-- (False, Left \"Old\") is the structure\n",
"-- \"old\" is the focus\n",
"\n",
"over (taking 2 worded . traversed) C.toUpper \"testing one two three\"\n",
"\n",
"-- over is the action\n",
"-- (taking 2 worded . traversed) is the path\n",
"-- \"testing one two three\"\n",
"-- \"testing one\" is the focus\n",
"\n",
"foldOf (both . each) ([\"super\", \"cali\"],[\"fragilistic\", \"expialidocious\"])\n",
"\n",
"-- foldOf is the action\n",
"-- (both . each) is the path\n",
"-- The rest is the structure"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Lens Actions\n",
"\n",
"### Viewing through lenses"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>_1 :: forall s t a b (f :: * -> *). (Field1 s t a b, Functor f) => (a -> f b) -> s -> f t</span>"
],
"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": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>Lens' :: * -> * -> *</span>"
],
"text/plain": [
"Lens' :: * -> * -> *"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>Lens :: * -> * -> * -> * -> *</span>"
],
"text/plain": [
"Lens :: * -> * -> * -> * -> *"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>_2 :: forall s t a b (f :: * -> *). (Field2 s t a b, Functor f) => (a -> f b) -> s -> f t</span>"
],
"text/plain": [
"_2 :: forall s t a b (f :: * -> *). (Field2 s t a b, Functor f) => (a -> f b) -> s -> f t"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>view :: forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a</span>"
],
"text/plain": [
"view :: forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'a'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"'b'"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":t _1\n",
"\n",
":k Lens'\n",
":k Lens\n",
"\n",
"-- _1 :: Lens' (a, b) a\n",
"-- (a, b) --> Type of structure\n",
"-- a --> Focus within it\n",
"\n",
":t _2\n",
"\n",
":t view\n",
"\n",
"-- A lens on it's own isn't enough. We need an action to perform on it.\n",
"\n",
"-- view :: Lens' s a -> s -> a\n",
"-- Get the path's focus from within the structure\n",
"\n",
"view _1 ('a', 'b')\n",
"\n",
"view _2 ('a', 'b')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setting through a lens"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>set :: forall s t a b. ASetter s t a b -> b -> s -> t</span>"
],
"text/plain": [
"set :: forall s t a b. ASetter s t a b -> b -> s -> t"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t</span>"
],
"text/plain": [
"over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"('x','b')"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"(100,2)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- set :: Lens' s a -> a -> s -> s\n",
"-- Set a new value at the paths focus, leaving the rest of the structure unaltered.\n",
"\n",
"-- over :: Lens' s a -> (a -> a) -> s -> s\n",
"-- Modify the focus of a path by running a function over it, altering it in-place and leaving the\n",
"-- rest of the structure unaltered.\n",
"\n",
":t set\n",
":t over\n",
"\n",
"set _1 'x' ('a', 'b')\n",
"\n",
"over _1 (*100) (1, 2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exercises - Lens Actions"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'c'"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"(False,20)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- 1. Find structure & focus in the following lens\n",
"\n",
"-- Lens' (Bool, (Int, String)) Int\n",
"\n",
"-- (Bool, (Int, String)) is the structure\n",
"-- Focus is Int, the 1st member of the 2nd member of the complete structure\n",
"\n",
"-- 2. Write the type signature of a Lens with the structure (Char, Int) and the focus Char\n",
"\n",
"-- Lens' (Char, Int) Char\n",
"\n",
"-- 3. Name three actions we can use on a Lens\n",
"\n",
"-- set\n",
"-- view\n",
"-- over\n",
"\n",
"-- 4\n",
"\n",
"view _3 ('a', 'b', 'c')\n",
"\n",
"over _2 (*10) (False, 2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Lenses and records\n",
"\n",
"* Lenses subsume the accessor pattern in other languages."
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>lens :: forall (f :: * -> *) s a b t. Functor f => (s -> a) -> (s -> b -> t) -> (a -> f b) -> s -> f t</span>"
],
"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"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>Lens :: * -> * -> * -> * -> *</span>"
],
"text/plain": [
"Lens :: * -> * -> * -> * -> *"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>Lens' :: * -> * -> *</span>"
],
"text/plain": [
"Lens' :: * -> * -> *"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Just changed the names from the example in the book\n",
"data Name = \n",
" Name { _name :: String\n",
" , _age :: Int\n",
" } deriving (Show)\n",
" \n",
"-- lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b\n",
"-- lens :: (s -> a) -> (s -> a -> s) -> Lens' s a\n",
"\n",
":t lens\n",
":k Lens\n",
":k Lens'\n",
"\n",
"-- Whenever you see 's' in a Lens thing 'structure' and when you see 'a', think 'focus'.\n",
"\n",
"-- getAge :: s -> a\n",
"getAge :: Name -> Int\n",
"getAge = _age\n",
"\n",
"-- setAge :: s -> a -> s\n",
"setAge :: Name -> Int -> Name\n",
"setAge name newAge = name { _age = newAge }\n",
"\n",
"numAge :: Lens' Name Int\n",
"numAge = lens getAge setAge"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exercises - Records Part One"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"31"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Name {_name = \"Sanchayan Maity\", _age = 32}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Name {_name = \"Sanchayan Maity\", _age = 34}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Name {_name = \"Sanchayan Maity\", _age = 34}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"\"Sanchayan Maity\""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Name {_name = \"Foo\", _age = 31}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Name {_name = \"Boo Sanchayan Maity\", _age = 31}"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- 1. The structure and focus of a lens are typically represented by which letters in type signature\n",
"-- s and a respectively\n",
"\n",
"-- 2. Which two components are required to create a lens\n",
"-- getter and setter\n",
"\n",
"-- Implement the following Lens\n",
"\n",
"-- name :: Lens' Name String\n",
"\n",
"getName :: Name -> String\n",
"getName = _name\n",
"\n",
"setName :: Name -> String -> Name\n",
"setName name newName = name { _name = newName }\n",
"\n",
"name :: Lens' Name String\n",
"name = lens getName setName\n",
"\n",
"myName :: Name\n",
"myName = Name { _name = \"Sanchayan Maity\"\n",
" , _age = 31 } \n",
" \n",
"-- Getting, setting & modifying with a field lens\n",
"\n",
"-- For Age field\n",
"view numAge myName\n",
"set numAge 32 myName\n",
"over numAge (+3) myName\n",
"set numAge (view numAge myName + 3) myName\n",
"\n",
"-- For Name field\n",
"view name myName\n",
"set name \"Foo\" myName\n",
"over name (\"Boo \" ++) myName"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Automatically generating field names"
]
},
{
"cell_type": "code",
"execution_count": 67,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>name :: forall (f :: * -> *). Functor f => (String -> f String) -> Ship -> f Ship</span>"
],
"text/plain": [
"name :: forall (f :: * -> *). Functor f => (String -> f String) -> Ship -> f Ship"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>numCrew :: forall (f :: * -> *). Functor f => (Int -> f Int) -> Ship -> f Ship</span>"
],
"text/plain": [
"numCrew :: forall (f :: * -> *). Functor f => (Int -> f Int) -> Ship -> f Ship"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>getNumCrew :: Ship -> Int</span>"
],
"text/plain": [
"getNumCrew :: Ship -> Int"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"data Ship = \n",
" Ship { _name :: String\n",
" , _numCrew :: Int \n",
" } deriving (Show)\n",
"\n",
"makeLenses ''Ship\n",
"\n",
":t name\n",
":t numCrew\n",
":t getNumCrew"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exercises - Records Part Two"
]
},
{
"cell_type": "code",
"execution_count": 72,
"metadata": {},
"outputs": [],
"source": [
"-- data Inventory = \n",
"-- Inventory { _wand :: Wand\n",
"-- , _book :: Book\n",
"-- , _potions :: [Potion] }\n",
"\n",
"-- makeLenses ''Inventory\n",
"\n",
"-- Lenses generated would be\n",
"\n",
"-- wand\n",
"-- book\n",
"-- potions\n",
"-- getWand\n",
"-- getBook\n",
"-- getPotions\n",
"-- setWand\n",
"-- setBook\n",
"-- setPotions\n",
"\n",
"-- gazork :: Functor f => (Spuzz -> f Spuzz) -> Chumble -> f Chumble\n",
"-- gazork :: Lens' Chumble Spuzz\n",
"\n",
"data Pet = Pet \n",
" { _petName :: String\n",
" , _petType :: String\n",
" }\n",
" \n",
"makeLenses ''Pet\n",
"\n",
"getPetName :: Pet -> String\n",
"getPetName = view petName"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Lens is an optic which **always** accesses **exactly** one focus"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Is it a Lens?\n",
"\n",
"* second :: Lens' (a, b, c) b\n",
"\n",
"* inMaybe :: Lens' (Maybe a) a\n",
"\n",
"* left :: Lens' (Either a b) a\n",
"\n",
"* listThird :: Lens' [a] a\n",
"\n",
"* Can you write a lens which focuses the second element of a tuple if the Bool in the first slot is True and focuses the third element if its False ? conditional :: Lens' (Bool, a, a) a\n",
"\n",
"* Consider the below data type. Is it possible to have a lens msg :: Lens' Err String"
]
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [],
"source": [
"data Err = \n",
" ReallyBadError { _msg :: String }\n",
" | ExitCode { _code :: Int }\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Lens Laws\n",
"\n",
"1. You get back what you set\n",
"2. Setting back what you got doesn't do anything\n",
"3. Setting twice is the same as setting once"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Virtual Fields"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"</style><span class='get-type'>celsius :: forall (f :: * -> *). Functor f => (Float -> f Float) -> Temperature -> f Temperature</span>"
],
"text/plain": [
"celsius :: forall (f :: * -> *). Functor f => (Float -> f Float) -> Temperature -> f Temperature"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"7.0"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Temperature {_location = \"Bangalore\", _celsius = 13.5}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Temperature {_location = \"Bangalore\", _celsius = 17.0}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"44.6"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Temperature {_location = \"Bangalore\", _celsius = 13.5}"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Temperature {_location = \"Bangalore\", _celsius = 17.0}"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"data Temperature = \n",
" Temperature { _location :: String\n",
" , _celsius :: Float\n",
" } deriving (Show)\n",
" \n",
"makeLenses ''Temperature\n",
"\n",
":t celsius\n",
"\n",
"let temp = Temperature \"Bangalore\" 7.0\n",
"\n",
"view celsius temp\n",
"set celsius 13.5 temp\n",
"over celsius (+10) temp\n",
"\n",
"celsiusToFahrenheit :: Float -> Float\n",
"celsiusToFahrenheit c = (c * (9/5)) + 32\n",
"\n",
"fahrenheitToCelsius :: Float -> Float\n",
"fahrenheitToCelsius f = (f - 32) * (5/9)\n",
"\n",
"fahrenheit :: Lens' Temperature Float\n",
"fahrenheit = lens getter setter\n",
" where\n",
" getter = celsiusToFahrenheit . view celsius\n",
" setter temp f = set celsius (fahrenheitToCelsius f) temp\n",
" \n",
"view fahrenheit temp\n",
"set fahrenheit 56.3 temp\n",
"over fahrenheit (+18) temp"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note: TODO: The exercises on laws & virtual fields"
]
}
],
"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
}