Thank you kind internet person(s) for your time.
I am attempting to implement a Monad that has type Int -> (a, Int, [Int])
and I need to be able to pull each of those values from the Monad.
Currently I am trying to implement, fmap, return, get, and put. The problem is that I have no idea how to retrieve the values from the Int -> (a, Int, [Int])
type.
The monad's type is defined as newtype M a = M { run :: Int -> (a, Int, [Int]) }
where the first int is the value that kicks off the computation (Like the Collatz sequence), the a is the result, the Int in the tuple is the final state (it will end up at 1 if doing the Collatz sequence), and the list of Ints is a log of all the computations that led up to the final state (I.E. is would be: [5, 16, 8, 4, 2, 1] if the beginning int was 5)
So far I have found ways to retrieve the values in the tuple
newtype M a = M { run :: Int -> (a, Int, [Int]) }
getVals :: M a -> Int -> a
getVals m z = a where
(a, _, _) = run m z
getState :: M a -> Int -> Int
getState m z = mid where
(_, mid, _) = run m z
getLog :: M a -> Int -> [Int]
getLog m z = ws where
(_, _, ws) = run m z
(The z is supposed to be the initial integer value that will kick of the computation: E.G. a collatz sequence)
but I haven't been able to retrieve the initial Int from the Int -> (a, Int, [Int])
Just to clarify I am asking for how to retrieve individual details from a Int -> (a, Int, [Int])
type. The Monad stuff is just the context.
CodePudding user response:
First, a stylistic point: you should redefine your tuple as a data type with named fields:
data MD a = MD {
mValue :: a,
mState :: Int,
mLog :: [Int]}
Now on to the meat.
The general form of a monadic action like this is
myAction :: M a
myAction = M $ \oldState ->
... stuff ...
MD result newState newLogs
The lambda argument oldState
is the Int
you are looking for.
Your getState
looks like this:
getState :: M Int
getState = M $ \s -> MD s s []
So you are returning the state argument as your result, and also passing it on unchanged to the next action. No logs get written as a result of doing this.
You can't write getLog
to inspect the current log in this monad because the log list is not being passed along as part of the state. However you can write one which takes an M
action, runs it, and gives you the resulting log as well as writing it to the outer log.
getLog :: M a -> M ([Int], a)
getLog action = M $ \oldState ->
let MD result newState innerLog = run action oldState
in MD (innerLog, result) newState innerLog
You will also want an action
writeLog :: Int -> M ()
Your bind >>=
will have the type:
(>>=) :: M a -> (a -> M b) -> M b
So your Monad
instance is going to start
instance Monad M where
v >>= f = M $ \oldState ->
The new log is going to be the log taken from v
concatenated with the log taken from the output of f
. The rest is left as an exercise for the reader.
CodePudding user response:
There's only one way (up to equivalence) that any type can be made into a Functor
. Here it is for your type:
instance Functor M where
fmap f m = M $ \z -> let (a, mid, ws) = run m z in (f a, mid, ws)
As for how to "retrieve" the Int
to the left of the ->
, that's not something that's stored in the type. You instead get access to it when the function eventually gets called. For example, in my above instance, you'd access it as the z
variable.