(Не сумев «нащупать» FParsec, я последовал совету, который где-то читал, и сам начал пытаться написать небольшой синтаксический анализатор. Каким-то образом я заметил то, что выглядело как шанс попытаться монадифицировать его, и теперь у меня N проблем. ..)
Это мой тип "Результат" (упрощенный)
type Result<'a> =
| Success of 'a
| Failure of string
Вот построитель вычислительных выражений
type ResultBuilder() =
member m.Return a = Success(a)
member m.Bind(r,fn) =
match r with
| Success(a) -> fn a
| Failure(m) -> Failure(m)
В этом первом примере все работает (компилируется), как ожидалось:
module Parser =
let res = ResultBuilder()
let Combine p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
return fn(x,y) }
Моя проблема здесь: я хотел бы иметь возможность уловить любой сбой в функции «комбинирования» и вернуть сбой, но в нем говорится, что я должен определить «ноль».
let Combine2 p1 p2 fn =
fun a -> res { let! x = p1 a
let! y = p2 a
try
return fn(x,y)
with
| ex -> Failure(ex.Message) }
Не имея представления, что мне вернуть в Zero, я просто бросил member m.Zero() = Failure("hello world")
, и теперь он говорит, что мне нужно TryWith
.
So:
member m.TryWith(r,fn) =
try
r()
with
| ex -> fn ex
А теперь ему нужна задержка, так что member m.Delay f = (fun () -> f())
.
Тут написано (на ex -> Failure
) This expression should have type 'unit', but has type 'Result<'a>'
, и я вскидываю руки и поворачиваюсь к вам, ребята ...
Ссылка для игры: http://dotnetfiddle.net/Ho1sGS