消除我通过像,单子和东西传递的显式状态 [英] Eliminating my explicit state passing via like, monads and stuff

查看:121
本文介绍了消除我通过像,单子和东西传递的显式状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过F#中的这本书(我很清楚,这很奇怪)。对于他们的第一个示例文本冒险,他们利用全局变量变异,我想避免它。我的monad-fu很弱,所以现在我做的丑陋状态就是这样传递的:

 让pickUp玩家的东西:Map< Location,Thing list>)= 
let objs = objects。[player.Location]
let attempt = objs |> List.partition(fun o - > o.Name = thing)

|匹配尝试[],_ - > 你不能得到那个。,玩家,objs
|东西:: _,东西 - >
let player'= {player with objects = thing :: player.Objects}
let msg = sprintf您现在正在携带%s%sthing.Article thing.Name
msg,玩家',东西

让玩家= {Location = Room; Objects = []}

let objects =
[Room,[{Name =whiskey;文章=一些}; {名称=桶; Article =a}];
花园,[{Name =chain;文章=长度}]]
|> Map.ofList

让msg,p',o'= pickUp playerbucketobjects
//等等

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

如果您想要使用状态monad通过 pickUp 函数对玩家的库存和世界状态进行线索,可以采用以下一种方法:

  type State <'s,'a> =('s  - >'a *'s)的状态

类型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)= vs
let(State v')= fa
v's)

让withState< s> = StateBuilder(s)()

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

让runState(State f)init = f init

type Location = Room |花园
类型Thing = {Name:string; Article:string}
type Player = {Location:Location;对象:物品清单}

让pick up thing =
withState {
let! (player,objects:Map< _,_>)= getState
let objs = objects。[player.Location]
let attempt = objs |> List.partition(fun o - > o.Name = thing)

|匹配尝试[],_ - >
返回你无法得到。
|东西:: _,东西 - >
let player'= {player with objects = thing :: player.Objects}
let object'= objects.Add(player.Location,things)
let msg = sprintfYou are now携带%s%s的东西。文章thing.Name
做! putState(player',objects')
return msg
}

let player = {Location = Room; Objects = []}
let objects =
[Room,[{Name =whiskey;文章=一些}; {名称=桶; Article =a}]
Garden,[{Name =chain;文章=长度}]]
|> (msg,(player',objects'))=
(player,objects)
|> Map.ofList

let runState(pickUpbucket)


I'm working through the book Land of Lisp in F# (yeah weird, I know). For their first example text adventure, they make use of global variable mutation and I'd like to avoid it. My monad-fu is weak, so right now I'm doing ugly state passing like this:

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.

How can I factor out the explicit state to make it prettier? (Assume I have access to a State monad type if it helps; I know there is sample code for it in F# out there.)

解决方案

If you want to use the state monad to thread the player's inventory and world state through the pickUp function, here's one approach:

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")

这篇关于消除我通过像,单子和东西传递的显式状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆