Как реализовать "функциональные" монады в рэкетах, используя модуль data / monad функционала?

Поскольку нотация do модуля данных / монады работает со структурами, как я могу определить типы монад, которые являются функциями, например как парсеры?

Я привык к OCaml, где моя монада имела примерно такую ​​сигнатуру:

module type Parser = sig
  type state = string * int
  type 'a t = state -> (('a * state), string) Result.t

  val return: 'a -> 'a t
  val bind: 'a t -> ('a -> 'b t) -> 'b t
end

Извините, что опубликовал пример в OCaml, мои ракетки пока не очень хороши.

Совместима ли эта монада с данными / монадой, или мне стоит поискать другое решение?

2
0
180
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ничто не мешает вам обернуть функцию в структуру, а затем реализовать интерфейс gen:monad в этой структуре. Библиотека мегапарсака - пример, который использует эту технику для реализации библиотеки комбинатора монадического синтаксического анализатора. В частности, взгляните на определение структуры parser:

(struct parser (proc)
  #:methods gen:functor
  [(define/generic -map map)
   (define (map f p)
     (parser (compose (match-lambda [(consumed (ok v rest message)) (consumed (ok (-map f v) rest message))]
                                    [(empty (ok v rest message))    (empty (ok (-map f v) rest message))]
                                    [error                          error])
                      (parser-proc p))))]

  #:methods gen:applicative
  [(define (pure _ x)
     (pure/p x))

   (define (apply p ps)
     (do [f  <- p]
         [xs <- (map/m values ps)]
         (d:pure (r:apply f xs))))]

  #:methods gen:monad
  [(define (chain f p)
     (parser
      (λ (input)
        (match (parse p input)
          [(empty (ok (and foo (syntax-box x _)) rest message))
           (match (parse (f x) rest)
             [(empty reply) (empty (merge-message/reply message reply))]
             [consumed      consumed])]
          [(consumed (ok (and foo (syntax-box x srcloc)) rest message))
           (consumed (match (parse (f x) rest)
                       [(consumed (ok stx rest message))
                        (ok (merge-syntax-box/srcloc stx srcloc) rest message)]
                       [(empty (ok (syntax-box datum _) rest message))
                        (merge-message/reply message (ok (syntax-box datum srcloc) rest message))]
                       [(consumed error) error]
                       [(empty error) (merge-message/reply message error)]))]
          [error error]))))])

Это определяет тип структуры с именем parser, содержащий одно поле, proc, и реализует интерфейсы gen:functor, gen:applicative и gen:monad для этого типа структуры. Единственное поле содержит процедуру парсера.

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