从String创建区分联合案例

 佳山申士_636 发布于 2023-01-29 13:47

我正在尝试从字符串创建DU案例.我可以看到这样做的唯一方法是通过枚举DU情况Microsoft.FSharp.Reflection.FSharpType.GetUnionCases,然后选择UnionCase匹配字符串(通过使用.Name),然后通过使用实现DU的情况FSharpValue.MakeUnion.

这样做是不是更简单/更优雅?在我的场景中,我有一个DU,有几百个关键字案例.我必须从文件中读取字符串(关键字)并从中提取类型.通过将案例放入Map中我做了一些"优化",但我希望有更好的方法来做到这一点.

我有以下内容,例如:

type Keyword = 
    | FOO
    | BAR
    | BAZ
    | BLAH

let mkKeywords (file: string) =
    use sr = new StreamReader(file)

    let caseMap = 
        FSharpType.GetUnionCases(typeof)
        |> Array.map (fun c -> (c.Name, FSharpValue.MakeUnion(c, [||]) :?> Keyword))
        |> Map.ofArray

    [
        while not sr.EndOfStream do
            let l = sr.ReadLine().Trim()

            match caseMap.TryFind l with
            | Some c -> yield c
            | None -> failwith <| "Could not find keyword: " + l
    ] 

Wallace Kell.. 14

我找到了这个方便的代码片段......

open Microsoft.FSharp.Reflection

let toString (x:'a) = 
    match FSharpValue.GetUnionFields(x, typeof<'a>) with
    | case, _ -> case.Name

let fromString<'a> (s:string) =
    match FSharpType.GetUnionCases typeof<'a> |> Array.filter (fun case -> case.Name = s) with
    |[|case|] -> Some(FSharpValue.MakeUnion(case,[||]) :?> 'a)
    |_ -> None

...这使得很容易将两行代码添加到任何DU ...

type A = X|Y|Z with
    override this.ToString() = FSharpUtils.toString this
    static member fromString s = FSharpUtils.fromString s


小智.. 8

我会像这样使用模式匹配:

type Keyword = 
    | FOO
    | BAR
    | BAZ
    | BLAH


let matchKeyword (word:string) : Keyword option =
    match word with
    | "FOO"  -> Some FOO
    | "BAR"  -> Some BAR
    | "BAZ"  -> Some BAZ
    | "BLAH" -> Some BLAH
    | _      -> None

也许在我的编辑器中第一次使用正则表达式自动生成匹配语句,但这只是因为你有数百个案例.但我不确定它是否比你更好的解决方案.

3 个回答
  • 我找到了这个方便的代码片段......

    open Microsoft.FSharp.Reflection
    
    let toString (x:'a) = 
        match FSharpValue.GetUnionFields(x, typeof<'a>) with
        | case, _ -> case.Name
    
    let fromString<'a> (s:string) =
        match FSharpType.GetUnionCases typeof<'a> |> Array.filter (fun case -> case.Name = s) with
        |[|case|] -> Some(FSharpValue.MakeUnion(case,[||]) :?> 'a)
        |_ -> None
    

    ...这使得很容易将两行代码添加到任何DU ...

    type A = X|Y|Z with
        override this.ToString() = FSharpUtils.toString this
        static member fromString s = FSharpUtils.fromString<A> s
    

    2023-01-29 13:49 回答
  • 由于案例没有价值,另一种选择是使用枚举:

    type Keyword = 
      | FOO   = 0
      | BAR   = 1
      | BAZ   = 2
      | BLAH  = 3
    
    let strings = ["FOO";"BAR"]
    let keywords = 
      [for s in strings -> s, Keyword.Parse(typeof<Keyword>, s)]
      |> Map.ofList
    

    然后你可以简单地使用Enum.Parse.

    2023-01-29 13:49 回答
  • 我会像这样使用模式匹配:

    type Keyword = 
        | FOO
        | BAR
        | BAZ
        | BLAH
    
    
    let matchKeyword (word:string) : Keyword option =
        match word with
        | "FOO"  -> Some FOO
        | "BAR"  -> Some BAR
        | "BAZ"  -> Some BAZ
        | "BLAH" -> Some BLAH
        | _      -> None
    

    也许在我的编辑器中第一次使用正则表达式自动生成匹配语句,但这只是因为你有数百个案例.但我不确定它是否比你更好的解决方案.

    2023-01-29 13:51 回答
撰写答案
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有