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

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

// 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
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.

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 […]