Вычисление F # Выражение для создания состояния и отсрочки выполнения - PullRequest
0 голосов
/ 23 декабря 2018

Я хочу построить вычислительное выражение, в котором я могу выразить следующее:

let x = someComputationExpression {
    do! "Message 1"
    printfn "something 1"
    do! "Message 2"
    printfn "something 2"
    do! "Message 3"
    printfn "something 3"
    let lastValue = 4
    do! "Message 4"
    // need to reference values across `do!`
    printfn "something %s" lastValue
}

и иметь возможность взять из x список:

[| "Message 1"
   "Message 2"
   "Message 3"
   "Message 4" |]

без printfn когда-либо вызывается, но с возможностью позже выполнить его (если это имеет смысл).

Это не обязательно должно быть с ключевым словом do!, это может быть yield или return все, что требуется для его работы.

Другими словами, я хочу иметь возможность собирать некоторые состояния в вычислительном выражении и ставить в очередь работу (printfn s), которая может бытьказнен позже.

Я пробовал несколько вещей, но не уверен, что это возможно.

1 Ответ

0 голосов
/ 23 декабря 2018

Сложно найти точное решение по ОП-вопросу.Вместо этого я собираюсь опубликовать некоторый код, который OP, возможно, может настроить в соответствии с потребностями.

Я определяю Result и ResultGenerator

type Result =
  | Direct  of string
  | Delayed of (unit -> unit)

type ResultGenerator<'T> = G of (Result list -> 'T*Result list )

Генератор выдает значение и список прямых и отложенныхзначения, прямые значения - список строк выше, но смешанные с ними являются задержанными значениями.Мне нравится возвращать смешанные, чтобы порядок сохранялся.

Обратите внимание, что это версия того, что иногда называют State монадой.

Помимо компонентов класса CE, таких как bind иПостроители Я создал две функции: прямую и отложенную.

direct используется для создания прямого значения, а delayed задержанное (принимает функцию)

let direct v : ResultGenerator<_> =
  G <| fun rs ->
    (), Direct v::rs

let delayed d : ResultGenerator<_> =
  G <| fun rs ->
    (), Delayed d::rs

Для улучшения читабельности.Я определил задержанные trace функции:

let trace m : ResultGenerator<_> =
  G <| fun rs ->
    (), Delayed (fun () -> printfn "%s" m)::rs

let tracef fmt = kprintf trace fmt

Из примера генератора:

let test =
  builder {
    do! direct "Hello"
    do! tracef "A trace:%s" "!"
    do! direct "There"
    return 123
  }

Был достигнут следующий результат:

(123, [Direct "Hello"; Delayed <fun:trace@37-1>; Direct "There"])

(Задержка будет печататьтрассировка при выполнении).

Надеюсь, что это может дать некоторые идеи о том, как атаковать актуальную проблему.

Полный источник:

open FStharp.Core.Printf

type Result =
  | Direct  of string
  | Delayed of (unit -> unit)

type ResultGenerator<'T> = G of (Result list -> 'T*Result list )

let value v : ResultGenerator<_> =
  G <| fun rs ->
    v,  rs

let bind (G t) uf : ResultGenerator<_> =
  G <| fun rs ->
    let tv, trs = t rs
    let (G u) = uf tv
    u trs

let combine (G t) (G u) : ResultGenerator<_> =
  G <| fun rs ->
    let _, trs = t rs
    u trs

let direct v : ResultGenerator<_> =
  G <| fun rs ->
    (), Direct v::rs

let delayed d : ResultGenerator<_> =
  G <| fun rs ->
    (), Delayed d::rs

let trace m : ResultGenerator<_> =
  G <| fun rs ->
    (), Delayed (fun () -> printfn "%s" m)::rs

let tracef fmt = kprintf trace fmt

type Builder() =
  class
    member x.Bind       (t, uf) = bind t uf
    member x.Combine    (t, u)  = combine t u
    member x.Return     v       = value v
    member x.ReturnFrom t       = t : ResultGenerator<_>
  end

let run (G t) =
  let v, rs = t []
  v, List.rev rs

let builder = Builder ()

let test =
  builder {
    do! direct "Hello"
    do! tracef "A trace:%s" "!"
    do! direct "There"
    return 123
  }

[<EntryPoint>]
let main argv =
  run test |> printfn "%A"
  0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...