haskellfunctional-programmingreturnmonadsreturn-type# How does return work within a Monad context within Haskell

Why does the following, given that the RegModule instance defines its return as: `return a = RegModule (\_s _i d -> return (a, 0, d))`

, not return `[((c, i+1, d), Int, d)]`

, and why does the second case expression not need to be written with `return []`

:

```
scanChar :: RegModule d Char
scanChar = RegModule (\s i d ->
case drop i s of
(c:cs) -> return (c, i+1, d)
[] -> []
)
```

In MVE:

```
import qualified Data.Set as S
import Control.Monad
type CharSet = S.Set Char
data RE =
RClass Bool CharSet
newtype RegModule d a =
RegModule {runRegModule :: String -> Int -> d -> [(a, Int, d)]}
instance Monad (RegModule d) where
return a = RegModule (\_s _i d -> return (a, 0, d))
m >>= f =
RegModule (\s i d -> do (a, j, d') <- runRegModule m s i d
(b, j', d'') <- runRegModule (f a) s (i + j) d'
return (b, j + j', d''))
instance Functor (RegModule d) where fmap = liftM
instance Applicative (RegModule d) where pure = return; (<*>) = ap
scanChar :: RegModule d Char
scanChar = RegModule (\s i d ->
case drop i s of
(c:cs) -> return (c, i+1, d)
[] -> []
)
regfail :: RegModule d a
regfail = RegModule (\_s _i d -> []
)
regEX :: RE -> RegModule [String] ()
regEX (RClass b cs) = do
next <- scanChar
if (S.member next cs)
then return ()
else regfail
runRegModuleThrice :: RegModule d a -> String -> Int -> d -> [(a, Int, d)]
runRegModuleThrice matcher input startPos state =
let (result1, pos1, newState1) = head $ runRegModule matcher input startPos state
(result2, pos2, newState2) = head $ runRegModule matcher input pos1 newState1
(result3, pos3, newState3) = head $ runRegModule matcher input pos2 newState2
in [(result1, pos1, newState1), (result2, pos2, newState2), (result3, pos3, newState3)]
```

Solution

It's a matter of type inference. In the code:

```
scanChar :: RegModule d Char
scanChar = RegModule (\s i d ->
case drop i s of
(c:cs) -> return (c, i+1, d)
[] -> []
)
```

the `RegModule`

constructor on the right hand side has type:

```
RegModule :: (String -> Int -> d -> [(a, Int, d)]) -> RegModule d a
```

Since `scanChar`

has type signature `RegModule d Char`

, Haskell unifies the types `RegModule d Char`

(on the left) with `RegModule d a`

(on the right), resulting in the unification of the type variable `a`

with `Char`

. Therefore, the expected type of the function passed to the `RegModule`

constructor is:

```
String -> Int -> d -> [(Char, Int, d)]
```

Note that, so far, we've only considered the type signature for `scanChar`

, and the type of the constructor `RegModule`

. Nothing from the various instances for `RegModule`

has been used.

Anyway, the anonymous lambda `\s i d -> ...`

gets unified with this type, so the arguments `s`

, `i`

, and `d`

must have type `String`

, `Int`

, and `d`

respectively, as you'd expect from their names, while the body must have type `[(Char, Int, d)]`

. Since the body of the anonymous lambda is a `case`

expression, every expression on the right-hand side of one of the cases must have that same type, `[(Char, Int, d)]`

. So, we have:

```
return (c, i+1, d) :: [(Char, Int, d)] -- for the first case
```

and:

```
[] :: [(Char, Int, d)] -- for the second case
```

The `return`

function is polymorphic with type `(Monad m) => t -> m t`

, so to unify this particular `return`

expression with its type, Haskell unifies `m`

with the list functor `[]`

and `t`

with the type of the argument passed to `(c, i+1, d)`

, namely `(Char, Int, d)`

. This instantiates `return`

to the type for the `[]`

monad:

```
return :: t -> [t]
```

and the list for elements of type `(Char, Int, d)`

in particular:

```
return :: (Char, Int, d) -> [(Char, Int, d)]
```

So, it's the `return`

function for the list monad that's used, and -- given its definition -- you could replace the code with:

```
...
(c:cs) -> [(c, i+1, d)]
...
```

and it would have the same meaning.

On the other hand, if the `[]`

on the RHS of the last case was replaced with `return []`

, the compiler would attempt to unify the general type signature for `return`

:

```
return :: (Monad m) => t -> m t
```

by unifying the argument type `t`

with the type of the empty list `[] :: [u]`

giving the type equality:

```
t ~ [u]
```

for some `u`

, while at the same type unifying the type of the `return []`

expression `m t`

with the expected type based on the type inference above, namely `[(Char, Int, d)]`

, giving the type equalities:

```
m ~ []
t ~ (Char, Int, d)
```

Since the type equality `t ~ [u]`

is incompatible with the type equality `t ~ (Char, Int, d)`

, this would be a type error:

```
Return.hs:29:18-19: error:
• Couldn't match expected type: (Char, Int, d)
with actual type: [a0]
```

In the end, none of the type inference above uses the type of `return`

for `RegModule d`

monad.

- 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