Question

How does lens handle the case where a de-sugared field is a keyword? I seem to remember reading that something special is done, but I can't remember where I read it or what the name of the "lensed" accessor would end up as.

Consider the following:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

import           Control.Lens
import           Control.Monad.IO.Class (liftIO)
import           Data.Maybe
import           Data.Aeson
import           Data.Aeson.TH
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy    as L
import qualified Data.ByteString.Lazy.Char8 as LC8
import qualified Data.Text.Lazy.Encoding as TLE


data Typ = Typ {
    _fld1 :: BS.ByteString
  , _type :: Int
} deriving (Show)

$(deriveJSON tail ''Typ)
$(makeLenses ''Typ)


main = do
  print $ typ^.fld1
  print $ typ^.getType
  where
    jsonTyp = "{\"fld1\": \"Test\", \"type\": 1 }"
    typ'    = decode jsonTyp  :: Maybe Typ
    typ     = fromJust typ'
    getType :: Getter Typ Int
    getType = to _type

What would the _type accessor be called and how do I avoid having to implement getType here?

I had to bash this out on school of haskell because I don't have access to a proper dev environment here, but I figure it might be useful to others. I'll add an answer when I can drop into ghci and do a :browse (if that gives an answer), but in the mean time does anyone know?

Conclusion

Thanks guys, I'll use makeLensesWith along with a mapping of keywords to replacements as per Edward's suggestion.

Was it helpful?

Solution

It doesn't do anything special. The generated lens is named type and funnily enough, GHC appears to be totally cool with this. You can even use it if you use the fully qualified name:

{-# LANGUAGE TemplateHaskell #-}    
module Foo where

import Control.Lens

data Bar = Bar { _type :: String }
  deriving Show

$(makeLenses ''Bar)
> :l Foo
> :t type      -- Um...
<interactive>:1:1: parse error on input `type'
> :t Foo.type  -- Haha!
Foo.type
  :: (Functor f, Profunctor p) =>
     p String (f String) -> p Bar (f Bar)
> Bar "hello" ^. Foo.type
"hello"

OTHER TIPS

I usually just pick a field name that is nearby. Use something like _ty instead of _type and then the resulting lens will be callable.

You can also use makeLensesWith to supply a custom name mangling function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top