【问题标题】:Unexpected type compilation issue when using pipe operations in F#在 F# 中使用管道操作时出现意外的类型编译问题
【发布时间】:2012-07-10 16:40:46
【问题描述】:

我正在尝试解析 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))

上面的 sn-p 来自我在 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")

【问题讨论】:

  • 你能发布错误信息吗?
  • 糟糕!错过了!错误信息如下:这个表达式应该有单位类型,但这里有类型字符串

标签: f# linqpad seq


【解决方案1】:

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

不过,我有几个 cmets:

  • Seq.cast 是多余的,因为 Directory.GetFiles 返回 string []
  • 当您同时拥有Seq.mapSeq.filter 时,您始终可以将它们替换为Seq.choose
  • printfn 是一种比 Console.WriteLine 更 F#ish 的打印方式。

这是一个改进的版本:

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")

【讨论】:

  • 我认为您可能打错字(或 thinko'd),因为您引用的行中没有 Seq.filter。 :)
  • 如果属性不为空,他可以通过将ExtractConfiguredCalculator 更改为返回Some string 来进一步缩短它,否则None
  • @Daniel:空值检查似乎很奇怪,因为我希望 GetAttribute 在找不到属性时返回空字符串。
  • 谢谢大家!我正在尝试通过解决现实生活中的问题来学习 f#,所以每个建议都有帮助。
  • 我已经用更 f#-ish [或我理解为更 f#-ish 的版本] 更新了这个问题。欢迎评论/建议。
【解决方案2】:

您第一次拨打Seq.iter 应该是Seq.mapExtractConfiguredCalculator 返回 stringSeq.iter 期望函数返回 unit

【讨论】:

    猜你喜欢
    • 2016-02-05
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 2021-10-13
    相关资源
    最近更新 更多