Simon H
Simon H

Reputation: 21007

State transformer: need a Nothing in a (Maybe Bool)

This is from the nicta course (hence List = [], Optional = Maybe, ...), so I'm not looking for a full solution, but I am stuck on a State Transformer question. The aim is to filter duplicates from a List and completely fail if passed any number > 100.

-- filtering :: Applicative f => (a -> f Bool) -> List a -> f (List a)

distinctF :: (Ord a, Num a) => List a -> Optional (List a)
distinctF lst = case runStateT (filtering go lst) S.empty of
  Full (val, _) -> Full val
  Empty         -> Empty
  where
    --go :: a -> StateT (S.Set a) Optional Bool
    go x = do
      s <- getT
      if x > 100 then do
        return *?*Empty / False*?*

This typechecks while go = undefined, but I'm struggling to put Empty into as return wraps e.g. False in a Full/Just. fail gets me someway forward but I don't think that is the solution.

In practice I am probably missing a more important issue and would welcome enlightenment.

Upvotes: 0

Views: 175

Answers (2)

Simon H
Simon H

Reputation: 21007

OK, so I finally found a way, by realising that I could construct the precisely correct return type, rather than trying to rely on return

  go x = do
    if x > 100 then
      StateT (\_ -> Empty)          -- `return` a fail
    else do
      st <- getT

However, I am still not quite sure how <- unwraps both the StateT and the inner monadic container

Upvotes: 0

phadej
phadej

Reputation: 12133

If the goal is to write function making both: unique filtering and failing on large input at the same time, you got the skeleton quite right:

distinctF :: (Ord a, Num a) => List a -> Optional (List a)
distinctF lst = evalStateT (go lst) S.empty -- evalStateT is your case runStateT part
  where -- on empty input we just return empty list
        go []     = return []
        -- otherwise
        go (x:xs)
          -- we check whether we should 'fail'
          -- for that we *lift* the value from underlying monad (Optional) into our StateT Optional
          | x > 100   = lift $ Empty
          | otherwise = do
            -- the stuff to do
            -- get the state, do nothing if x is in there
            -- otherwise add x to the state and recurse

So for your question, you need to lift Empty, not return it.

Upvotes: 2

Related Questions