The for-notation extension is an extention to help programming with unique typing. Here is a simple example.
hello f = for f fwrites "your name? " s <- freadline s = chop s fwrites "Hello, " $> s $> newline return
This is interpreted as the following.
hello f = case f of f # f = f |> fwrites "your name? " (s,f) = f |> freadline s = chop s f = f |> fwrites "Hello, " $> s $> newline = f
Basic Rules
Beginning of the notation
The first line of the notation is the following.
... for <expression-1>
This <expression-1> will be used for a hidden object during this for-notation. The scope of this notation is indicated by indent rule.
Simple statement
A simple statement like the following is interpreted to be complemented by the hidden object.
fwrites "your name? "
will be
f = f |> fwrites "your name? "
The '|>' operator is a pipeline operator defined in OptBase module in OptEnv library.
// pipeline operator (|>) infixl 0 //:: .a (.a -> .b) -> .b (|>) a f :== f a
Assign statement
A statement with '<-' is an assign statement and the left variables are complemented by a tuple with the hidden object.
s <- freadline
will be
(s,f) = f |> freadline
Another example is the case when there are two left variables.
ok, i <- freadi
will be
(ok, i, f) = f |> freadi
Bind statement
A statement with '=' is a bind statement and it is interpreted as it is.
s = chop s
Return statement
A statement beggining with 'return' is a return statement and it is the returning statement of the for-notation. It is interpreted as it is the body of the function.
return
will be
= f
If a return statement has some arguments, a tuple with the hidden object complements the statement.
return ok, i
will be
= (ok, i, f)
Guard statement
A line beginning with '|' is a guard. Unlike standard clean syntax, a guard of for-notation must be in a single line and does not allow including a body of the guard.
Body statements follows after the guard line with indentation. The body lines will be also interpreted as a part of for-notation.
ok, i <- freadi | not ok return -1 return i
will be interpreted as
# (ok, i, f) = f |> freadi | not ok = (-1, f) = (i, f)
Auxiliary functions
For-notation can have auxiliary functions. Those functions also have a hidden object as the main part.
for f ok, i <- freadi i <- check ok i return i check False _ fwrites "read error\n" return -1 check True i return i
In the above sample, 'check' function is an auxiliary function of the for-notation. This function is interpreted as the following.
check False _ f # f = f |> fwrites "read error\n" = (-1, f) check True i f = (i, f)
Continue statement
A statement beginning with 'continue' is a continue statement and it is the tail call statement of the for-notation. It is interpreted as it is the body of the function with function call.
continue next_call str
will be interpreted as
= f |> next_call str
Except pattern
A line beginning with '?' is a except pattern. It is used for focusing a main process while handling an exceptional process with an auxiliary function.
for f ? True, i <- freadi return i except False _ fwrites "read error\n" return -1
will be interpreted as
case f of f = case f |> freadi of (True, i, f) = (i, f) (ok, i, f) = except ok i f with except False _ f # f = f |> fwrites "read error\n" = (-1, f)
If some letters or numbers follow the leading '?' without any spaces, it is interpreted as those will be added to the except function name. For example if a leading symbol is '?1' then the except function name is 'except1' and if '?_foo' then 'except_foo.'
Nested for-notation
For-notation can be nested. Here is a sample below.
Start w = for w f <- stdio f = for f fwrites "your name? " s <- freadline fwrites "Hello, " $> s return _ <- fclose f return
The program can also be written as the following.
Start w = for w f <- stdio _ <- for f fwrites "your name? " s <- freadline fwrites "Hello, " $> s continue fclose return
