VB.NETでもコマンドライン引数を楽にパースしたい(またの名をVB.NETとF#で連携したい)

はじめに

好きなイヤホンはBOSEQuietComfort 20 どうも弊社です。

前になんかいい感じのコマンドライン引数をパースするライブラリを見つけたいとか書いたのですが、DSL付きで見つけました。

なんとこちら、DSLなのに.NETの型システムと高い親和性を持っていたりマイクロソフトがサポートを改めて表明したりと至れり尽くせりなんです。F#って言うんですって

VB.NETとFSharp

とまぁ、やっぱりF#はこういう方面はめっぽう強いから好きです。

namespace CommandLine.Parser

open System

type Param = { Level:int; IsDryRun:bool; OutputName:string option; Files:string list }

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Param = 
    
    let rec parseImpl input param =
            match input with
            | "--level" :: x :: tail ->
                match Int32.TryParse(x) with
                | (true, x) when 1 <= x && x <= 5 -> parseImpl tail { param with Level = x }
                | _ -> parseImpl tail param
            | "--dry-run" :: tail -> 
                parseImpl tail { param with IsDryRun = true }
            | "--output-name" :: name :: tail ->
                parseImpl tail { param with OutputName = Some(name) }
            | head :: tail ->
                parseImpl tail { param with Files = head :: param.Files }
            | [] -> param

    [<CompiledName("Parse")>]
    let parse input =
        parseImpl (Array.toList input) { Level = 1; IsDryRun = false; OutputName = None; Files = [] } 

    [<CompiledName("Show")>]
    let show x = printfn "%A" x

これだけのコードで割と複雑なコマンドライン引数をパースできます。

Imports CommandLine.Parser

Module Program

    Sub Main()
        Dim param1 = ParamModule.Parse({"--level", "2", "--dry-run", "c.txt"})
        ParamModule.Show(param1)

        Console.WriteLine()

        Dim param2 = ParamModule.Parse({"--level", "2", "--output-name", "hoge.exe", "a.txt", "b.txt"})
        ParamModule.Show(param2)
    End Sub

End Module
{Level = 2;
 IsDryRun = true;
 OutputName = None;
 Files = ["c.txt"];}

{Level = 2;
 IsDryRun = false;
 OutputName = Some "hoge.exe";
 Files = ["b.txt"; "a.txt"];}

言語のちゃんぽんはあまりオススメ出来ませんが、異なるパラダイムをごった煮出来るのが.NET Frameworkの良さ*1なのだと思います。

おわりに

まぁ、例のごとくgithubから見つけてきた手法の紹介でアレなのですが、githubは宝の山ですね。

このライブラリはどうやってこの機能を実現しているのだろうと思ったときに調べればすぐに出てきますし、すごい人はやっぱり凄いなと感心するばかりです。

あと、本題とは違う形での紹介で申し訳ないのですが、このPersimmonと言うユニットテストフレームも結構いい感じなので、興味があろうとなかろうと一回使ってみるといいかもしれません。

github.com

おわり

*1:この辺はJavaScala・Kotlinが先を行っている感がありますが