Reputation: 1796
I'm trying to understand the Reader monad, and I'm following this answer https://stackoverflow.com/a/14179721/10116440 which has this example:
import Control.Monad.Reader
data GameState = NotOver | FirstPlayerWin | SecondPlayerWin | Tie
data Game position
= Game {
getNext :: position -> [position],
getState :: position -> GameState
}
getNext' :: position -> Reader (Game position) [position]
getNext' position
= do game <- ask
return $ getNext game position
getState' :: position -> Reader (Game position) GameState
getState' position
= do game <- ask
return $ getState game position
negamax :: Double -> position -> Reader (Game position) Double
negamax color position
= do state <- getState' position
case state of
FirstPlayerWin -> return color
SecondPlayerWin -> return $ negate color
Tie -> return 0
NotOver -> do possible <- getNext' position
values <- mapM ((liftM negate) . negamax (negate color)) possible
return $ maximum values
The first thing I don't understand is return $ getNext game position
. getNext
, when applied to a game
, returns position -> [position]
. This, when applied to position
, returns [position]
. So the line return $ getNext game position
should returng something other than Reader (Game position) [position]
, I don't know which this something is, because I don't know how the return
is defined for the Reader
monad.
Anyways, which "instance" of the Game
will ask
return? I don't understand, there's none in this code. Also, runReader
is never called, so what are the Reader
results of getNext
, getState
and negamax
used for?
Could someone complete this example with how would runReader
actually be run in this code, and which game
instance is returned by ask
?
Also, why Reader env a
and not simply Reader a
?
Upvotes: 1
Views: 320
Reputation: 7159
There is a plenty of questions in your post – this is quite against StackOverflow rules. Nevertheless, I will answer them one by one:
return $ getNext game position
Indeed, getNext game position
returns something of type [position]
. Now take a look at the return
function — its type is Monad m => a -> m a
. In this case m
is Reader (Game position)
(not Reader (Game position) a
, nor just Reader
! Reader
itself isn't a Monad. Reader something
is). If you instantiate a
to [position]
(as applied) you will get Reader (Game position) [position]
as declared.
Game
will ask
return?ask
is a utility coming from Control.Monad.Reader
. Generally speaking, Reader
is a monad that handles some environment under the hood. ask :: Reader env env
is an action that just results in that environment. For example
runReader ask 123 == 123
So, answering your question, it will return the currently handled game
that is hidden under the Reader
's coat.
I don't know what do you mean by "complete" here, but sample usage of runReader
:
runReader (negamax 1.0 123) Game{getNext = \x -> [x], getState = \x -> NotOver}
Reader env a
and not simply Reader a
Because Reader env
describes a computation with a "background" value of type env
. This would make no sense without env
– the point of Reader
is to have that value and its type needs to be known. If you don't like writing it every time in your case you may write
type GameMonad position = Reader (Game position)
Upvotes: 3