Как правильно отбросить результат (монадического) вычисления в 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,

Другие вопросы по тегам