[Haskell-cafe] Compiler's bane

Jonathan Cast jonathanccast at fastmail.fm
Thu Sep 4 13:50:24 EDT 2008


On Thu, 2008-09-04 at 18:41 +0100, Andrew Coppin wrote:
> Ryan Ingram wrote:
> > It's pretty simple, I think.
> >
> > type ExpGen = ReaderT [String] Gen
> >
> > arbExp :: ExpGen Expression
> > -- exercise for the reader
> >
> > instance Arbitrary Expression where
> >     arbitrary = runReaderT arbExp []
> >     coarbitrary = coarbExp
> >
> > coarbExp (Var s)      = variant 0 . coarbitrary s
> > coarbExp (Apply a b)  = variant 1 . coarbitrary a . coarbitrary b
> > coarbExp (Lambda s e) = variant 2 . coarbitrary s . coarbitrary e
> >
> > instance Arbitrary Char where
> >   arbitrary   = elements "abcdefghijklmnopqrstuvwxyz_"
> >   coarbitrary = coarbitrary . fromEnum
> >   
> 
> o_O
> 
> I love the way other people have wildly different ideas of "simple" than 
> me. I'm staring at this and completely failing to comprehend it. (But 
> then, anything with "co" in the name generally makes little sense to 
> me...) Why on earth would you need a reader monad? Surely if you want to 
> add bound variables and then later query what variables are bound, you'd 
> want a state monad? Hmm, I'm completely lost here.

Motto (off-the-cuff): State monads are for APIs with function names like
`set'; reader monads are for APIs with function names like `with'.  In
this case, you definitely do not want to bring names into scope with

  bringNameIntoScope :: Name -> ExpGen ()

because then you'd just have to implement

  bringNameOutofScope :: Name -> ExpGen ()

and remember to call it after you've generated the body of the lambda,
except that you have to check before bringing the name into scope
whether it's already in scope and if so make sure it's still in scope
afterwards.

A simpler alternative is to pull out the entire scope, using get, save
it off, modify the state, and then put it back later:

  withNameInScope :: Name -> ExpGen alpha -> ExpGen alpha
  withNameInScope name a = do
    scope <- get
    modify (name:)
    x <- a
    set scope
    return x

But by adopting that API, you're suggesting the use of a reader monad to
implement scoping, since withNameInScope would then be just

  withNameInScope name = local (name:)

jcc

http://haskell.org/ghc/docs/latest/html/libraries/mtl/Control-Monad-Reader-Class.html#v%3Alocal




More information about the Haskell-Cafe mailing list