Andrea Rossato wrote:
Il Tue, Aug 29, 2006 at 07:45:46AM +0100, Brian Hulley ebbe a
scrivere:
Andrea Rossato wrote:
Il Mon, Aug 28, 2006 at 09:28:02PM +0100, Brian Hulley ebbe a
scrivere:
where the 4th element of the tuple is True iff we can continue or
False iff an exception occurred.

I'm starting to believe that the best method is just take the way
StateT takes... without reinventing the wheel...

The solution I gave was very close to being correct. I enclose a
tested example below - you'll need to adapt it to do evaluation but
it shows an exception being raised.

I said I think that the StateT approach is the one to take only
because I believe that the complexity of the definition of >>= is
getting unmanageable, that is, as far as I understand, contrary to the
spirit of haskell, and functional programming in general.


so, start getting my hands dirty in monadic combinations is probably
the best for improving my knowledge of haskell and functional
programming.
what do you think?

Hi -
Yes I agree the StateT/monad transformer approach is probably best in the long run, since by using the standard monad transformers, you will get code that will scale better to handle more complexities later, and has the advantage of being already tested so you can be sure the resulting monads will obey all the monad laws. Also, there are a lot of tutorials about how to use them to solve different problems.

Just for interest, I enclose another version of the SOIE implementation which I think is closer to what you originally intended. I've used two constructors for the result to avoid having to use (undefined), but the whole function is still wrapped inside a single constructor newtype:

module Test where

import Control.Monad

data Result a
   = Good a State Output
   | Bad State Output
   deriving Show

newtype Eval_SOI a = SOIE {runSOIE :: State -> Result a}

type State = Int
type Output = String

raise e = SOIE (\s -> Bad s e)

instance Monad Eval_SOI where
   return a = SOIE (\s -> Good a s "")

   m >>= f = SOIE $ \x ->
       case runSOIE m x of
           Good a y o1 ->
               case runSOIE (f a) y of
                   Good b z o2 -> Good b z (o1 ++ o2)
                   Bad z o2 -> Bad z (o1 ++ o2)
           Bad z o2 -> Bad z o2  -- (*)


display t = SOIE(\s -> Good () s t)

test = runSOIE (do
  display "hello"
  raise "Exception"
  display "Foo"
 ) 0

(*) This line is essential, because the (Bad z o2) on the lhs has type (Eval_SOI a) whereas the (Bad z o2) on the rhs has type (Eval_SOI b) (given (>>=) :: m a -> (a->m b) -> m b) so something like r@(Bad z o2) -> r would not work, though the hope is that the compiler would manage to optimize out the re-construction that's needed to satisfy the type checker.

I think monads can be quite difficult to understand until you see that they are just quite simple definitions of (return) and (>>=) as above, and understanding how the monad transformers are defined (by reading the source in ...\libraries\mtl\Control\Monad) means you'll be able to use them with absolute confidence rather than having a vague uneasiess that there is some "magic" involved.

Happy monadic explorations! :-)
Brian.
--
Logic empowers us and Love gives us purpose.
Yet still phantoms restless for eras long past,
congealed in the present in unthought forms,
strive mightily unseen to destroy us.

http://www.metamilk.com
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to