2013-11-20 2 views
1

В Haskell, я могу написать:Как правильно сбросить результат (монадической) вычисления в 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 #? Я попытался с помощью делать !, но я получаю сообщение об ошибке (потому что моя >>= функция не принимает блок типа, а «а):

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() в конструктор? Любые идеи, как это сделать правильно? Пример кода?

+0

Вы можете определить '>>', но с другим именем, поскольку оно уже является стандартным оператором. Пример: https://github.com/fsharp/fsharpx/blob/9ad7ff3024b1cc90fd252520272421920c1f4017/src/FSharpx.Core/ComputExpressions/Monad.fs#L779 –

+0

Хорошо, и когда я определил >> под другим именем, что мне делать ? – badbadboy

+0

Вы используете его так же, как и в Haskell. Или используйте 'let! _ = ... ' –

ответ

5

Предполагая, что тип возвращаемого space является Parser<unit> (что имело бы смысл, если он не представляет собой анализатор, который возвращает некоторый результат), вы можете написать:

let token = compose { 
    do! space 
    let! v = parser 
    do! space 
    return v 
} 

Это просто синтаксический сахар для того, что вы написали - так do! e переведен как let! _ = e который, в свою очередь, переведен на parser.Bind(e, fun _ -> ...). У меня есть образец для Additive parsers on Try Joinads, который также определяет Combine и еще несколько (возможно) полезных вещей, но для ключевого слова do! требуется только Bind.

+2

Хорошо, в этом случае пространство - это Parser , поэтому я могу использовать «do!». Но что, если это парсер чего-то другого? Во многих случаях он возвращает что-то полезное, но мне это просто не нужно. В Haskell я просто не привязываю его в этом случае. Каков наилучший способ справиться с этим в F #? Комбинат что-то я должен использовать тогда? – badbadboy

+0

@badbadboy: Даже в этом случае вы можете использовать 'do!', Поскольку документация 'Bind' в выражении вычислений говорит' Called for let! и делай! в выражениях вычислений' – Ankur

+0

Да, но тогда я получаю ошибку компиляции, потому что делаю! вызывает Bind, снабжая его(), в то время как он ожидает другого типа ('a). @ tomas-petricek, любые предложения? – badbadboy

Смежные вопросы