在F#中使用管道操作时出现意外的类型编译问题

时间:2012-07-10 16:40:46

标签: f# linqpad seq

我正在尝试解析XML文件的目录,然后在给定节点存在时选择特定属性的值。我无法理解以下F#导致的编译错误的原因。

open System
open System.IO
open System.Xml
open System.Xml.XPath
open System.Xml.Linq


let configRootDirectory = @"C:\dir"
let relativeProductDir = @"relDir"

let ExtractConfiguredCalculator (productConfigFile:string) = 
    let xmlNavigator = XPathDocument(productConfigFile).CreateNavigator()
    let node = xmlNavigator.SelectSingleNode(@"Product/SupportedRisk/Risk[@type='PV']") 
    node.GetAttribute("methodology", "")

let configFile = Directory.GetFiles(Path.Combine(configRootDirectory, relativeProductDir), @"*.xml")
                    |> Seq.cast<string>
                    |> Seq.iter(fun configFileName -> ExtractConfiguredCalculator(configFileName))                  
                    |> Seq.filter(fun configuredCalculatorNode -> configuredCalculatorNode != null)
                    |> Seq.iter(fun calculator -> Console.WriteLine(calculator))

上面的代码片段来自我在LinqPad中尝试的代码。看到的错误信息如下所示。

This expression was expected to have type     unit     but here has type     string   

更新 试图获得更多f#-ish。如果可以改进,请建议。

let configFile = 
        Directory.GetFiles(Path.Combine(configRootDirectory, relativeProductDir), @"*.xml")    
        |> Seq.map(fun configFileName -> 
                    let xmlNavigator = XPathDocument(configFileName).CreateNavigator()
                    let node = xmlNavigator.SelectSingleNode(@"Product/SupportedRisk/Risk[@type='PV']")
                    match node with
                    | null -> "PV not configured"
                    | _ -> 
                        let attributeValue = node.GetAttribute("methodology", "")
                        match attributeValue with 
                        | null -> "Calculator not configured"
                        | _ -> attributeValue)
        |> Seq.iter (printfn "%s")

2 个答案:

答案 0 :(得分:6)

您必须将第一个Seq.iter更改为Seq.map才能返回后续Seq.filter所需的序列。

我有几条评论:

  • Seq.cast是多余的,因为Directory.GetFiles会返回string []
  • 当您Seq.mapSeq.filter在一起时,您可以随时将其替换为Seq.choose
  • printfn是一种比Console.WriteLine更多的F#打印方式。

以下是改进版本:

let configFile = 
        Directory.GetFiles(Path.Combine(configRootDirectory, relativeProductDir), @"*.xml")    
        |> Seq.choose (fun configFileName -> 
                            let config = ExtractConfiguredCalculator(configFileName)
                            if config <> null then Some config else None)
        |> Seq.iter (printfn "%s")

答案 1 :(得分:4)

您对[{1}}的第一次电话应该是Seq.iterSeq.map返回ExtractConfiguredCalculator,但string期望函数返回Seq.iter