It's not entirely clear what you have in mind, but based on the comments, here's a few suggestions.
Parametrise the function
As given, f
returns (Int, String)
, and you can't just change that. What you can do, however, is to parametrise it:
f' :: a -> a -> Int -> (Int, a)
f' bigger smaller x | x > 3 = (x, bigger)
| otherwise = (x, smaller)
This variation no longer returns (Int, String)
, but rather (Int, a)
. The price you pay, however, is that you must supply bigger
and smaller
as arguments. We'll return to that in a moment, but before we do that, we can turn any function with the general type s -> (s, a)
into a State s a
value:
make' :: (s -> (s, a)) -> State s a
make' fn = State fn
You can now partially apply f'
to vary the type:
*Q56181862> :t make' $ f' "bigger than 3" "smaller than 3"
make' $ f' "bigger than 3" "smaller than 3" :: State Int [Char]
*Q56181862> :t make' $ f' True False
make' $ f' True False :: State Int Bool
In the first of the above GHCi examples, the type is State Int String
, whereas the second example has the type State Int Bool
.
Return
From other comments, it seems that you wish to vary between State Int String
and State Int (IO String)
. While you can achieve that with the above technique, you can also use return
in the function itself:
f'' :: Monad m => Int -> (Int, m String)
f'' x | x > 3 = (x, return "bigger than 3")
| otherwise = (x, return "smaller than 3")
This varies only the monad, but not the 'return type' String
. You can provide enough hints to Haskell's type system to inform it that m
should be IO
:
*Q56181862> :t make' $ f'' :: State Int (IO String)
make' $ f'' :: State Int (IO String) :: State Int (IO String)
If you don't want to run the computation in IO
, you can instead run it in Identity
, which is also a Monad
:
*Q56181862 Control.Monad.Identity> :t make' $ f'' :: State Int (Identity String)
make' $ f'' :: State Int (Identity String) :: State Int (Identity String)
You can now run the computation and pull the String
out of Identity
using runIdentity
.
Functor
If you make State s
a functor as well, you can pull the String
out of Identity
:
*Q56181862 Control.Monad.Identity> :t fmap runIdentity $ make' $ f''
fmap runIdentity $ make' $ f'' :: State Int String
The easiest way to do that is to use the DeriveFunctor
GHC extension:
newtype State s a = State { runstate :: s -> (s, a) } deriving Functor
...or, you could just use Control.Monad.State.Lazy
from the mtl
package...