An example of functional programming

Time:2021-1-28

After the introduction of f#in the previous articles in this series, it’s time for a smaller example.

For the original text of this example, seehttps://fsharpforfunandprofit.com/posts/roman-numerals/

To convert Roman numerals into ordinary decimal digits, the complete code is as follows:

module Roman =
    type Digit = I | V | X | L | C | D | M
    type Numeral = Numeral of Digit list

    let digitToInt =
        function
        | I -> 1
        | V -> 5
        | X -> 10
        | L -> 50
        | C -> 100
        | D -> 500
        | M -> 1000

    let rec digitsToInt =
        function
        | [] -> 0
        | x::y::tail when x < y ->
            (digitToInt y - digitToInt x) + digitsToInt tail
        | digit::tail ->
            digitToInt digit + digitsToInt tail

    let print digits = digits |> digitsToInt |> printfn "%A"

Very elegant, very concise, clear, readable, easy to expand, easy to maintain, no variables, no management state, no side effects, not easy to make mistakes, and type safety, can carry out static type analysis.

Above is a module, which can be used as follows:

open type Roman.Digit

Roman.print [I;I;I;I] // 4
Roman.print [I;V]     // 4
Roman.print [V;I]     // 6
Roman.print [I;X]     // 9

[M;C;M;L;X;X;I;X] |> Roman.print // 1979
[M;C;M;X;L;I;V] |> Roman.print   // 1944

This article introduces a more complete example, it is like a snack, I hope you can also like me, the first taste of F # functional programming delicious.

Update, supplement

For the above example, I said it is easy to expand and maintain. Let’s try a small expansion.

You may have found that in the above example, the input parameter is an array (list), not a string, which makes the input very inconvenient. Next, let’s make it accept strings.

module Roman =
    type Digit = I | V | X | L | C | D | M
    type Numeral = Numeral of Digit list

    let digitToInt =
        function
        | I -> 1
        | V -> 5
        | X -> 10
        | L -> 50
        | C -> 100
        | D -> 500
        | M -> 1000

    // Digit list -> int
    let rec digitsToInt =
        function
        | [] -> 0
        | x::y::tail when x < y ->
            (digitToInt y - digitToInt x) + digitsToInt tail
        | digit::tail ->
            digitToInt digit + digitsToInt tail

    // Numeral -> int
    //Note that numerical is unpacked here, that is, a digit is removed from a numerical.
    let toInt (Numeral digits) = digitsToInt digits

    type ParsedChar =
        | Good of Digit
        | Bad of char

    let parseChar =
        function
        | 'I' -> Good I
        | 'V' -> Good V
        | 'X' -> Good X
        | 'L' -> Good L
        | 'C' -> Good C
        | 'D' -> Good D
        | 'M' -> Good M
        | ch -> Bad ch

    // string -> ParsedChar list
    let toDigitList (s:string) =
        s.ToCharArray()
        |> List.ofArray
        |> List.map parseChar

    // string -> Numeral
    let toNumeral s =
        toDigitList s
        |> List.choose (
            function
            | Good digit -> Some digit
            | Bad ch ->
                eprintfn "%c is not a valid character" ch
                None
            )
        |> Numeral

    let print s =
        s |> toNumeral |> toInt |> printfn "%A"

It can be seen that almost all the original codes are retained as they are. You can directly add the code to handle strings, and then the new functions can call the original functions very easily. We can use it like this:

open type Roman.Digit

Roman.print "IIII"
Roman.print "IV"
Roman.print "VI"
Roman.print "IX"

"MCMLXXIX" |> Roman.print
"MCMXLIV" |> Roman.print

"" |> Roman.print
"IIKKMM" |> Roman.print

This example can be further expanded / modified, because it can’t handle wrong Roman numerals at presenthttps://fsharpforfunandprofit.com/posts/roman-numerals/I will not complete it here.

Recommended Today

Review of SQL Sever basic command

catalogue preface Installation of virtual machine Commands and operations Basic command syntax Case sensitive SQL keyword and function name Column and Index Names alias Too long to see? Space Database connection Connection of SSMS Connection of command line Database operation establish delete constraint integrity constraint Common constraints NOT NULL UNIQUE PRIMARY KEY FOREIGN KEY DEFAULT […]