I have a single monadic action called step that I would like to run recursively until it returns a Nothing value. The below code works, but I'm calling runState on every step. The solution I'm looking for would build up within the state monad then call runState once at the end.
I know my use of Maybe here screams "transformer", but I'm trying to get it to work without a transformer first.
testFn :: Int -> Maybe Int
testFn i = if i > 5 then Nothing else Just i
step :: State Int (Maybe Int)
step = do
i <- get
let i' = testFn i
put $ maybe i (1 +) i'
return i'
go :: Int -> Int -> Maybe Int
go s a = case runState step s of
(Nothing, _) -> Just a
(Just a', s') -> go s' a'
repl:
> go 0 0
Just 5
You can write a modifier that transforms a a -> State s (Maybe a) to a a -> State s a:
repeatM :: Monad m => (a -> m (Maybe a)) -> a -> m a
repeatM f = g
where g x = f x >>= maybe (pure x) g
We can thus create a function with:
repeatStep :: Int -> State Int Int
repeatStep = repeatM (const step)
Then go is just:
go :: Int -> Int -> (Int, Int)
go s a = runState (repeatStep a) s
Here the first item of the 2-tuple is the Int that is the last Just … output before it outputs Nothing. The second item of 2-tuple is the state in that case.
and then our go thus returns:
Prelude Control.Monad.State> go 0 0
(5,6)
Related
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.
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.
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.
I have a these three functions
a :: Int -> Maybe Int
a i = if i < 100 then Just i else Nothing
b :: Int -> Maybe Int
b i = if i < 50 then Just i else Nothing
c :: Int -> Maybe Int
c i = if i > 0 then Just i else Nothing
And I want to chain them together so that when the result of one function results in a Nothing the input of that function is returned instead.
I can achieve this with this function:
import Data.Maybe (fromMaybe)
e :: Int -> [Int -> Maybe Int] -> Int
e i [] = i
e i (f:fs) = e (fromMaybe i $ f i) fs
-
*Main> e 75 [a,b,c]
75
Is there an existing function, Monad instance, or other way in the base libraries that exhibits this behavior?
Expanding my comment above -- this approach is not too different from the code the OP posted.
We first define how to turn a function a -> Maybe a into a -> a, substituting the input for Nothing.
totalize :: (a -> Maybe a) -> (a -> a)
totalize f x = fromMaybe x (f x)
Then, we exploit the above: we make every function "total" (meaning no-Nothings), wrap it as an Endo, then we compose the list of endomorphisms (mconcat is composition in the Endo monoid).
e :: [a -> Maybe a] -> a -> a
e = appEndo . mconcat . map (Endo . totalize)
or even (as suggested below)
e :: Foldable t => t (a -> Maybe a) -> a -> a
e = appEndo . foldMap (Endo . totalize)
Well, you can create a a -> a from a a -> Maybe a:
repair :: (a -> Maybe a) -> a -> a
repair f x = fromMaybe x (f x)
Afterwards, you can just combine (.) and repair:
andThen :: (a -> Maybe a) -> (a -> Maybe a) -> a -> a
andThen f g = repair g . repair f
But there's no library function for that, since there is no general way to get a value out of a Monad.
Are you looking for the maybe monad?
*Main> let f x = a x >>= b >>= c >> return x
*Main> f 1
Just 1
*Main> f 100
Nothing
*Main>
Then if the result is Nothing we can get to your desired end state with fromMaybe (or just maybe and id, same thing):
*Main> let g x = maybe x id (f x)
*Main> g 100
100
I find it difficult for me to understand the MonadState .
The reason maybe most of the examples mixing up with record syntax in their data structure.
So, I tried to implement the MonadState without using record syntax.
The following code I wrote did pass the compiler, but it seems totally nonsense to me.
What is wrong with these code?
Is there a simple example of implementing MonadState without using record syntax?
data Foo a b = Foo (Maybe ([a],b)) deriving (Show)
unwrapFoo :: Foo a b -> Maybe ([a],b)
unwrapFoo (Foo x) = x
instance Monad (Foo [a]) where
return x = Foo $ Just ([], x)
m >>= f = case unwrapFoo m of
Just (_, r) -> f r
Nothing -> Foo Nothing
instance MonadState Int (Foo [a]) where
get = Foo $ Just ([], 1)
put _ = Foo $ Just ([],())
*Main> get :: Foo [a] Int
Foo (Just ([],1))
*Main> put 3 :: Foo [a] ()
Foo (Just ([],()))
*Main>
So let's start with the basic idea of the State Monad.
newtype MyState s a = MyState (s {- current state -}
-> (s {- New state -}, a {- New value -}))
unwrap (MyState f) = f
So now we need to implement >>= and return.
return is pretty easy:
return a = MyState $ \s -> -- Get the new state
(s, a) -- and pack it into our value
In other words, this just passes the current state through with a new value.
And now >>=
(MyState f) >>= g = MyState $ \state ->
let (newState, val) = f state
MyState newF = g val
in newF state
So we get a new state, feed it into our existing state monad, then pass the resulting value/state pair into g and return the result of that.
The total number of differences between this and the record syntax is just that I had to manually define unwrap.
To complete our monad
runState = unwrap
get = MyState \s -> (s, s)
put a = MyState \s -> (a, ())
Is there a traditional way to map over a function that uses IO? Specifically, I'd like to map over a function that returns a random value of some kind. Using a normal map will result in an output of type ([IO b]), but to unpack the values in the list from IO, I need a something of type (IO [b]). So I wrote...
mapIO :: (a -> IO b) -> [a] -> [b] -> IO [b]
mapIO f [] acc = do return acc
mapIO f (x:xs) acc = do
new <- f x
mapIO f xs (new:acc)
... which works fine. But it seems like there ought to be a solution for this built into Haskell. For instance, an example use case:
getPercent :: Int -> IO Bool
getPercent x = do
y <- getStdRandom (randomR (1,100))
return $ y < x
mapIO (\f -> getPercent 50) [0..10] []
The standard way is via:
Control.Monad.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
which is implemented in terms of sequence:
sequence :: (Monad m) => [m a] -> m [a]
Just to add to Don's answer, hake a look to the mapM_ function as well, which does exactly what mapM does but discards all the results so you get only side-effects.
This is useful if you want the have computations executed (for example IO computations) but are not interested in the result (for example, unlinking files).
And also see forM and forM_.
I want to create my own monad. This is what i wrote:
data LeafConType a = LeafCon (a,Int,Int)
instance Monad (LeafConType ) where
return = LeafCon
lc#(LeafCon (t,i,n)) >>= f = if i>=n
then lc
else f (t,i,n)
But this dont work. Ghc says:
leafcon.hs:26:1:
Occurs check: cannot construct the infinite type: a = (a, Int, Int)
When generalising the type(s) for `return'
In the instance declaration for `Monad LeafConType'
leafcon.hs:27:1:
Occurs check: cannot construct the infinite type: a = (a, Int, Int)
When generalising the type(s) for `>>='
In the instance declaration for `Monad LeafConType'
Whats wrong with that?
I want to do calculations while i is lower than n. n should be constants by I don't know yet how to do this correct. It should be some mix of State and Maybe. If you have some advices feel free to share it with me:P
About return:
Prelude> :t return
return :: (Monad m) => a -> m a
So return takes an argument of type a, and returns something of type m a. In this case m is LeafConType, so LeafConType a is returned.
Now suppose that we pass True. Then a = Bool, so the return type must be LeafConType Bool. However, you define:
return = LeafCon
So, return True becomes LeafCon True. But that is not allowed, because the type definition of LeafConType states that
data LeafConType a = LeafCon (a, Int, Int)
So for LeafConType Bool the argument to LeafCon must have type (Bool, Int, Int), not just Bool. And that is what the compile error means: a cannot be the same as (a, Int, Int). You state:
I want to do calculations while i is lower than n.
This means that you will need some default values for i and n, for otherwise it will be impossible to define return. If both of them are zero by default, then you could define:
return a = LeafCon (a, 0, 0)
About (>>=):
Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
Now look at your implementation (slightly different notation, same idea):
lc#(LeafCon (t, i, n)) >>= f | i >= n = lc
| otherwise = f t
What we see here, is that lc is returned when i >= n. But lc is of type LeafConType a, while f is a function which may return a value of type LeafConType b, for any b. As a result it could be that b is not equal to a and hence these types don't match. In conclusion, you seriously have to ask yourself one question:
Can this type of computation be expressed as a monad anyway?
The functions you specified for >>= and return don't satisfy the types required by Monad:
return :: a -> LeafConType a
Given the declaration
return = LeafCon
you give the function the incompatible type
return :: (a, Int, Int) -> LeafConType a
A statement like return 42 would therefore be impossible in your monad.
I don't understand what your monad should do at all.
First take a look at simple, working monads!
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
Judging from your description of what you want your monad to do, I think you want something a bit like this:
data LeafConType a = LeafCon { runLeafCon' :: Int -> Int -> (Maybe a, Int, Int) }
runLeafCon :: Int -> Int -> LeafConType a -> Maybe a
runLeafCon i n lc = let (t, _, _) = runLeafCon' lc i n in t
getI :: LeafConType Int
getI = LeafCon $ \i n -> (Just i, i, n)
getN :: LeafConType Int
getN = LeafCon $ \i n -> (Just n, i, n)
setI :: Int -> LeafConType ()
setI i = LeafCon $ \_ n -> (Just (), i, n)
setN :: Int -> LeafConType ()
setN n = LeafCon $ \i _ -> (Just (), i, n)
instance Monad LeafConType where
return t = LeafCon $ \i n -> if (i < n)
then (Just t, i, n)
else (Nothing, i, n)
(LeafCon k) >>= f =
LeafCon $ \i n ->
let (t, i', n') = k i n
in case t of
Nothing -> (Nothing, i', n')
(Just t') -> if (i' < n')
then runLeafCon' (f t') i' n'
else (Nothing, i, n)
example :: Int -> LeafConType ((), Int)
example x = do
i <- getI
m <- setI (i + x)
return (m, i + x)
Some examples:
*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)
I threw this together pretty quickly, it's rather ugly, and I haven't checked to see whether it obeys any of the Monad laws, so use at your peril! :)