Skip to content

Instantly share code, notes, and snippets.

@etorreborre
Created July 14, 2021 07:22
Show Gist options
  • Save etorreborre/3f4eff01ed3cb0ef66cabe5e3d3a2e39 to your computer and use it in GitHub Desktop.
Save etorreborre/3f4eff01ed3cb0ef66cabe5e3d3a2e39 to your computer and use it in GitHub Desktop.
Optics with the Witch library
{-# LANGUAGE TemplateHaskell #-}
import qualified Data.Text as T
import Optics as O
import Protolude hiding ((%), from)
import Witch
import Data.Coerce
-- 2 different temperature types
newtype Kelvin = Kelvin Double deriving (Eq, Show, Num)
newtype Celsius = Celsius Double deriving (Eq, Show, Num)
-- conversions between the 2 different temperature types
instance From Kelvin Celsius where
from (Kelvin k) = Celsius (k - 273.15)
instance From Celsius Kelvin where
from (Celsius c) = Kelvin (c + 273.15)
-- measured temperature is stored as Kelvin
data Temperature = Temperature
{ _location :: Text,
_measured :: Kelvin
}
deriving (Eq, Show)
makeLenses ''Temperature
-- we can use from to implement a celsius lens
celsius :: Lens' Temperature Celsius
celsius = lens getter setter
where
getter = from . view measured
setter temp c = set measured (from c) temp
-- we can also redefine set and view to use a From instance
set' :: (Is k A_Setter, From c b) => Optic k is s t a b -> c -> s -> t
set' o b s = set o (from b) s
view' :: (Is k A_Getter, From a b) => Optic' k is s a -> s -> b
view' o s = from $ view o s
-- example: we modify a measured temperature directly even if the
-- measurement is in Celsius
> let t = Temperature "here" (Kelvin 300)
> set' measured (Celsius 20) t
Temperature {_location = "here", _measured = Kelvin 293.15}
it :: Temperature
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment