为什么该计算表达式构建器期望“单位"为1?在我的for循环中? [英] Why does this computation expression builder expect "unit" in my for loop?

查看:69
本文介绍了为什么该计算表达式构建器期望“单位"为1?在我的for循环中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是对

此版本允许我以前无法做的事情,例如:

let stuff = 
    listBuilder {
        let x = 5 * 47
        printfn "hey"
        add x
        addMany [x .. x + 10]
    } |> build

但是,我仍然在此方面遇到编译器错误:

let stuff2 =
    listBuilder {
        for x in 1 .. 50 do
            add x            
    } |> build

在这种情况下,IDE将在for x in中的x下划线并告诉我:该表达式应该具有unit类型,但此处具有int类型."

对我来说还不是很清楚,为什么期望循环变量是unit类型.显然,我在某个地方有错误的方法签名,并且我怀疑我没有在应该到达的每个位置传递我的累积状态,但是编译器错误实际上并不能帮助我缩小出错地方.任何建议,将不胜感激.

解决方案

直接原因是您的While函数限制了body的类型.但是,通常,您不能在同一计算表达式中同时使用自定义操作和控制流操作符,因此,即使您修复了签名,我也不认为您将能够完全按照自己的意愿进行操作.

This is a follow-up question to this question.

I'm trying to create a computation expression builder that accumulates a value through custom operations, and also supports standard F# language constructs at the same time. For the purposes of having a simple example to talk about, I'm using a computation expression that builds F# lists. Thanks to suggestions from kvb and Daniel I'm further along, but still having trouble with for loops.

The builder:

type Items<'a> = Items of 'a list

type ListBuilder() =
    member x.Yield(vars) = Items [], vars
    member x.Run(l,_) = l
    member x.Zero() = Items [], ()
    member x.Delay f = f()
    member x.ReturnFrom f = f

    member x.Combine((Items curLeft, _), (Items curRight, vars)) =
        (Items (curLeft @ curRight), vars)

    member x.Bind(m: Items<'a> * 'v, f: 'v -> Items<'a> * 'o) : Items<'a> * 'o =
        let (Items current, vals) = m
        x.Combine(m, f vals)

    member x.While(guard, body) =
        if not (guard()) then
            x.Zero()
        else
            x.Bind(body, fun () -> x.While(guard, body))

    member x.TryWith(body, handler) =
        try
            x.ReturnFrom(body())
        with e ->
            handler e

    member x.TryFinally(body, compensation) =
        try
            x.ReturnFrom(body())
        finally
            compensation()

    member x.Using(disposable:#System.IDisposable, body) =
        let body' = fun() -> body disposable
        x.TryFinally(body', fun () ->
            match disposable with
            | null -> ()
            | disp -> disp.Dispose())

    member x.For(xs:seq<'a>, body) =
        x.Using(xs.GetEnumerator(), fun enum ->
            x.While(enum.MoveNext, x.Delay(fun () -> body enum.Current)))

    [<CustomOperation("add", MaintainsVariableSpace=true)>]
    member x.Add((Items current, vars), [<ProjectionParameter>] f) =
        Items (current @ [f vars]), vars

    [<CustomOperation("addMany", MaintainsVariableSpace=true)>]
    member x.AddMany((Items current, vars), [<ProjectionParameter>] f) =
        Items (current @ f vars), vars


let listBuilder = ListBuilder()

let build (Items items) = items

This version allows for things I could not do before, such as:

let stuff = 
    listBuilder {
        let x = 5 * 47
        printfn "hey"
        add x
        addMany [x .. x + 10]
    } |> build

However, I'm still getting a compiler error on this one:

let stuff2 =
    listBuilder {
        for x in 1 .. 50 do
            add x            
    } |> build

In this case, the IDE is underlining the x in for x in and telling me, "This expression was expected to have type unit, but here has type int."

It's not really clear to me why it's expecting the loop variable to be of type unit. Clearly I've got the wrong method signature somewhere, and I suspect I'm not passing through my accumulated state in every place I should be, but the compiler error is really not helping me narrow down where I went wrong. Any suggestions would be appreciated.

解决方案

The immediate cause is that your While function constrains the type of body. However, in general you can't use both custom operations and also control flow operators in the same computation expression, so I don't think you'll ever be able to do exactly what you want even if you fix the signature.

这篇关于为什么该计算表达式构建器期望“单位"为1?在我的for循环中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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