我正在研究《 F#中的Lisp之地》(是的,很奇怪,我知道)。对于第一个示例文本冒险,他们利用了全局变量突变,我想避免这种情况。我的monad-fu很虚弱,所以现在我正在像这样通过丑陋的状态传递信息:

let pickUp player thing (objects: Map<Location, Thing list>) =
    let objs = objects.[player.Location]
    let attempt = objs |> List.partition (fun o -> o.Name = thing)
    match attempt with
    | [], _ -> "You cannot get that.", player, objs
    | thing :: _, things ->
        let player' = { player with Objects = thing :: player.Objects }
        let msg = sprintf "You are now carrying %s %s" thing.Article thing.Name
        msg, player', things

let player = { Location = Room; Objects = [] }

let objects =
    [Room, [{ Name = "whiskey"; Article = "some" }; { Name = "bucket"; Article = "a" }];
    Garden, [{ Name = "chain"; Article = "a length of" }]]
    |> Map.ofList

let msg, p', o' = pickUp player "bucket" objects
// etc.

如何排除显式状态使其更漂亮? (假设有帮助,我可以访问State monad类型;我知道那里有F#中的示例代码。)

最佳答案

如果您想使用状态单子(monad)通过pickUp函数来处理玩家的库存和世界状态,这是一种方法:

type State<'s,'a> = State of ('s -> 'a * 's)

type StateBuilder<'s>() =
  member x.Return v : State<'s,_> = State(fun s -> v,s)
  member x.Bind(State v, f) : State<'s,_> =
    State(fun s ->
      let (a,s) = v s
      let (State v') = f a
      v' s)

let withState<'s> = StateBuilder<'s>()

let getState = State(fun s -> s,s)
let putState v = State(fun _ -> (),v)

let runState (State f) init = f init

type Location = Room | Garden
type Thing = { Name : string; Article : string }
type Player = { Location : Location; Objects : Thing list }

let pickUp thing =
  withState {
    let! (player, objects:Map<_,_>) = getState
    let objs = objects.[player.Location]
    let attempt = objs |> List.partition (fun o -> o.Name = thing)
    match attempt with
    | [], _ ->
        return "You cannot get that."
    | thing :: _, things ->
        let player' = { player with Objects = thing :: player.Objects }
        let objects' = objects.Add(player.Location, things)
        let msg = sprintf "You are now carrying %s %s" thing.Article thing.Name
        do! putState (player', objects')
        return msg
  }

let player = { Location = Room; Objects = [] }
let objects =
  [Room, [{ Name = "whiskey"; Article = "some" }; { Name = "bucket"; Article = "a" }]
   Garden, [{ Name = "chain"; Article = "a length of" }]]
  |> Map.ofList

let (msg, (player', objects')) =
  (player, objects)
  |> runState (pickUp "bucket")

关于f# - 消除了我通过诸如monads之类的东西传递的明确状态,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5184583/

10-16 20:56