【问题标题】:Statically typed Context静态类型的上下文
【发布时间】:2014-05-15 03:51:11
【问题描述】:

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

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

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

更新:答案似乎是您目前无法完全做到这一点,尽管我有一些很好的建议可以用不同的方式对我正在寻找的东西进行建模。感谢所有试图帮助解决我措辞不当的问题的人。

【问题讨论】:

  • 如果我理解你,首先想到的是一个元组。你可以有一个函数'a -> 'a * 'b。当然,嵌套元组可能会使类型变得混乱,但对于少数转换来说,它既快速又简单。
  • type Context 'a>(f:'a -> 'b -> 'c, v:'a, v1:'b ) = 成员 x.Current:'c = f(v, v1)
  • ...抱歉,这个编辑器不太好。上面的代码接近我正在寻找的类型的约束。我实际上更喜欢 'a 和 'c 是不可变的。
  • 试图弄清楚你想要达到的目标。 'a、'b、'c 类型应该如何相互关联?在您的示例中,'c 是 'a 的子类型,为什么它很重要?当您谈论将信息添加到上下文的操作时,您听起来好像 'a 和 'b 都是集合。如果是这样,为什么它们不能是同一类型?如果不是,那么“'a 的所有元素都在 'b 中”是什么意思?
  • 你的意思是一个以'a开始的过程,然后通过一系列步骤,你用'b类型的数据优化上下文,并从初始'a生成一个'c对象以及收集到的 'b 值?

标签: f#


【解决方案1】:

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

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

我看到了两种建模方法,它们在 F# 中感觉更合适,并且仍然允许您以某种方式在运行时强制执行某种形式的 'a :> 'c 约束。

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

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

这样,以前不相关的类型 'a 和 'c 的记录将成为单一类型的一部分。这意味着您可以将它们存储在 Context 内的列表中,并轻松地及时返回以查看更改是否朝着正确的方向发展(初始 -> 中间 -> 最终)。

2) 如果您预见到“添加”单个字段等大量更改,并且您更关心最终产品而不是中间产品,您可以根据最终记录定义选项字段记录:

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

并有办法将其转换为非选项 NameAndAmountAndFoo (或中间的 NameAndAmount 如果您出于某种原因需要它们)。然后在 Context 中,您可以一次设置单个字段的值,然后再次收集以前的记录以跟踪更改是如何应用的。

【讨论】:

    【解决方案2】:

    这样的?

    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
    

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

    【讨论】:

    • 在代码中:type Context&lt;'a, 'b, 'c when 'c :&gt; 'a&gt;(f:'a -&gt; 'b -&gt; 'c, v:'a, v1:'b) = member x.Current:'c = f v v1 为什么'a 被封了? 'a 不能是 INamed'c 不能是 INamedAndAmount(使用一些 C# 命名约定)?
    猜你喜欢
    • 2011-05-11
    • 2012-06-13
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    相关资源
    最近更新 更多