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:
{-# LANGUAGE TemplateHaskell, TypeOperators #-}
module StateExample where
import Control.Monad.State hiding (modify)
import Data.Label (mkLabels)
import Data.Label.Pure ((:->))
import Data.Label.PureM
data GlobState = GlobState { _c1 :: Int , _c2 :: Int , _c3 :: Int } deriving Show
$(mkLabels [''GlobState])
newGlobState:: GlobState
newGlobState = GlobState { _c1 = 0, _c2 = 0, _c3 = 0 }
incr :: (GlobState :-> Int) -> State GlobState ()
incr x = modify x (+1)
main :: IO ()
main = do
let a = flip execState newGlobState $ do
incr c1
incr c2
incr c1
print a
There are some magic parts here. We define the GlobState
with the same
record names but prependend with an underscore. Then the function
mkLabels
uses TemplateHaskell
to define "lenses" for every field
in the record. These lenses will have the same name but without the underscore. The argument (GlobState :-> Int)
to incr
is such a
lens, and we can use the modify
function from Data.Label.PureM
which updates records defined this way inside the state monad. We hide
modify
from Control.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
gets
and puts
.
If you do not have fclabels
installed, but you have the cabal
executable from the cabal-install
package (which you get if you install the Haskell Platform), you can install fclabels
by simply running:
cabal install fclabels
If this is the first time you run cabal
, you first need to update the database:
cabal update
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With