【发布时间】:2016-02-02 18:09:32
【问题描述】:
如果这个问题的答案是“你做错了”,一定要让我知道一个更合适的方法。我的代码结构如下:
type Res<'T> =
| E of (DC -> 'T)
| V of 'T
现在这种类型主要是直接使用的,有很多内联代码进行手动绑定,这是我试图摆脱的很多样板,所以我想我把它变成一个计算表达式。 map、bind 和 apply 并不难。
State 是通过 DC 进行的,但这样做很麻烦,所以我将其更改为以下内容,这是我在与 state monad 讨论时看到的常见签名。
type Res<'T> =
| E of (DC -> DC * 'T)
| V of 'T
然后我决定将它提升到一个新的水平并引入延迟单子(或最终或其他名称)。所以我改变了我的类型,使其递归:
type Res<'T> =
| E of (DC -> DC * Res<'T>)
| V of 'T
我尝试了以下的一些变体,但不断得到:
当统一 ''a' 和 'Res -> Res'时,结果类型将是无限的
(通常发生在我不调用 return 时,即下面的 Res.E <|)
或者我似乎无法正确输入类型,以下(可以理解)引发类型错误,但我有一个盲点来修复它:
这个表达式的类型应该是'Res',但这里的类型是'DC * Res'。
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
我知道签名应该是('a -> Res<'b>) -> Res<'a> -> XRes<'b>。问题来自正确的递归,至少在我的脑海中。我什至不确定为什么要将结果提供给Res.E,据我所知,k 延续无论如何都应该已经返回此类型。
另外,我目前的return如下(跟随Steve Horsfield):
let result v = Res.V v
但在一些帖子(尤其是hilarious Frankenfunctor)中也注意到了这一点:
let result v = Res.E <| fun dc -> dc, Res.V v
也许我遵循了我不应该遵循的模式,但当时这似乎是个好主意,尤其是在尝试重构大量样板代码并将其替换为计算表达式时,但也许我应该坚持直接评估,它适合我的想法;)。
但我觉得我很接近了……有什么想法吗?
【问题讨论】:
-
在 Haskell 中,当想要同时应用两个 monad 时,使用 Monad Transformers。我不确定这些是否在 F# 中可用(或者它们是否甚至可以在 - 我自己没有实现)中实现。为了理解这个概念,我听说Monad Transformers Step by Step 的论文很好。
-
@paul,谢谢,我去看看。但不知何故,要求有一个一维实现来保持状态 and 对其进行延迟评估似乎并不过分。
-
在 github 上有一个项目可以完成其中的一些工作(我现在找不到它,但我认为它使用 FsControl - 我相信有人记得它
标签: f# monads free-monad recursive-type