基礎プログラミング演習(1),(2)をF# でやってみた
元々お手本コードを割と関数型風に書いていたので、ほとんどそのまま一対一対応で移植する形になりました。
比較すると、記法がどれほど簡潔かわかるんじゃないでしょうか。
BMIを計算するプログラム
units of measureを使ってみました。
module BmiProgram module String = open System // convert string to int let tryParseInt (s:string) = Int32.TryParse(s) |> function | (true, x) -> Option.Some(x) | (false, _) -> Option.None module Option = // Option.filter let filter (predicate : 'T -> bool) value = value |> function | None -> None | Some x -> if predicate x then Some x else None module Metre = [<Measure>] type cm [<Measure>] type m let toCentiMetre (x:int<m>) = x * 100<cm/m> let toMetre (x:int<cm>) = let x = float x |> LanguagePrimitives.FloatWithMeasure<cm> x / 100.0<cm/m> module Gram = [<Measure>] type kg module Bmi = open Metre open Gram // compute bmi value let compute (h:int<cm>) (w:int<kg>) = let w = w |> (float) let h = h |> Metre.toMetre |> (float) w / (h * h) // define bmi type type BmiType = Fat | Slim | Normal // check bmi type by bmi value let check = function | x when x < 18.5 -> Slim | x when x >= 25.0 -> Fat | _ -> Normal // get string of bmi type let getBmiTypeName = function | Fat -> "肥満" | Slim -> "痩せ" | Normal -> "普通" module Program = open System // validate input value let validate (s:string) = s |> String.tryParseInt |> Option.filter (fun x -> x > 0) // get correct integer value let rec getInput () = Console.ReadLine() |> validate |> function | Some x -> x | None -> printfn "error. 0より大きい整数を入力して下さい"; getInput () let run () = printfn "身長は?" let h = getInput () |> LanguagePrimitives.Int32WithMeasure<Metre.cm> printfn "体重は?" let w = getInput () |> LanguagePrimitives.Int32WithMeasure<Gram.kg> let bmi = Bmi.compute h w printfn "あなたのBMIは%fです" bmi printfn "あなたは%s体型です" (bmi |> Bmi.check |> Bmi.getBmiTypeName) //(* [<EntryPoint>] let main args = Program.run () #if DEBUG System.Console.ReadKey () |> ignore #endif 0 //*)
じゃんけんゲーム
バリアントとパターンマッチが便利すぎてもうそれ無しには生きていけません。
module JankenProgram module Janken = open System // define janken hands type Hand = Gu | Chi | Pa // define janken results type Result = Win | Aiko |Lose let getRandomHand (r:Random) = r.Next(0, 2) % 3 |> function | 0 -> Gu | 1 -> Chi | _ -> Pa // judge let isHumanWin (human, cp) = (human, cp) |> function | h, c when h = c -> Aiko | Gu, Chi | Chi, Pa | Pa, Gu -> Win | _ -> Lose // get janken hand name let getHandName = function | Gu -> "グー" | Chi -> "チョキ" | Pa -> "パー" // get janken result name let getResultName = function | Win -> "勝ち" | Aiko -> "あいこ" | Lose -> "負け" module Program = open System type Input = Hand of Janken.Hand | Exit let validateChar = function | 'g' -> Janken.Hand.Gu |> Hand |> Some | 'c' -> Janken.Hand.Chi |> Hand |> Some | 'p' -> Janken.Hand.Pa |> Hand |> Some | 'q' -> Exit |> Some | _ -> None // get hand by input string let validate (input:string) = if input.Length <> 1 then None else validateChar input.[0] let rec getInput () = Console.ReadLine() |> validate |> function | Some x -> x | None -> printfn "error.入力値が不正です"; getInput() let run () = let random = new Random() let rec loop () = printfn "出す手を入力してください(g:グー、c:チョキ、p:パー)。終了する場合はqを入力してください" getInput () |> function | Exit -> () | Hand hand -> let cpHand = Janken.getRandomHand random let result = Janken.isHumanWin (hand, cpHand) printfn "あなた: %s / CP: %s" (Janken.getHandName hand) (Janken.getHandName cpHand) printfn "あなたの%sです" (Janken.getResultName result) loop () loop () //(* [<EntryPoint>] let main args = Program.run () 0 //*)