I am trying to create a function
for the state monad that can receive a generic type in the a
:
newtype State s a=State { runstate::s->(s,a) }
I want to bind only the first type of the runstate::s->(s,a)
, and later decide what a
should be :
So instead of something like :
f::Int->(Int,String)
f x | x>3 = (x, "bigger then 3")
|otherwise =(x,"smaller then 3")
make::State Int String
make =State f
How can I accomplish :
makeFree::State Int a
makeFree=State ....
You might be wondering why would I need that. While I know the type of the state
i want the result of the computation to vary.
It's not entirely clear what you have in mind, but based on the comments, here's a few suggestions.
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
.
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
.
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...