- Create a new project working-with-lenses, with a simple stack template:
stack new working-with-lenses simple
- Add a dependency on lens library in the build-depends sub-section of the executable section:
executable working-with-lenses hs-source-dirs: src main-is: Main.hs default-language: Haskell2010 build-depends: base >= 4.7 && < 5 , lens
- Open src/Main.hs. We will be adding our source here. Add a TemplateHaskell extension for creating lenses for the user-defined data types. Define the Main module, and import the necessary imports:
{-# LANGUAGE TemplateHaskell #-} module Main where import Control.Lens.TH import Control.Lens
- Define a data type, Line, which is composed of two end Points. Note that we used *_* for naming the fields:
data Point a = Point { _x :: a, _y :: a } deriving Show data Line a = Line { _start :: Point a, _end :: Point a }
deriving Show
- Create lenses for Point and Line. We use TemplateHaskell support in lens to automatically create the lenses for Point and Line:
makeLenses ''Point makeLenses ''Line
This will remove the underscores from the field names, and make lenses out of them.
- Use the data types, and lenses in the main function:
main :: IO () main = do let line = Line (Point 5 7) (Point 11 13) putStrLn $ "Line " ++ show line putStrLn $ "Using lenses" -- Get the x coordinates of the start point putStrLn "Start point of line" print $ view start line putStrLn "Composing lenses" putStrLn "X of end of the line" print $ view (end . x) line putStrLn "Using setters" putStrLn "Setting Y coordinate of end of the line"
-- Supply a function to modify the coordinate (const 17) print $ over (end . y) (const 17) line putStrLn "Making it fancier with ^." putStrLn "Access X of start of line" print $ line ^. (start . x)
- Build and execute the project:
stack build stack exec -- working-with-lenses
- You should see the following output:
