Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Haskell's lens package handle fields that are also keywords?

Tags:

haskell

lenses

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.

like image 863
Ben Ford Avatar asked May 17 '13 13:05

Ben Ford


1 Answers

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"
like image 189
hammar Avatar answered Oct 23 '22 21:10

hammar