Re: [Haskell] Monadic parser combinators with logging

2006-08-02 Thread Andrew Pimlott
On Thu, Aug 03, 2006 at 08:40:26AM +0200, Harald ROTTER wrote:
> Thanks for the hint, I will try to implement the suggested monadic
> structure.

I realized perhaps I should have made the hint slightly more explicit by
changing the name:

newtype ParserT m a = ParserT { runParserT :: (PState -> m [(a, PState)])}

But I know you would figure it out either way. :-)

> As for the MonadState declaration:
> 
> If I put
>   instance MonadState PState Parser
> 
> then ghci complains:
>   Illegal instance declaration for 'MonadState PState Parser'
> (The instance type must be of form (T a b c)
> where T is not a synonym, and a,b,c are distict type variables)
>   In the instance declaration for 'MonadState PState Parser'
> 
> I found out that invoking ghci with "-fglasgow-exts" solves the issue nut I
> have to admit that I do not really understand what's so special about this
> instance declaration to make it require the extensions.

You would need -fglasgow-exts anyway for a multi-parameter (ie., two
types, PState and Parser) instance.  Haskell 98 has quite limited
support for typeclasses, compared to current practice.  I wouldn't worry
much about the above error--but that said, I suspect your PState is a
type synonym, which as the error message says is forbidden (in Haskell
98).

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Monadic parser combinators with logging

2006-08-02 Thread Andrew Pimlott
On Wed, Aug 02, 2006 at 10:52:14AM +0200, Harald ROTTER wrote:
> newtype Parser a = Parser { runParser :: (PState -> [(a, PState)])}
> 
> as the parsing monad with the Parser state  "PState" that contains the
> remaining input after matching and possibly some additional user defined
> state elements. I want to add logging such that the application of every
> element parser/parser combinator gets recorded in a string. In the end I
> want to print out the trace of all encountered parsers for successful and
> for failed matches.
> 
> I tried to use the WriterT transformer to add a writer monad on top of the
> Parser monad but for failed matches (i.e. runParser gives []) the log is
> also "lost" since WriterT gives a monad of "m (a,w)".

Excellent observation!  The order in which you apply monad transformers
matters.  "WriterT w Parser" keeps a separate output for each branch of
the parser.  If you stare at the definition of (>>=) for WriterT, you'll
see why this must be so.  Or, as you did, you can just look at the type.

> What I would look for is "(m a, w)".

Hmm, that looks like (if m is Parser) a parser plus some output.  I
think you'd rather have an answer plus some output, ie "([(a, PState)],
w)".  Hint:  Consider

newtype Parser m a = Parser { runParser :: (PState -> m [(a, PState)])}

where m is a Monad.

> How can I make the Parser monad given above an instance of MonadState ? (I
> always get kind errors ...)

Did you switch up the order of parameters or something?  I don't get any
error using

instance MonadState Int Parser where ...

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] generic catch in a MonadIO

2006-02-08 Thread Andrew Pimlott
On Wed, Feb 08, 2006 at 12:59:48AM -0500, David Menendez wrote:
> Since the monad transformers in MTL all promote MonadError, you can also
> use throwError and catchError with instances of MonadIO. Currently, the
> error type associated with IO is IOError, not Exception, but it should
> be possible to work around that with a wrapper:

That's still not the same, because the point of Oleg's code seems to be
to catch Exceptions within any CaughtMonadIO.  With your approach, if
there is any ErrorT transformer involved, catchError will catch the
error from the outermost ErrorT, and general Exceptions will escape.
See for example Oleg's test2.

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


[Haskell] Re: System.FilePath survey

2006-02-06 Thread Andrew Pimlott
On Mon, Feb 06, 2006 at 03:36:17PM +, Simon Marlow wrote:
> The reason we can't just go right ahead and do The Right Thing (i.e. 
> introduce a new ADT for FilePaths) is because it touches so much other 
> stuff, including stuff that also needs revising, so it doesn't feel 
> right to just fix the FilePath library.
> 
> Experience with GHC releases has left me with the opinion that it's 
> better to group breaking changes together rather than dribble them out - 
> people only have to modify their code once, and conditional compilation 
> gets fewer cases.
> 
> So I'm of the opinion that introducing an ADT for FilePaths is something 
> that should wait until the I/O library is revised.  In the meantime, we 
> should include a String-based Data.FilePath library in Haskell'.  It's 
> not as elegant, but it's terribly practical, and that's one goal of 
> Haskell'.

I don't see why merely introducing an ADT would break anyone's code, as
there is no existing standard filepath model, therefore no code to
break!  The code I posted works with the current IO library and uses an
ADT.  I also think it has the potential to be compatible with a
redesigned IO library.

I further believe in incremental change when possible.  So if it's
possible to try out a "better" approach to filepaths (whatever "better"
may be) without redesigning IO, IMO that's exactly what we should do.

Now it may be that the need for a filepath library is so great, and
"better" approaches sufficiently untested, that we should use whatever
exists and works right now.  But that is a separate question.

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: Records (was Re: [Haskell] Improvements to GHC)

2005-11-21 Thread Andrew Pimlott
On Sun, Nov 20, 2005 at 08:54:35AM -0500, David Roundy wrote:
> As an aside, what's responsible for the insanity of pattern matching record
> fields being backwards? I'd bar = b to bind b to bar, not the other way
> around... why should record pattern matching use '=' in a manner opposite
> from the rest of Haskell?

Perhaps it's better to think of '=' as asserting equality, than as
binding?

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] line-based interactive program

2005-07-08 Thread Andrew Pimlott
On Fri, Jul 08, 2005 at 02:51:11PM +0100, Colin Runciman wrote:
> >>My interaction depends on the (subtle order of) evaluation of a pure and
> >>total function?
> >>
> Pure, yes; total, no.
> 
> Many important things depend on order of evaluation in lazy programs:
> for example, whether they compute a well-defined value at all!   The
> interleaving of demand in the argument of a function with computational
> progress in its result seems a perfectly natural view of interaction in
> a lazy functional language.  This sort of interaction is what actually
> happens when your function applications are evaluated whether you
> exploit it or not.  I embrace it as part of lazy functional programming;
> you prefer an appeal to something extraneous.

It is one thing to embrace lazy evaluation order, and another to embrace
lazy IO (implemented using unsafeInterleaveIO).  As a relative newcomer
to Haskell, I got the impression that the "interact" style was always a
hack, discarded for good reason in favor of the IO monad.  Is there a
strong case for interact?

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Re: ANNOUNCE: The jhc Haskell compiler.

2005-04-28 Thread Andrew Pimlott
On Wed, Apr 27, 2005 at 03:56:38PM -0700, John Meacham wrote:
> for now, these are equivalent. 
> 
> ghc --make Main.hs -o foo
> jhc Main.hs -o foo
> 
> jhc is effectivly always in --make mode. 

I suggest you make it possible not to operate in --make mode.  A build
system usually wants to know which targets will be built by a command,
but --make makes this hard.  This is a significant problem in the java
world (where javac always works in something like --make mode).  Yes,
you can blame it on dumb build tools, but the problem exists.

Also, processing only one file is desirable for quick compile tests.

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] State, StateT and lifting

2005-03-18 Thread Andrew Pimlott
[I think it is preferred to post this on haskell-cafe.]

On Fri, Mar 18, 2005 at 02:00:37PM -0800, Juan Carlos Arevalo Baeza wrote:
> matchRuleST :: String -> State RuleSet (Maybe Rule)
> makeST :: String -> StateT RuleSet IO ()
> 
>   matchRuleST doesn't really need IO for anything (it just works on the 
> current state "RuleSet"). makeST needs IO (it does file date 
> comparisons, actions on the files, etc... the usual "make" stuff). The 
> problem is how to properly use matchRuleST from makeST.

You might solve this by changing the type of matchRuleST:

matchRuleST :: MonadState RuleSet m => String -> m (maybe Rule)

(This requires -fglasgow-exts, but I don't think there's anything
controversial about non-variables in class constraints.)

>   Then, I decided to try again, and came up with this function:
> 
> liftState :: State s a -> StateT s m a

(I think you left out the constraint (Monad m).)

> liftState s = do
>state1 <- get
>(
>let (result, state) = evalState (do {result <- s; state <- get; 
> return (result, state)}) state1 in do
>put state
>return result
>)

You can turn this into a one-liner if you work on it a bit.  But I would
go with the above.

Aside:  It bugs me that this is not defined by Control.Monad.State
(alongside modify and gets):

state :: MonadState s m => (s -> (a, s)) -> m a

I almost always end up defining it myself and use it to implement other
state transformers.  I would do the same for other monad classes
(Writer, etc): provide a function that captures the general operation.

Andrew
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Do the libraries define S' ?

2004-07-07 Thread Andrew Pimlott
On Wed, Jul 07, 2004 at 01:18:54PM +0100, Graham Klyne wrote:
> There's a pattern of higher-order function usage I find myself repeatedly 
> wanting to use, exemplified by the following:
> 
> [[
> -- combineTest :: (Bool->Bool->Bool) -> (a->Bool) -> (a->Bool) -> (a->Bool)
> combineTest :: (b->c->d) -> (a->b) -> (a->c) -> a -> d
> combineTest c t1 t2 = \a -> c (t1 a) (t2 a)
> 
> (.&.) :: (a->Bool) -> (a->Bool) -> (a->Bool)
> (.&.) = combineTest (&&)

This can be seen as liftM2 on the reader monad ((->) r):

(.&.) = liftM2 (&&)
t1 = (>0) .&. (<=4)
ans = t1 3  == True

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-18 Thread Andrew Pimlott
On Wed, Feb 18, 2004 at 02:45:15PM +0100, Daan Leijen wrote:
> On Wed, 18 Feb 2004 01:11:31 -0500, Andrew Pimlott <[EMAIL PROTECTED]> 
> wrote:
> >After some pondering and fiddling, a version I like:
> >
> >notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
> >notFollowedBy' p= join $  do a <- try p; return (unexpected (show 
> >a))
> >  <|>
> >  return (return ())

Argh, there is still a problem!  When notFollowedBy' fails, it will have
consumed whatever p consumed.  Stupid example:

ab= do  char 'a'
(notFollowedBy' $ do char 'b'; char 'c') 
  <|> do char 'b'; return ()

*Main> parseTest ab "abcd"
parse error at (line 1, column 4):
unexpected 'c'

Last version:

notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
notFollowedBy' p  = try $ join $  do  a <- try p
  return (unexpected (show a))
  <|>
  return (return ())


Try, try again,
Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-18 Thread Andrew Pimlott
On Wed, Feb 18, 2004 at 02:45:15PM +0100, Daan Leijen wrote:
> On Wed, 18 Feb 2004 01:11:31 -0500, Andrew Pimlott <[EMAIL PROTECTED]> 
> wrote:
> >After some pondering and fiddling, a version I like:
> >
> >notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
> >notFollowedBy' p= join $  do a <- try p; return (unexpected (show 
> >a))
> >  <|>
> >  return (return ())
> 
> Great work. Do you think that the library function should
> be fixed with this version? (or can you check it in yourself?)

Thanks!  There is one catch:  I followed Graham's idea of generalizing
the signature (which is orthogonal to my fix).  As per earlier mails,
the signature of the current notFollowedBy

notFollowedBy  :: Show tok => GenParser tok st tok -> GenParser tok st ()
notFollowedBy p  = try (do{ c <- p; unexpected (show [c]) }
   <|> return ()
   )

is rather curious--as if the author knew about the problem,
and required a parser returning tok so no-one would notice.

Actually, maybe the reason is error reporting.  Graham's "show a" might
be confusing (who knows whether a is anything like a representation of
the input?).  It seems you'd like to grab the Expect message out of p,
but I'm not sure if this is possible.

Also, in the tok case, there is a small change in the error message (c
vs [c]).

Even if these are not fixible, they seem to me minor problems compared
with the benefit of a more general type.  So I'm happy with my version
as written.

I'm not set up to check it in, so you should probably do it.  Don't
forget that there is a copy of the code in the documentation.

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-17 Thread Andrew Pimlott
On Tue, Feb 17, 2004 at 04:57:34PM -0500, Andrew Pimlott wrote:
> What about a more prosaic implementation:
> 
> notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
> notFollowedBy' p= do  res <-  do a <- try p; return $ Just a
>   <|>
>   return Nothing
>   case res of Just a  -> unexpected (show a)
>   Nothing -> return ()

After some pondering and fiddling, a version I like:

notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
notFollowedBy' p= join $  do a <- try p; return (unexpected (show a))
  <|>
  return (return ())

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-17 Thread Andrew Pimlott
On Tue, Feb 17, 2004 at 07:48:52PM +, Graham Klyne wrote:
> Thanks!  That got me going, though not with quite what you suggested.
> 
> I ended up with this:
> [[
> notMatching :: Show a => GenParser tok st a -> GenParser tok st ()
> notMatching p = do { a <- try p ; unexpected (show a) } <|> return ()
> ]]
> which does the required job for me.

Oops, that does look better.  I knew the try had to go somewhere.  :-)

The only remaining problem is when p succeeds but does not consume any
input, eg eof.  In this case, the <|> return () cannot distinguish it
from p failing.

I didn't realize at first what a dirty trick this function uses:  It
distinguishes success or failure of p by whether any input from the
first part (before <|> return ()) was consumed.  I don't think it is
possible (or desirable!) to get this approach 100% right:  By "erasing"
the success of p, you lose the information you need.

What about a more prosaic implementation:

notFollowedBy' :: Show a => GenParser tok st a -> GenParser tok st ()
notFollowedBy' p= do  res <-  do a <- try p; return $ Just a
  <|>
  return Nothing
  case res of Just a  -> unexpected (show a)
  Nothing -> return ()

This works for the tests I've tried, but there's one little quirk with
error reporting:

aNoBC = do  char 'a'
notFollowedBy' $ do  char 'b'; char 'c'

*Main> parseTest (aNoBC >> char 'e') "abe"
parse error at (line 1, column 2):
unexpected "e"
expecting "c" or "e"

It seems that parsec both misreports which token is unexpected (should
be "b", and thinks that the failure to match "c" is a problem, even
though notFollowedBy' succeeded.

> Using your version caused the notMatching parser to be equivalent to:
>   return ()
> presumably, because the failure was protected by the try combinator?

Or perhaps more accurately, the success (of p) was protected by the try!
Ie, the unexpected and the try together undid the tell-tale token
consumption of p.

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] Parsec question: attempted 'notMatching' combinator

2004-02-17 Thread Andrew Pimlott
On Tue, Feb 17, 2004 at 06:42:39PM +, Graham Klyne wrote:
> I've attempted to define a Parsec combinator thus:
> 
> [[
> notMatching :: Show a => GenParser tok st a -> GenParser tok st ()
> notMatching p = try ( do { a <- p ; unexpected (show a) } <|> return () )
> ]]

If p fails but consumes some input, return () won't be tried, thus the
whole notMatching will have failed.  The try means that it will not have
consumed any input, but that's no consolation, because notMatching
should have succeeded!  How about:

notMatching p = try ( do { a <- p ; unexpected (show a) } ) <|> return ()

In fact, I think notFollowedBy can be considered to be buggy in the same
way.

notFollowedBy p = try (do{ c <- p; unexpected (show [c]) }
   <|> return ()
  )

It doesn't usually bite, because notFollowedBy takes a parser that
returns a token, and such a parser normally only looks at one token.
But it could look at more:

aNoBC = do  char 'a'
notFollowedBy $ do  char 'b'
char 'c'

Intutively, (aNoBC >> char 'b') should match "abe", but

*Main> parseTest (aNoBC >> char 'b') "abe"
parse error at (line 1, column 2):
unexpected "e"
expecting "c"

If you instead put the try around the do, it works as expected.  So I
conclude that the try simply got put in the wrong place by mistake.

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] ANNOUNCE: HsUnix 1.0.1 - Haskell for Unix Shell Scripting

2004-02-09 Thread Andrew Pimlott
On Mon, Feb 09, 2004 at 07:16:09PM +0100, Volker Wysk wrote:
>   main = mainwrapper $
>  call (execp "cat" ["nosuchfile"] -|- execp "echo" ["hello"])
> 
> This happens to work right. The error is reported via a dynamic exception:
> 
>   ~/src/hsunix/build $ ./test2
>   cat: nosuchfilehello
>   : No such file or directory
>   Process error. process status = Exited (ExitFailure 1)
> 
> However, when using pipes, the exitcode of only one of the involved
> processes can be monitored.

Let me give my frank opinion that, even though it's how shell
scripts have always worked, this should be considered broken.  It is
rather a pain to fix, as you can't implement it in the usual
straightforward way.  You have to fork all subprocesses from the
main process, and do extra work to share the pipes.  If you don't
want to use filehandles extravagantly, you have to do additional
work.  I essentially wrote a mini-OS layer that wraps all fork,
pipe, and open calls, and tries (in a fairly dumb but usually
effective way) to allocate filehandles efficiently.  I can share if
you'd like.  (I found this exercise gave great insight into the
"worse is better" philosophy.)

If you don't change this behavior, at least document it prominently
as a robustness sink!  :-)

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


Re: [Haskell] ANNOUNCE: HsUnix 1.0.1 - Haskell for Unix Shell Scripting

2004-02-09 Thread Andrew Pimlott
On Mon, Feb 09, 2004 at 12:49:28PM +0100, Tomasz Zielonka wrote:
> On Sun, Feb 08, 2004 at 09:36:16PM +0100, Volker Wysk wrote:
> > Error Handling
> > Error handling is one thing which is done much more thoroughly in
> > HsUnix than in shells. Failed programs won't be silently ignored.
> > Dynamic exceptions are used for error handling. Non zero exit codes
> > are thrown as exceptions.
> 
> Most sh derivaties have -e set option, which causes the shell to (taken
> from FreeBSD sh man page):
> 
>   -e errexit
> Exit immediately if any untested command fails in non-interactive
> mode.

It doesn't work.

#!/bin/sh -e
cat nosuchfile | echo hello

This script will exit with status 0 (success).  If you think about
how traditional unix shells are implemented, you will see that they
can't get this right.  (Which proves the non-existence of reliable
non-trivial shell scripts!)

I have my own half-finished shell-in-Haskell that handles this.  I
would be interested to know whether HsUnix does.

Andrew
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell