I am working on this problem and had previously asked related question. Implementation of State Monad To further refine my code i tried to implement it using only one increment function.
module StateExample where
import Control.Monad.State
data GlobState = GlobState { c1 :: Int, c2:: Int, c3:: Int} deriving (Show)
newGlobState:: GlobState
newGlobState = GlobState { c1=0,c2=0,c3=0 }
incr :: String-> State GlobState ()
incr x = do
modify(\g -> g {x =x g + 1})
main:: IO()
main = do
let a1= flip execState newGlobState $ do
incr c1
incr c2
incr c1
print a
But here i am getting an error
`x' is not a (visible) constructor field name
How can i remove this error?
You have hit a weakness in Haskell: records are not first class values!
Indeed, it would be very nice to write as you have done, but it is not possible.
However, you can use different libraries to achieve the desired effect.
This is how it looks if you use
fclabels:
There are some magic parts here. We define the
GlobStatewith the samerecord names but prependend with an underscore. Then the function
mkLabelsusesTemplateHaskellto define “lenses” for every fieldin the record. These lenses will have the same name but without the underscore. The argument
(GlobState :-> Int)toincris such alens, and we can use the
modifyfunction fromData.Label.PureMwhich updates records defined this way inside the state monad. We hide
modifyfromControl.Monad.State, to avoid collision.You can look at the other
functions in the
documentation for
PureM
for other functions usable with state monads, as
getsandputs.If you do not have
fclabelsinstalled, but you have thecabalexecutable from thecabal-installpackage (which you get if you install the Haskell Platform), you can installfclabelsby simply running:If this is the first time you run
cabal, you first need to update the database: