Re: The dreaded layout rule

1999-07-29 Thread Ian Holyer

This is a multi-part message in MIME format.
--F93F7E72348E2F23CC7D1D40
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Manuel says

 One of our students just pointed out an IMHO rather problematic clause in the  
layout rule ... So, I guess (I hope!!) there is a nifty trick that lets you
 achieve the same effect by using only conditions depending on local
 information ...

Attached is Haskell code which handles the layout rule reasonably well as a
separate pass between scanning and parsing (though it is Haskell 1.4 rather
than 98 and imperfect).
-- 
Ian[EMAIL PROTECTED], http://www.cs.bris.ac.uk/~ian
--F93F7E72348E2F23CC7D1D40
Content-Type: text/plain; charset=us-ascii; name="Layout.hs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="Layout.hs"

{--
LAYOUT ANALYSIS

The layout function deals with the layout conventions of Haskell 1.4, inserting
extra "{", ";" and "}" tokens to represent implicit blocks.  The inserted
tokens are marked as implicit, and are inserted as early as possible in the
token stream, in order to promote well-phrased and well-positioned error
messages in case of trouble.  The layout function never fails; it is left up to
a parser to detect errors.

The Haskell standard says that a block (or layout list) is terminated "whenever
the syntactic category containing the layout list ends, that is, if an illegal
lexeme is encountered at a point where a close brace would be legal".  This can
only be implememented easily if layout processing is combined with parsing.
Here, layout processing is done separately, so an approximation to the standard
is achieved by keeping track of brackets.  See the end of this file for
examples where the layout function deviates from the standard.

ISSUES TO BE RESOLVED

-- "case" terminated by "where" may be common enough to make a special case
-- "case" terminated by "," may be worth dealing with
-- check that "let"s inside "do" (which don't have "in") are handled OK
-- check explicit blocks, and their interaction with implicit ones

Ian Holyer  @(#) $Id: Layout.hs,v 1.2 1998/10/26 15:18:39 ian Exp $
--}

module Layout (layout) where

import Haskell
import Lex

-- Start layout processing.  If the source does not begin with "module" or "{",
-- then there is an implicit surrounding block.  Here and elsewhere, a
-- lookahead past possible comments is done so that a token can be inserted
-- before the comments if necessary; also, the end-of-file token makes it
-- unnecessary to check for an empty token stream.

layout :: [Token] - [Token]
layout ts =
   if s == "module" then comments ++ scanExplicit [] (tok:rest) else
   openBlock [] (Tok "}" 1 0 Implicit) ts
   where
   comments = takeWhile isComment ts
   tok @ (Tok s r c k) : rest = dropWhile isComment ts

-- A stack of tokens is used to keep track of the surrounding blocks.  For each
-- block, its opening "{" token is pushed onto the stack.  In an implicit
-- block, the brackets "(",")" and "[","]" and "case","of" and "let","in" and
-- "if","then","else" are tracked by putting the opening bracket on the stack
-- until the matching closing bracket is found.  Each opening bracket is stored
-- on the stack with the indent for the current block in place of its actual
-- column.

type Stack = [Token]

-- Scan the source tokens while in an explicit block (or while not in any
-- blocks) when layout is inactive.  Look for an explicit close block token, or
-- a keyword which indicates the beginning of a new block. Treat field selector
-- as an explicit block.

scanExplicit :: Stack - [Token] - [Token]
scanExplicit stack [] = []
scanExplicit stack (t@(Tok s r c k) : ts1) = case s of
   "}" - t : closeBlock stack t ts1
   "where" - t : openBlock stack t ts1
   "let" - t : openBlock stack t ts1
   "do" - t : openBlock stack t ts1
   "of" - t : openBlock stack t ts1
   "{" - openBlock stack undefined (t:ts1)
   _ - t : scanExplicit stack ts1

-- Scan the source tokens while in an implicit block, with layout active.  The
-- parameters are the stack, the last token dealt with, and the remaining
-- tokens.  The block is terminated by indenting or by a suitable closing
-- bracket.  Treat field selector as an explicit block.

scanImplicit :: Stack - Token - [Token] - [Token]
scanImplicit stack@(Tok bs br bc bk : stack1) last@(Tok ls lr lc lk) ts =
   if c  bc || k == EndToken then close els

standards and libraries

1998-08-04 Thread Ian Holyer

On the subject of standards, all that is needed from my own personal point of
view is a statement in the Haskell report saying how long the current version
is guaranteed to remain in force.  Why can't we start right now by putting one
on Haskell 1.4, even if it only says "demise imminent"?

On the subject of libraries, the main deficiency to my way of thinking is a
graphics/GUI library.  I am in the process of converting all my C programs to
Java largely because it has such a standard, portable library.  I'm well aware
of the problems of producing one, and I'm not expecting one soon, but it is a
very obvious gap.

Ian[EMAIL PROTECTED], http://www.cs.bris.ac.uk/~ian





Re: Monads and their operational behavior

1997-11-26 Thread Ian Holyer

Koen wrote:

  | Is it possible to write a monad such that this equality holds
  | both denotationally and operationally
  | 
  |   do {x - foo; return x} = foo
  | 
  | For all I know, the answer to this question is 
  | "yes, with sufficient sneakiness".

 Aha! Show us how!!

We tried the two example programs which started this dicussion on a tracer
that Alastair Penney has been developing in Bristol.  As far as we can see,
the problem boils down to a classic known problem: that if you have

   let (x,y) = e in ...

and you compile it naively, and x is evaluated and discarded, then y still
hangs on to (fst e) even though it is no longer needed.  We are not entirely
sure that this is the only problem, but it is clearly one of them.

It also seems to be fairly widely known that this problem cannot, in general,
be eliminated by a source-to-source transformation.

I know of two solutions for handling it.  One is for the compiler to generate
special code for "let (x,y) = e in ..." where the code for evaluating e also
updates x and y appropriately.  The other is for the run time system to look
for opportunities for eliminating indirection-like constructs such as "y = snd
(e1,e2)" either in the garbage collector or in a low-priority background
process.

Ian[EMAIL PROTECTED], http://www.cs.bris.ac.uk/~ian