haskellfunctional-programmingmonadsmonad-transformersstate-monad# Applying changes to outer Monads in Haskell without using Transformer monads

I am trying to do something like the following where I want to return an error message in case the state of a State-Monad isn't fulfilling a certain condition, can it be done without using `lift`

and `ExceptT`

or other transformer monad?

```
type Log = State [String] ()
stateCheckDuplicate :: String -> Either String Log
stateCheckDuplicate elem =
Right (do
log <- get
if lookup elem log /= Nothing then Left "Duplicate elements"
else
(put (elem:log)))
```

Solution

If I understand what the `stateCheckDuplicate`

should do, you need the type of `stateCheckDuplicate`

isomorphic to `String -> [String] -> Either String [String]`

. Then your implementation will look like this:

```
stateCheckDuplicate :: String -> [String] -> Either String [String]
stateCheckDuplicate msg logs
| msg `elem` logs = Left "Duplicate elements"
| otherwise = Right $ msg : logs
```

As you can see, there is nor State, nor ExceptT, nor liftXXX. But maybe there is one problem, this function is "hard" to compose with others functions. To solve this problem need understand what you try to do.

Update on:

Ok, so I want to use it for a sequence of operations within a do-block, such that the state (or in this case string) will be updated at every operation. Each of these operations could then in turn be handled using for instance mapM_ or the like. I want the function with this do-block to return the Left "Duplicate elements" if the State or String-function returns the Left part, otherwise the function with the do block shall return a completely other type, that could be Either String (Int, Int) or something else.

For using this operation in do-block, the result type should be an instanca of class `Monad`

. You can make your own type for this purpose.

```
newtype LogM a = LogM { runLogM :: [String] -> (Either String a, [String]) }
instance Functor LogM where
fmap f m = LogM $ \log0 ->
let (ex, log1) = runLogM m log0 in
case ex of
Right x -> (Right $ f x, log1)
Left err -> (Left err, log1)
instance Applicative LogM where
pure x = LogM $ \log -> (Right x, log)
mf <*> mx = do
f <- mf
x <- mx
pure $ f x
instance Monad LogM where
m >>= k = LogM $ \log0 ->
let (ex, log1) = runLogM m log0 in
case ex of
Right x -> runLogM (k x) log1
Left err -> (Left err, log1)
instance MonadState [String] LogM where
state f = LogM $ \log0 ->
let (x, log1) = f log0 in
(Right x, log1)
instance MonadError String LogM where
throwError err = LogM $ \log -> (Left err, log)
catchError m h = LogM $ \log0 ->
let (ex, log1) = runLogM m log0 in
case ex of
Right x -> (Right x, log1)
Left err -> runLogM (h err) log1
stateCheckDuplicate :: String -> LogM ()
stateCheckDuplicate msg = do
log <- get
if msg `elem` log then
throwError "Duplicate elements"
else
put $ msg : log
```

But compare how easy it will be with transformers:

```
type LogM = ExceptT String (State [String])
stateCheckDuplicate :: String -> LogM ()
stateCheckDuplicate msg = do
log <- get
if msg `elem` log then
throwError "Duplicate elements"
else
put $ msg : log
```

If you don't want type alias you can do like this:

```
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype LogM a = LogM { runLogM :: ExceptT String (State [String]) a }
deriving ( Functor, Applicative, Monad
, MonadState [String]
, MonadError String
)
```

- Comparing lists in Haskell
- Is there a non-identity monad morphism M ~> M that is monadically natural in M?
- Problem with loading module ‘Distribution.Simple’
- Improving efficiency in Stirling numbers calculation
- Does sequencing an infinite list of IO actions by definition result in a never-ending action? Or is there a way to bail out?
- How to call pgQuery from postgresql-query?
- How to avoid whitespace after a tag (link) in Hamlet templates?
- Understanding type-directed resolution in Haskell with existential types
- Why is seq bad?
- Understanding bind function in Haskell
- How to create route that will trigger on any path in Servant?
- How do I use a global state in WAI middleware?
- nixos 23.11 cabal install mysql-simple problem - "Missing (or bad) C libraries"
- Is there a way to kill all forked threads in a GHCi session without restarting it?
- Why can an invalid list expression such as 2:1 be assigned to a variable, but not printed?
- Iterate over a type level list and call a function based on each type in the list
- How does this solution of Project Euler Problem 27 in the Haskell Wiki work?
- Why `Monad` is required to use `pure`?
- Can't do partial function definitions in GHCi
- recommended way to convert Double -> Float in Haskell
- Haskell profiling understanding cost centre summary for anonymous lambda
- Why is Haskell fully declarative?
- GHC Generating Redundant Core Operations
- Question about Event firing in reflex-frp
- Using Haskell's "Maybe", type declarations
- How can I elegantly invert a Map's keys and values?
- Why there is no output for wrapped IO in Haskell?
- What are the definitions of Weather and Memory in xmobar repo?
- Serializing a Data.Text value to a ByteString without unnecessary \NUL bytes
- Using Haskell with VS Code