F# F中的随机/状态工作流#
我正试图用F#来概括mon-,呃,工作流,虽然我认为我对基本的“可能”工作流有着非常扎实的理解,但试图实现一个状态工作流来生成随机数确实让我感到困惑 我未完成的尝试可以在这里看到:F# F中的随机/状态工作流#,f#,state,monads,state-monad,F#,State,Monads,State Monad,我正试图用F#来概括mon-,呃,工作流,虽然我认为我对基本的“可能”工作流有着非常扎实的理解,但试图实现一个状态工作流来生成随机数确实让我感到困惑 我未完成的尝试可以在这里看到: let randomInt state = let random = System.Random(state) // Generate random number and a new state as well random.Next(0,1000), random.Next() type
let randomInt state =
let random = System.Random(state)
// Generate random number and a new state as well
random.Next(0,1000), random.Next()
type RandomWF (initState) =
member this.Bind(rnd,rest) =
let value, newState = rnd initState
// How to feed "newState" into "rest"??
value |> rest
member this.Return a = a // Should I maybe feed "initState" into the computation here?
RandomWF(0) {
let! a = randomInt
let! b = randomInt
let! c = randomInt
return [a; b; c]
} |> printfn "%A"
编辑:真的让它工作了!虽然不太清楚它是如何工作的,所以如果有人想给出一个好的答案,它仍然可以被利用。这是我的工作代码:
type RandomWF (initState) =
member this.Bind(rnd,rest) =
fun state ->
let value, nextState = rnd state
rest value nextState
member this.Return a = fun _ -> a
member this.Run x = x initState
有两件事使您更难了解您的工作流程:
type Random<'a> =
Comp of (int -> 'a * int)
let run init (Comp f) = f init
type Random<'a> with
member this.Run(state) = fst <| run state this
type RandomBuilder() =
member this.Bind(Comp m, f: 'a -> Random<_>) =
Comp <| fun state ->
let value, nextState = m state
let comp = f value
run nextState comp
member this.Return(a) = Comp (fun s -> a, s)
let random = RandomBuilder()
type Random(随机)=
公司
let值,nextState=m状态
设comp=f值
运行下一个州公司
成员返回(a)=Comp(乐趣s->a,s)
让random=RandomBuilder()
以下是您如何使用它:
let randomInt =
Comp <| fun state ->
let rnd = System.Random(state)
rnd.Next(0,1000), rnd.Next()
let rand =
random {
let! a = randomInt
let! b = randomInt
let! c = randomInt
return [a; b; c ]
}
rand.Run(0)
|> printfn "%A"
let randomInt=
公司
设rnd=System.Random(状态)
rnd.Next(01000),rnd.Next()
让兰德=
随机的{
设!a=randomInt
设!b=randomInt
设!c=randomInt
返回[a;b;c]
}
rand.Run(0)
|>printfn“%A”
在这个版本中,分别构建计算(并将其存储在Random类型中),然后以初始状态运行它。查看生成器方法上的类型是如何推断的,并将它们与描述的类型进行比较
编辑:一次构造一个构建器对象并使用绑定作为排序别名基本上是惯例,但构建器是无状态的是合理的。我可以理解为什么参数化构建器看起来是一个有用的特性,但我不能诚实地想象它有一个令人信服的用例
monad的主要卖点是将计算的定义和执行分离开来
在您的例子中,您希望能够做的是获取您的计算的表示,并能够使用某种状态运行它—可能是0,可能是42。您不需要知道初始状态就可以定义将使用它的计算。通过将状态传递给构建器,最终会模糊定义和执行之间的界限,这只会降低工作流的实用性
与
async
workflow相比,当您编写一个异步块时,您不会使代码异步运行。您只创建了一个Async,有两件事使您更难看到您的工作流在做什么:
您正在使用函数类型作为monad的类型
您的工作流不仅构建了计算,还运行了计算
我认为,一旦你看到没有这两个障碍的情况下它会是什么样子,你就可以更清楚地理解它。以下是使用DU包装器类型定义的工作流:
type Random<'a> =
Comp of (int -> 'a * int)
let run init (Comp f) = f init
type Random<'a> with
member this.Run(state) = fst <| run state this
type RandomBuilder() =
member this.Bind(Comp m, f: 'a -> Random<_>) =
Comp <| fun state ->
let value, nextState = m state
let comp = f value
run nextState comp
member this.Return(a) = Comp (fun s -> a, s)
let random = RandomBuilder()
type Random(随机)=
公司
let值,nextState=m状态
设comp=f值
运行下一个州公司
成员返回(a)=Comp(乐趣s->a,s)
让random=RandomBuilder()
以下是您如何使用它:
let randomInt =
Comp <| fun state ->
let rnd = System.Random(state)
rnd.Next(0,1000), rnd.Next()
let rand =
random {
let! a = randomInt
let! b = randomInt
let! c = randomInt
return [a; b; c ]
}
rand.Run(0)
|> printfn "%A"
let randomInt=
公司
设rnd=System.Random(状态)
rnd.Next(01000),rnd.Next()
让兰德=
随机的{
设!a=randomInt
设!b=randomInt
设!c=randomInt
返回[a;b;c]
}
rand.Run(0)
|>printfn“%A”
在这个版本中,分别构建计算(并将其存储在Random类型中),然后以初始状态运行它。查看生成器方法上的类型是如何推断的,并将它们与描述的类型进行比较
编辑:一次构造一个构建器对象并使用绑定作为排序别名基本上是惯例,但构建器是无状态的是合理的。我可以理解为什么参数化构建器看起来是一个有用的特性,但我不能诚实地想象它有一个令人信服的用例
monad的主要卖点是将计算的定义和执行分离开来
在您的例子中,您希望能够做的是获取您的计算的表示,并能够使用某种状态运行它—可能是0,可能是42。您不需要知道初始状态就可以定义将使用它的计算。通过将状态传递给构建器,最终会模糊定义和执行之间的界限,这只会降低工作流的实用性
与async
workflow相比,当您编写一个异步块时,您不会使代码异步运行。您只创建了一个async,您的问题是什么?如何修复它?或者一般来说如何构造这样的monad/工作流。下面是state monad如何工作的一个很好的描述。它有点长(3部分),但值得一读。也许这会有帮助啊,我喜欢FSharp的乐趣和利润!实际上,在编写这段代码时,我一直在研究以下系列:。谢谢你的链接!通过使用生成的数字播种下一个随机数,您可能最终进入循环。即随机(123)。下一个(01000)。下一个()==123。这将是很好的,从随机种子,但它没有暴露。最好的替代方法是滚动您自己的Random类,或者使用Random可序列化的事实,将其序列化,并将该字符串传入传出。您的问题是什么?如何修复它?或者一般来说如何构造这样的monad/工作流。下面是state monad如何工作的一个很好的描述。它有点长(3部分),但值得一读。也许这会有帮助啊,我喜欢FSharp的乐趣和利润!实际上,在编写这段代码时,我一直在研究以下系列:。谢谢你的链接!通过使用生成的数字播种下一个随机数,您可能最终进入循环。