首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >F#“状态”计算表达式

F#“状态”计算表达式
EN

Stack Overflow用户
提问于 2014-12-12 16:29:19
回答 3查看 555关注 0票数 3

我目前正在学习F#,并遇到了一些绊脚石;我认为其中有很多是在学习如何从功能上思考。

我目前正在学习的一件事是计算表达式,我希望能够定义一个处理某些跟踪状态的计算表达式,例如:

代码语言:javascript
复制
let myOptions = optionListBuilder {
    let! opt1 = {name="a";value=10}
    let! opt2 = {name="b";value=12}
}

我希望能够拥有它,以便myOptions是一个Option<'T> list,因此每个let!绑定操作都会使构建器在执行过程中“跟踪”定义的选项。

我不想使用可变状态(例如,由构建器维护并使用每个bind调用更新的列表)来完成这个任务。

有什么办法可以做到这一点吗?

Update:生成的Option<'T> list类型只是有代表性的,实际上我可能会有一个OptionGroup<'T>类型来包含一个列表以及一些附加信息--因此,正如丹尼尔下面提到的,我可以使用列表理解来处理一个简单的列表。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-12 17:05:48

我编写了一个字符串生成器计算表达式here

代码语言:javascript
复制
open System.Text

type StringBuilderUnion =
| Builder of StringBuilder
| StringItem of string

let build sb =
    sb.ToString()

type StringBuilderCE () =
    member __.Yield (txt : string) = StringItem(txt)
    member __.Yield (c : char) = StringItem(c.ToString())
    member __.Combine(f,g) = Builder(match f,g with
                                     | Builder(F),   Builder(G)   ->F.Append(G.ToString())
                                     | Builder(F),   StringItem(G)->F.Append(G)
                                     | StringItem(F),Builder(G)   ->G.Append(F)
                                     | StringItem(F),StringItem(G)->StringBuilder(F).Append(G))
    member __.Delay f = f()
    member __.Zero () = StringItem("")
    member __.For (xs : 'a seq, f : 'a -> StringBuilderUnion) =
                    let sb = StringBuilder()
                    for item in xs do
                        match f item with
                        | StringItem(s)-> sb.Append(s)|>ignore
                        | Builder(b)-> sb.Append(b.ToString())|>ignore
                    Builder(sb)

let builder1 = new StringBuilderCE ()

注意到底层类型是不可变的(包含的StringBuilder是可变的,但不一定是可变的)。不是更新现有数据,而是将当前状态和输入的输入组合在一起,从而生成一个StringBuilderUnion的新实例,您可以使用F#列表来实现这一点,因为向列表的头添加一个元素只是一个新值的构造,而不是对现有值进行变异。

使用StringBuilderCE如下所示:

代码语言:javascript
复制
//Create a function which builds a string from an list of bytes
let bytes2hex (bytes : byte []) =
    string {
        for byte in bytes -> sprintf "%02x" byte
    } |> build

//builds a string from four strings
string {
        yield "one"
        yield "two"
        yield "three"
        yield "four"
    } |> build

注意到了yield而不是let!,因为我实际上不想使用计算表达式中的值。

票数 5
EN

Stack Overflow用户

发布于 2014-12-12 17:48:44

溶液

使用mydogisbox提供的基本行StringBuilder CE生成器,我能够生成以下解决方案,该解决方案具有魅力:

代码语言:javascript
复制
type Option<'T> = {Name:string;Item:'T}

type OptionBuilderUnion<'T> =
    | OptionItems of Option<'T> list
    | OptionItem of Option<'T>

type OptionBuilder () =
    member this.Yield (opt: Option<'t>) = OptionItem(opt)
    member this.Yield (tup: string * 't) = OptionItem({Name=fst tup;Item=snd tup})
    member this.Combine (f,g) = 
        OptionItems(
            match f,g with
            | OptionItem(F), OptionItem(G) -> [F;G]
            | OptionItems(F), OptionItem(G) -> G :: F
            | OptionItem(F), OptionItems(G) -> F :: G
            | OptionItems(F), OptionItems(G) -> F @ G
        )
    member this.Delay f = f()
    member this.Run (f) = match f with |OptionItems items -> items |OptionItem item -> [item]

let options = OptionBuilder()

let opts = options {
        yield ("a",12)
        yield ("b",10)
        yield {Name = "k"; Item = 20}
    }

opts |> Dump
票数 3
EN

Stack Overflow用户

发布于 2014-12-12 17:11:28

F#支持明文规定的清单理解.

代码语言:javascript
复制
let myOptions =
    [
        yield computeOptionValue()
        yield computeOptionValue()
    ]
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27447933

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档