Как правильно отбросить результат (монадического) вычисления в F#
В Хаскеле я могу написать:
token: Parser a -> Parser a
token p = do space
v <- p
space
return v
В F# я зашел так далеко:
let token = compose {
let! _ = space
let! v = parser
let! _ = space
return v
}
Другими словами, я должен представить это неиспользованное let! _ =
привязка для сброса значения парсера "пробела" парсера (монады), который мне не нужен.
Как избежать этих бесполезных привязок в F#? Я пытался использовать do!, но я получаю ошибку (потому что мой >>=
функция не принимает единицу типа, но 'a):
let (>>=) (p: Parser<'a>) (f: 'a -> Parser<'b>) : Parser<'b>
Вот мое определение строителя:
type ParserComposer() =
member x.Bind(p, f) = p >>= f
member x.Return(y) = ret y
member x.Zero() = failure
Мне нужно определить >>
функционировать? Добавить Combine() к строителю? Есть идеи, как это сделать правильно? Пример кода?
1 ответ
Предполагая тип возвращаемого значения space
является Parser<unit>
(что имеет смысл, если он не представляет синтаксический анализатор, который возвращает некоторый результат), вы можете написать:
let token = compose {
do! space
let! v = parser
do! space
return v
}
Это просто синтаксический сахар для того, что вы написали - так do! e
переводится как let! _ = e
который, в свою очередь, переведен на parser.Bind(e, fun _ -> ...)
, У меня есть пример для парсера Additive на Try Joinads, который также определяет Combine
и еще несколько (возможно) полезных вещей, но do!
нужны только ключевые слова Bind
,