静态类型的上下文

时间:2014-05-12 21:31:56

标签: f#

我希望编码(在某些.NET语言中 - fsharp似乎最有可能支持)一类形成当前上下文的类型。

规则是我们从类型'a的初始上下文开始。随着我们在计算中的进展,将添加上下文,但是我总是可以获得以前的值。因此,假设一个向上下文添加信息的操作,'a - > 'b,推断'a的所有元素也在'b。

这个想法类似于不可变的地图,但我希望它是静态类型的。这可行吗?怎么样,为什么不呢? TIA。

更新:答案似乎是你现在不能做到这一点,虽然我有一些很好的建议,以不同的方式建模我正在寻找的东西。感谢所有试图帮助我措辞不好的人。

2 个答案:

答案 0 :(得分:1)

这样的东西?

type Property = 
    | Name of string
    | Amount of float

let context = Map.empty<string,Property>

//Parse or whatever
let context = Map.add "Name" (Name("bob")) context
let context = Map.add "Amount" (Amount(3.14)) context

我有一种感觉,如果你能向我们展示一些你的问题空间,可能会有一个更惯用的整体解决方案。

答案 1 :(得分:1)

F#中的单独记录类型是不同的,即使表面上它们具有相似的结构。即使记录字段a形成记录字段的子集,也无法静态强制执行该关系。如果您有充分的理由在那里使用不同的记录类型,那么您可以做的最好的事情就是使用反射来使用FSharpType.GetRecordFields来获取字段,并检查是否形成了另一个的子集。

此外,为每个添加的数据引入新的记录类型会导致大量的样板。

我认为有两种方法可以对F#进行建模,并且仍然允许您通过某种方式强制执行某种形式的&#39; a:&gt;

。在运行时约束。

1)如果你预见到少量记录,所有这些记录在程序的其他部分都很有用,你可以使用一个有区别的联合来枚举你的过程的步骤:

type NameAndAmountAndFooDU = 
    | Initial of Name
    | Intermediate of NameAndAmount
    | Final of NameAndAmountAndFoo

通过这种方式,以前不相关的类型&#39; a和&#c; c的记录将成为单一类型的一部分。这意味着您可以将它们存储在Context中的列表中,并且可以轻松地及时返回以查看更改是否朝着正确的方向发展(Initial - &gt; Intermediate - &gt; Final)。

2)如果您预见到很多变化,例如添加&#39;单个字段,您更关心最终产品而不是中间产品,您可以根据最终记录定义选项字段的记录:

type NameAndAmountAndFooOption =
    {
        Name: string option
        Amount: decimal option
        Foo: bool option
    }

并有办法将其转换为非选项NameAndAmountAndFoo(或者如果由于某种原因需要它们,则为NameAndAmount之类的中间选项)。然后在上下文中,您可以一次设置一个字段的值,并再次收集以前的记录以跟踪更改的应用方式。