F# 试图让bind为State和Delayed monad的组合工作
如果答案是“你完全错了”,请务必让我知道一个更恰当的方法。我有这样的代码结构:F# 试图让bind为State和Delayed monad的组合工作,f#,monads,free-monad,recursive-type,F#,Monads,Free Monad,Recursive Type,如果答案是“你完全错了”,请务必让我知道一个更恰当的方法。我有这样的代码结构: type Res<'T> = | E of (DC -> 'T) | V of 'T 但也注意到一些帖子(尤其是 让结果v=Res.E dc,Res.v 也许我遵循的是一种我不应该遵循的模式,但在当时这似乎是一个好主意,特别是在试图重构无数样板代码并用计算表达式替换它时,但也许我应该坚持直接求值,它适合我的头脑;) 但我觉得我很接近。。。有什么想法吗 我不太确定这个单子是什么意思
type Res<'T> =
| E of (DC -> 'T)
| V of 'T
但也注意到一些帖子(尤其是
让结果v=Res.E dc,Res.v
也许我遵循的是一种我不应该遵循的模式,但在当时这似乎是一个好主意,特别是在试图重构无数样板代码并用计算表达式替换它时,但也许我应该坚持直接求值,它适合我的头脑;)
但我觉得我很接近。。。有什么想法吗 我不太确定这个单子是什么意思,但是好的,在仔细考虑并阅读了问题的标题:-)之后,我确实理解了它的含义,并且我可以看到如何为它构建
bind
您的错误是,Res.E
中包装的函数应该返回一个元组,但您让它只返回Res'b Res)(Res:'a Res:'b Res=
匹配
|V a->k a
|E->
E
设dc',res'=e dc
dc',绑定k res'
我不认为晚期病例也应该延迟。也就是说,我看不出有什么理由。据我所知,对
vx
情况的解释应该是“一个不改变状态并返回x
”的计算,在这种情况下,使其延迟只会增加一个额外的lambda表达式。在Haskell中,当一个人想要同时应用两个Monad时,他使用Monad转换器。我不确定这些在F#中是否可用(或者它们是否可以在中实现——我自己还没有实现)。为了弄清楚这个概念,我听说这篇论文很好。@paul,谢谢,我来看看。但不知何故,要求一个一维的实现来保持stateá并对其进行延迟评估似乎并不过分。github上有一个项目完成了其中的一部分(我现在找不到它,但我认为它使用了-我肯定有人记得它Hanks,你是对的,这很有效!我没有(去)tupling;)。至于它的含义,我之所以使用嵌套类型,是因为这里有关于构造延迟monad(带单位参数)的建议。在元组中添加的dc
参数和是一个状态,该状态随每次执行一起标记并弹出/推送。它遵循(如果我做得正确的话)状态单子的模式。整个过程是两者的结合。顺便说一句,我不完全确定它现在是否仍然是尾部递归的,因为递归调用bind
现在取决于edc
的结果。但是,因为这本身不是递归的,所以我可能是安全的(虽然这里的深度不是可笑的深,但最终可能无关紧要)。第二,我不认为在这个定义下,你能使它成为尾部递归的,但好消息是,如果你仔细想想,这个东西实际上根本不是递归的。尽管它在bind
的定义中调用bind
,但该调用并不是真正的“递归”,因为bind
不将自身作为其自身评估的一部分进行调用。相反,它返回一个闭包,再次调用bind
进行编辑。是的,你完全正确。虽然它是递归的(rec
关键字),但它使用continuations,这就是编写这种绑定表达式的全部思想。在计算时,闭包被递归地扩展/调用,但正如您所说,这最终不是真正的递归;)。顺便说一句,乔恩·哈洛普曾经告诉我,通常,通过使用连续体,一切都可以通过尾部递归实现。乔恩·哈洛普是正确的。但要做到这一点,你最终会得到一种不同的类型。这就是为什么我说“在这个定义下不能使尾部递归”。
type Res<'T> =
| E of (DC -> DC * 'T)
| V of 'T
type Res<'T> =
| E of (DC -> DC * Res<'T>)
| V of 'T
let rec bind k res =
match res with
| Res.V v -> k v // not delayed, should it be?
| Res.E e ->
Res.E <| fun dc -> bind k (e dc) // here's my error, on 'e dc'
//(fun dc -> dc, bind f (e dc))
bind k res
let result v = Res.V v
let result v = Res.E <| fun dc -> dc, Res.V v
let rec bind (k: 'a -> 'b Res) (res: 'a Res) : 'b Res =
match res with
| V a -> k a
| E e ->
E <| fun dc ->
let dc', res' = e dc
dc', bind k res'