1

The following toy example computes nondeterministically a number by calling a function anyFunction, and then keeps only the even choices. How could I write a similar code that keeps the maximum choice instead the even choices? Do I need a different monad stack signature?

anyFunction :: StateT Int [] Int
anyFunction = undefined


test :: StateT Int [] Int
test = do
  s <- anyFunction
  put s
  v <- get
  if even v then return v else mzero
Bob
  • 1,713
  • 10
  • 23
  • 2
    What type do you expect the result to have? Selecting the maximum choice would naturally only produce one result rather than a list, unless you choose all possible maximum values. – Ganesh Sittampalam Aug 04 '14 at 18:35
  • @GaneshSittampalam: If `test'` is the name of the wished function, `runStateT test' 0` would be a list with one element such as `[ (4, 4) ]`. – Bob Aug 04 '14 at 21:12

2 Answers2

2

StateT Int [] Int is probably not what you want here. Expanding the definition we can see that it is Int -> [(Int, Int)]. When we do s <- lift [1, 2, 3, 4], we run multiple stateful actions for each number, and then both the return values and modified states get collected into a list.

This means that this monad can't really compute the maximum of a list using lift, since we have separate states for each number in the list (and each state is invisible to the others).

We're better off with mapM or flipM here with a simple State Int Int:

import Control.Monad
import Control.Monad.State.Strict

test :: State Int Int
test = do
    forM_ [1, 2, 3, 4] $ \n -> do
        modify $ max n
    get

This corresponds directly to the usual imperative counter for computing maximums.

András Kovács
  • 29,931
  • 3
  • 53
  • 99
  • Thank you for your proposal. But, unless I misunderstood it, it does not answer my question. I have edited my question by replacing `s <- [1, 2, 3, 4]` with `s <- anyFunction` in order to make clear that I am not just trying to compute the maximal element of a list. – Bob Aug 04 '14 at 21:04
  • @Bob: for any `anyFunction`, you can't do any computation that requires visible shared state, so no `maximum`, `minimum` or anything that requires dependency between list elements is possible, so what I said in the answer holds just the same. – András Kovács Aug 04 '14 at 21:14
  • Yes, what you say is true for this *particular* monad stack. But there ought to be another one that allows to do what I want. Haskell is Turing-complete, right? ;-) – Bob Aug 04 '14 at 21:20
2

What you want is to "run the [] under the StateT" so to speak, obtaining all the Int results of anyFunction, while preserving the rest of the monad stack as much as possible.

You would like a function with a type similar to StateT Int [] Int -> State Int [Int]. That gets all the Ints so that you can calculate the maximum.

But given your monad stack, your function is difficult to implement. Each branching path of the computation has its own "thread" of state, but when you reduce a StateT Int [] Int to a State Int [Int], which "thread" of state should we keep? There's no solution that looks natural.

Now, imagine that you are working with a ListT (State Int) Int monad stack instead. Here all branches share the same "thread" of state. Specializing runListT, it has the signature ListT (State Int) Int -> State Int [Int].

The example could be written as follows:

anyFunction :: ListT (State Int) Int
anyFunction = undefined

test :: ListT (State Int) Int
test = do
  -- preserve non-ListT parts of the stack
  -- and re-wrap the result into a list
  s <- ListT $ liftM (\l -> [maximum l]) $ runListT anyFunction
  put s
  v <- get
  if even v then return v else mzero
danidiaz
  • 26,936
  • 4
  • 45
  • 95