F# で言語内ターミナル的なものを作ってみる 03 12月, 2012 kos59125 2012-12-03 プログラミング F# F# 3.0 では言語内 DSL っぽいものが簡単に作れるので,僕の考えた最強のターミナル的なものを試してみようかと思った次第です。ガチでスタンドアローンなやつではなく, fsi 上で操作をしたいなという感じで。 open System open System.IO type Terminal<'a> = | Terminal of string * option<'a> type CommandResult<'a> = | Success of 'a | Failure of exn let executeCommand (Terminal (current, lastResult)) command = match command current lastResult with | Success (next, result) -> Terminal (next, Some (result)) | Failure ex -> Console.Error.WriteLine (ex.Message) Terminal (current, None) let getResult (Terminal (_, result)) = result type TerminalBuilder () = member this.Yield (_) = Terminal (Environment.CurrentDirectory, None) [<CustomOperation("ls")>] member this.GetChildItem (current, ?dir) = let dir = defaultArg dir Environment.CurrentDirectory executeCommand current (fun c _ -> try let dir = Path.Combine (c, dir) let files = Directory.GetFiles (dir) Success (c, files) with | ex -> Failure (ex) ) [<CustomOperation("cd")>] member this.SetLocation (current, ?dir) = let dir = defaultArg dir <| Environment.GetFolderPath (Environment.SpecialFolder.UserProfile) executeCommand current (fun c _ -> try let dir = Path.Combine (c, dir) Environment.CurrentDirectory <- dir Success (dir, dir) with | ex -> Failure (ex) ) let terminal = TerminalBuilder () [<EntryPoint>] let main argv = let command = terminal { cd @"C:\Windows\Fonts" ls "." // Cannot omit this argument? } getResult command |> function | Some (files) -> Array.iter (printfn "%s") files | None -> () 0 省略可能なパラメーターを使ってはいるものの,残念ながらコンピュテーション式内では省略はできないみたいですね。