I'm writing a toy compiler, which is in a very early stage of development. The lexer contains the following block of code:
let consumeChar (state: LexerState) =
match state.CurrentChar() with
| End -> state
| _ -> { state with Offset = state.Offset + 1u }
let tryConsume (ch: char) (state: LexerState) =
if state.CurrentChar() = Regular ch
then Success <| consumeChar state
else Failure state
// ...
let onForwardSlash() =
let onUnterminatedMLComment = ...
state |> consumeChar
// Line comment
|> tryConsume '/'
|> andThenSuccess (consumeToEndOfLine >> lexToken)
// Multiline comment
|> orElse (tryConsume '*'
>> andThen (consumeTo "*/"
>> andThenSuccess lexToken
>> orElseSuccess onUnterminatedMLComment))
// Just a forward slash
|> orElseSuccess (LexingResult.T (Punctuator Slash) start)
Where andThen
, orElse
and friends are defined like this:
type TryResult<'fail, 'res> =
| Failure of 'fail
| Success of 'res
let orElse next tryResult =
match tryResult with
| Success res -> Success res
| Failure cont -> next cont
let andThen next tryResult =
match tryResult with
| Success cont -> next cont
| Failure fail -> Failure fail
let orElseSuccess f tryResult =
match tryResult with
| Success res -> Success res
| Failure cont -> Success <| f cont
let andThenSuccess f tryResult = ...
I arrived at this code "naturally" while trying to reduce duplication in the previous version. And the current version is shorter and seems less noisy indeed.
A little later, I stumbled across a blog post which discourages point-free style of programming.
And my code seems to be in a style quite similar to point-free. So it got me thinking. Briefly looking through the sources of FAKE, Paket, Suave, and FSharp compiler itself, they seem to keep function composition usage to a minimum.
Hence the question: Is the onForwardSlash
function's code abusing function composition/point-free style?
(I know about FsLexxYacc and FParsec. This question is about code style, not implementing a lexer)