questions

Hal Daume III hdaume@ISI.EDU
Tue, 20 Aug 2002 08:37:17 -0700 (PDT)


There are three basic problems here.  The first is the syntax error you
see, the second and third will become available once you fix the syntax
error.

> lexi (a:x)
>          | isLetter a = token: lexi restante
>            where S = takeWhile isLetterorDigit x
> line 20 ------>           restante = dropWhile isLetterorDigit x
>            token = 'Id' ++ S

So, Haskell uses a system of "layout".  THis saves us from writing lots of
braces and parentheses (some people don't like layout and you're free to
do without it -- Ashley will probably post something along these
lines).  The basic idea is that without layout, you would have to write:

  "... where { S = takeWhile isLetterorDigit x ; restante = dropWhile
isLetterorDigit x ... }"

what layout allows you to do is tell the compiler where to insert these
braces and semicolons implicitly.  You do this by verical
alignment.  Basically, if a keywords like 'where' (or 'let' or 'do') is
not followed by a brace, the column number at which the next identifier is
found is remembered.  Henceforth, as long as columns begin at that column
number, they are part of the same where clause.  This might be a bit
tricky to grasp, but the moral is:

  make sure the starting column for the definition of each element in a
where clause is the same.  

so you would write:

> lexi (a:x)
>          | isLetter a = token: lexi restante
>            where S = takeWhile isLetterorDigit x
>                  restante = dropWhile isLetterorDigit x
>                  token = 'Id' ++ S

now, the second problem.  identifiers must begin with lowercase letters,
so this "S" will not do.  According to haskell, things that begin with a
capital letter are type constructors, types, classes.  So you must you
"s" instead of "S".

Finally, the third problem.  You define:

> main = lexi

But this won't work.  The type of lexi (once you get it working) is
'String -> [String]' but the type of main must be 'IO ()'.

Presumably, you want to apply the lexer to stdin and then print the
identifiers out one per line.  You can do this with something like:

  main = interact (unlines . lexi)

The function 'interact' has type

  (String -> String) -> IO ()

and what it does is read from stdin, run what it reads through the string
processing function, and prints the results to stdout.  Now, your function
lexi has type 'String -> [String]', so this won't do.  The function
'unlines' has type:

  [String] -> String

and basically takes the list of strings, puts newlines between them, and
catenates them.

Finally, '.', the composition operator composes the two functions, thus
producing a function of type 'String -> String' as required by interact.

I hope this has made some sense.

 - Hal