【问题标题】:Active patterns over provided types in F#F# 中提供的类型上的活动模式
【发布时间】:2014-03-03 10:06:45
【问题描述】:

我有一个场景,我使用 FSharp.Data 中的 XML 类型提供程序来读取包含各种键/值对的流。这种情况下的值有时是小数,有时是日期,有时是字符串:

<records>
  <fields>
    <key>foo</key>
    <value>123.456</value>
  </fields>
  <fields>
    <key>bar</key>
    <value>2013-07-23</value>
  </fields>
  <fields>
    <key>fizz</key>
    <value>hello world</value>
  </fields>
</records>

因为似乎没有办法按名称引用提供的类型,为了对值进行模式匹配,我必须将值移动到元组中,然后在其上提供活动模式:

open System
open System.IO
type XmlFoo=FSharp.Data.XmlProvider<"""<records>
      <fields>
        <key>foo</key>
        <value>123.456</value>
      </fields>
      <fields>
        <key>bar</key>
        <value>2013-07-23</value>
      </fields>
      <fields>
        <key>fizz</key>
        <value>hello world</value>
      </fields>
    </records>""">

[<EntryPoint>]
let main argv = 

    let (|Date|_|) ((v,_,_):Option<DateTime> * Option<Decimal> * Option<String>) = v
    let (|Number|_|) ((_,v,_):Option<DateTime> * Option<Decimal> * Option<String>) = v
    let (|String|_|) ((_,_,v):Option<DateTime> * Option<Decimal> * Option<String>) = v

    use stream = File.OpenRead("sample.xml")
    let data = XmlFoo.Load(stream)

    for field in data.Fields do
      let value = field.Value.DateTimeValue, field.Value.NumberValue, field.Value.StringValue
      match value with
      | Date x -> printfn "Found a date: %s" (x.ToShortDateString())
      | Number x -> printfn "Found a number: %M" x
      | String x -> printfn "Found a string: %s" x
      | _ -> printfn "Found nothing"

    0 // return an integer exit code

有没有办法 a) 直接引用提供的类型(所以我不需要中间元组,并且活动模式可以推广到返回任意数量的可能数据类型的 XML 文件) 或者 b) 修改类型提供程序,以便它自己提供活动模式 - 不确定这是否可能查看类型提供程序 API。

编辑:没关系,我错过了明显的 - VS2013 中的工具提示具有误导性。通过显示 <...> 它给人的印象是没有办法通过名称来引用类型。感谢@ovatsus 的提示。你可以这样做:

open System
open System.IO
type XmlFoo=FSharp.Data.XmlProvider<"""<records>
      <fields>
        <key>foo</key>
        <value>123.456</value>
      </fields>
      <fields>
        <key>bar</key>
        <value>2013-07-23</value>
      </fields>
      <fields>
        <key>fizz</key>
        <value>hello world</value>
      </fields>
    </records>""">

[<EntryPoint>]
let main argv = 

    let (|Date|_|) (v:XmlFoo.Value) = v.DateTimeValue
    let (|Number|_|) (v:XmlFoo.Value) = v.NumberValue
    let (|String|_|) (v:XmlFoo.Value) = v.StringValue

    use stream = File.OpenRead("sample.xml")
    let data = XmlFoo.Load(stream)

    for field in data.Fields do
      match field.Value with
      | Date x -> printfn "Found a date: %s" (x.ToShortDateString())
      | Number x -> printfn "Found a number: %M" x
      | String x -> printfn "Found a string: %s" x
      | _ -> printfn "Found nothing"

    0 // return an integer exit code

【问题讨论】:

    标签: f# type-providers


    【解决方案1】:

    您可以创建类型别名来直接引用类型:

    type F = XmlFoo.Field
    

    【讨论】:

      【解决方案2】:

      对于直接在类型提供者中有活动模式的问题,似乎活动模式必须是let绑定,而不是类成员(甚至是静态的),所以很遗憾没有办法提供它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多