如果这个问题的答案是“你做错了”,一定要让我知道一个更合适的方法。我的代码结构如下:
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<'a> -> Res<'b>' 时,结果类型将是无限的
(通常在我不调用return时发生,即Res.E <|
以下)
或者我似乎无法正确输入类型,以下(可以理解)引发类型错误,但我有一个盲点来修复它:
此表达式应具有类型“Res<'a>”,但此处具有类型“DC * Res<'a>”。
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
延续应该已经返回这种类型。
另外,我目前的回报如下(跟随史蒂夫霍斯菲尔德):
let result v = Res.V v
但在一些帖子(特别是热闹的 Frankenfunctor )中也注意到了这一点:
let result v = Res.E <| fun dc -> dc, Res.V v
也许我遵循了我不应该遵循的模式,但当时这似乎是个好主意,尤其是在尝试重构大量样板代码并用计算表达式替换它时,但也许我应该坚持直接评估,它适合在我脑海中 ;)。
但我觉得我很接近......有什么想法吗?