經過本系列前面幾篇文章對 F# 的介紹,是時候來一個比較小巧的例子了,
這個例子的原文見 https://fsharpforfunandprofit.com/posts/roman-numerals/
將羅馬數字轉換成普通的十進制數字,完整代碼如下:
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"
非常優雅,非常簡潔、清晰,可讀性強,易擴展易維護,沒有變數,不用管理狀態,函式沒有副作用,不容易出錯,而且型別安全,可進行靜態型別分析,
上面是一個模塊,可以這樣使用它:
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
本文介紹了一個比較完整的例子,它像一個小點心,希望你也能和我一樣初嘗 F# 函式式編程的美味,
更新,補充
上面的例子,我說它易擴展易維護,下面我們就對它進行一次小小的擴展試試,
也許你已經發現,上面的例子,輸入的引數是一個陣列(串列),而不是一個字串,這讓輸入很不方便,下面,我們讓它能接受字串,
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
// 注意,這里對 Numeral 進行了 unpacking, 即從一個 Numeral 里拆出一個 digits 來,
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"
可見,原來的代碼幾乎全部照原樣保留,直接添加處理字串的代碼即可,然后新增的函式可以非常輕松地呼叫原有的函式,我們可以這樣使用它:
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
這個例子還可以繼續擴充/改造,因為現在它還不能處理錯誤的羅馬數字,有興趣的同學請看原文 https://fsharpforfunandprofit.com/posts/roman-numerals/ 我在這里就不補充完整了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/231682.html
標籤:.NET技术
下一篇:C#(七)基礎篇—基本I/O操作
