Код выглядит довольно хорошо для меня.
Я не уверен, было ли это вашим намерением или совпадением, но вы реализуете что-то очень похожее на «комбинаторы синтаксического анализа», что является темой многих научных работ :-).Я думаю, что Monadic Parser Combinators вполне читабелен (в Haskell есть примеры, но вы должны быть в состоянии перевести их на F #).
Что касается оператора композиции функций.Я вообще не большой поклонник слишком частого использования оператора, потому что он часто запутывает код.Однако в вашем примере это имеет смысл, поскольку вы легко можете представить, что >>
означает «за этой группой должна следовать эта группа», что легко интерпретировать.
Единственное незначительное изменение, которое я хотел быДля этого нужно выбрать хороший пользовательский оператор для операции disjunction
и определить еще несколько примитивных операций, чтобы вы могли написать, например, следующее:
// Test against several terms in sequence
let sequence terms = (fun state -> terms |> Seq.fold (>>) state)
// Test for a substring
let substring s = sequence [ for c in s -> term (set [c]) ]
let test = // (abc|xyz)a{2,3}bc
( substring "abc" <|> substring "xyz" )
>> quantify 2 3 (term (set "a")) // (a{2,3})
>> substring "bc" // bc
Это более высокоуровневое описание, поэтомуудаляет некоторые операторы >>
в пользу функций, которые являются более описательными (и инкапсулируют >>
).Я также изменил quantify
, чтобы принимать несколько аргументов вместо тройки (что является незначительным изменением)
Если вы хотите поиграть с этим дальше, тогда вы можете взглянуть на статью и попробовать написать F #конструктор выражений вычислений, позволяющий использовать синтаксис parser { .. }
.