[Haskell-cafe] accessible layout proposal?

Jimmy Hartzell jim at shareyourgifts.net
Wed Sep 23 03:11:58 EDT 2009


> On Sep 23, 2009, at 3:04 PM, Evan Laforge wrote:
> Let's not forget what the proposal actually _is_.
> It is that "#(" "#[" "#$" and "#" should become magic
> tokens such that
>
> 	#( {a;b;c}  is read as  (a,b,c)
> 	#[ {a;b;c}  is read as  [a,b,c]
>        f #$ {a;b;c}  is read as  f (a) (b) (c)
>          #  {a;b;c}  is read as  {a,b,c}
>
> [http://www.haskell.org/haskellwiki/Accessible_layout_proposal]
>
> Are you not troubled by the inconsistencies here?

I am indeed. I concede that the proposal in its present form is completely
unacceptable.

How about this (which I believe to be backwards compatible):
* For data-type declarations, simple indentation may be used:

data Tree a
    Leaf a
    Branch (Tree a) (Tree a)
    deriving
         Show -- this bit may be overkill
         Read

* For records, simple indentation is extended:
data Tree a =
   Branch
        left::a
        right::a
   Leaf a

* Export lists are similarly without extra symbols:

module Foo
        Zap
            Con1
            Con2
            Con3
        mkZap
        count
        where

* [~] and (~) introduce newline-separated lists and tuples, respectively:

wrapWithParens str = concat [~]
   "("
   str
   ")"

Ideally, I'd want something even more light-weight, but I can't think of
anything backwards-compatible that satisfies the bracket-matching
requirement (which I also care about, as I don't particularly want to hack
my editor for this layout proposal either).

* For the magic uncurried-function operator, I don't want to have the
monstrosity of $$(~). A simple ~ should do here:

main = between_ ~
    enter a
    exit a
    body a

This is also allowable in data declarations:

data Tree a =
    Branch ~
        Tree a
        Tree a
    Leaf a

I'd also be interested in knowing if any of these seem interesting
separately.

I would personally use this new layout for virtually all datatypes,
records, and long (where long = (> 2) . length) lists and tuples. I would
probably use the '~' notation heavily in writing parsec parsers (the
following based loosely off of code from a compiler for a toy programming
language):

classDeclaration = LiftM4 ClassDeclaration ~
     scopeDesignator
         >>~ keyword "class"
     typeNameDeclaration
     option rootClass $ parens qualifiedConstantName -- look, no parens
     list fieldVariable
         >>~ operator ";"

I like how this version allows me to plainly list the components of a
ClassDeclaration. Certainly, if I was actually designing a programming
language for writing parsers in, I wouldn't require a bunch of parentheses
for productions like this. The fact that, with this proposal, Haskell
would no longer require them I take as a good sign.

(>>~) is defined as per an article I can't seem to find right now:

a >>~ b = do
   res <- a
   b
   return res

Furthermore, a function 'if_ a b c = if a then b else c' would be a lot
more natural to use. I prefer programming languages where an if-function
is as natural to use as the programming language's native 'if', especially
those that have a function to implement the functionality of 'if', as
those languages are usually the most flexible in their control structures
(in Haskell, the only awkwardness with 'if_' at present is syntactic):

if_ $ a < 3 ~
    errorResult "insufficient allocations"
    Right $ f b c

I feel that with the existence of ($), do notation, the significant
whitespace for both do-notation and case statements, Haskell already leans
in the direction of allowing for minor awkwardness and inconsistency to
eliminate parentheses and to make the structure of the program easily
visibly accessible.

Jimmy Hartzell



More information about the Haskell-Cafe mailing list