I\'m implementing a combinatorial optimization algorithm in Haskell:
Given an initial candidate solution, repeat until stopping criteria are met:
1. Determine
Here's a pseudocodey sketch of how you might use the State monad to thread the search state through the computation:
import Control.Monad.State
type SearchState = ...
type Move = ...
type Fitness = ...
determineMoves :: State SearchState [Move]
determineMoves = do
-- since determineMoves is in the State monad, we can grab the state here
st <- get
...
evaluateMoves :: [Move] -> [(Move, Fitness)]
evaluateMoves = ...
chooseMove :: [(Move, Fitness)] -> Move
chooseMove = ...
-- makeMove is not itself monadic, but operates on the SearchState
-- type we're threading through with the State monad
makeMove :: Move -> SearchState -> SearchState
makeMove m st = ...
loop :: State SearchState ()
loop = do
moves <- determineMoves
let candidates = evaluateMoves moves
move = chooseMove candidates
-- we pass a function (SearchState -> SearchState) to modify in
-- order to update the threaded SearchState
modify (makeMove move)
loop
Notice that even though your main computation is in the state monad, not every component has to be in the monad. Here, evaluateMoves
and chooseMove
are non-monadic, and I've used let
to show you how to explicitly integrate them into a do
block. Once you get comfortable with this style, though, you'll probably want to get comfortable using <$>
(aka fmap
) and function composition to get more succinct:
loop :: State SearchState ()
loop = do
move <- (chooseMove . evaluateMoves) <$> determineMoves
modify (makeMove move)
loop