为 `[<EntryPoint>]` 调用 `argv` 中定义的特定函数或动态命名要调用的函数

Calling a specific function defined in `argv` for `[<EntryPoint>]` or dynamically naming the function to be called

是否可以以某种方式定义名为 and/or 模块名称 函数 名称在 F# 中动态打开?

谷歌搜索互联网似乎表明只有当“名称”是一个类型的成员时才可能使用内省。

我问的原因是因为我对 Advent of Code[<EntryPoint>] 的解决方案开始看起来很样板化,绝对不是 DRY。

我所有的“解谜”函数都在特定于 Day 的模块中定义,并具有相同的签名 String -> Unit -> int64 即它们采用文件名作为输入(为了测试,大多数(如果不是全部)谜题都有测试向量)和单元(以便它们在模式匹配时不会全部执行)

open AoC2020.Utils
open AoC2020.Day1
open AoC2020.Day2
open AoC2020.Day3
open AoC2020.Day4
open AoC2020.Day5
open AoC2020.Day6
open AoC2020.Day7
open AoC2020.Day8
open AoC2020.Day9

[<EntryPoint>]
let main argv =
    let day = argv |> getProblem
    match day with
    | "1" -> day1 "1" ()
    | "1b" -> day1part2 "1" ()
    | "2" -> day2 "2" ()
    | "2b" -> day2part2 "2" ()
    | "3" -> day3 "3" ()
    | "3b" -> day3part2 "3" ()
    | "4" -> day4 "4" ()
    | "4b" -> day4part2 "4" ()
    | "5" -> day5 "5" ()
    | "5b" -> day5part2 "5" ()
    | "6" -> day6 "6" ()
    | "6b" -> day6part2 "6" ()
    | "7" -> day7 "7" ()
    | "7b" -> day7part2 "7" ()
    | "8" -> day8 "8" ()
    | "8b" -> day8part2 "8" ()
    | _ -> 1L
    |> printfn "%d"
    0

..或者我做的事情完全错了,有更好的方法来实现同样的事情吗?

更一般地说,我可能不会费心为代码的降临创建一个复杂的启动器 - 对于我做的几个谜题,我只是将每个谜题的代码保存在一个脚本文件中,然后 运行 通过选择这一切,运行在 F# Interactive 中将其整合 - 而不是使用命令行界面。

但是,如果您更喜欢命令行界面,那么您应该能够使用反射来做您想做的事。每个 F# 模块都编译为 class,您可以使用 Assembly.GetExecutingAssembly().GetTypes() 获取所有已加载 class 的列表,找到您想要的 class 并调用您想要的方法知道它有诸如 run.

例如:

module Day1 = 
  let run () = printfn "day 1"

module Day2 = 
  let run () = printfn "day 2"

module Day2b = 
  let run () = printfn "day 2b"

一个(非常基本的)函数,它采用模块名称和 运行 它的 run 函数如下所示:

open System.Reflection

let run name = 
  let typ = 
    Assembly.GetExecutingAssembly().GetTypes()
    |> Seq.find (fun t -> t.Name = name)
  typ.GetMethod("run").Invoke(null, [||]) |> ignore

要对此进行测试:

run "Day1"
run "Day2"
run "Day2b"