let getValue number divisor =
let firstNumber = int (System.Math.Floor((float) number / (float) divisor))
let rest = number % divisor
firstNumber, rest
let getNumeral value =
match value with
| (1, 1) -> "I"
| (5, 1) -> "V"
| (1, 2) -> "X"
| (5, 2) -> "L"
| (1, 3) -> "C"
| (5, 3) -> "D"
| (1, 4) -> "M"
| (_,_) -> ""
let getStringRepresentation value =
match value with
| (1 , order) ->
getNumeral (1, order)
| (2, order) ->
getNumeral (1, order) + getNumeral (1, order)
| (3, order) ->
getNumeral (1, order) + getNumeral (1, order) + getNumeral (1, order)
| (4, order) ->
getNumeral (1, order) + getNumeral (5, order)
| (5, order) ->
getNumeral (5, order)
| (6, order) ->
getNumeral (5, order) + getNumeral (1, order)
| (7, order) ->
getNumeral (5, order) + getNumeral (1, order) + getNumeral (1, order)
| (8, order) ->
getNumeral (5, order) + getNumeral (1, order) + getNumeral (1, order) + getNumeral (1, order)
| (9, order) ->
getNumeral (1, order) + getNumeral (1, order + 1)
| (_, _) -> ""
let rec convertToRoman number =
match number with
| number when number >= 1000 && number < 4000 ->
let value = getValue number 1000
let rest = convertToRoman (snd value)
let current = getStringRepresentation ((fst value), 4)
current + rest
| number when number >= 100 && number < 1000 ->
let value = getValue number 100
let rest = convertToRoman (snd value)
let current = getStringRepresentation ((fst value), 3)
current + rest
| number when number >= 10 && number < 100 ->
let value = getValue number 10
let rest = convertToRoman (snd value)
let current = getStringRepresentation ((fst value), 2)
current + rest
| number when number >= 1 && number < 10 ->
let value = getValue number 1
let rest = convertToRoman (snd value)
let current = getStringRepresentation ((fst value), 1)
current + rest
| _ -> ""
printfn "%A" (convertToRoman 49)
我是F#和整个函数式编程的新手。来自C#我决定从容易开始。我正试图让这件事情变得简单。但是,我多次调用一些方法有一些麻烦(getStringRepresentation),我也认为递归可以使用一些清理,但我不知道如何。
任何想法如何调用该函数两次?
答案 0 :(得分:2)
据评论我可以理解,你真正不喜欢的是这样的:
getNumeral (1, order) + getNumeral (1, order) + getNumeral (1, order)
你可以做的是定义另一个让你重复这些调用的功能:
let repeatOnes count order =
let one _ = getNumeral (1, order)
Seq.init count one |> Seq.reduce (+)
它使用Seq.init
初始化重复count
次的函数调用序列。然后,它使用Seq.reduce
使用+
运算符连接每个结果字符串。这使您可以像这样编写上面的表达式:
repeatOnes 3 order
作为第一次重构,您可以像这样替换getNumeral (1, order)
的所有出现:
let getStringRepresentation value =
match value with
| (1 , order) ->
repeatOnes 1 order
| (2, order) ->
repeatOnes 2 order
| (3, order) ->
repeatOnes 3 order
| (4, order) ->
repeatOnes 1 order + getNumeral (5, order)
| (5, order) ->
getNumeral (5, order)
| (6, order) ->
getNumeral (5, order) + repeatOnes 1 order
| (7, order) ->
getNumeral (5, order) + repeatOnes 2 order
| (8, order) ->
getNumeral (5, order) + repeatOnes 3 order
| (9, order) ->
repeatOnes 1 order + getNumeral (1, order + 1)
| (_, _) -> ""
但是,您现在可以稍微压缩模式:
let getStringRepresentation value =
match value with
| (count , order) when 1 <= count && count <= 3 ->
repeatOnes count order
| (4, order) ->
repeatOnes 1 order + getNumeral (5, order)
| (5, order) ->
getNumeral (5, order)
| (count, order) when 6 <= count && count <= 8 ->
getNumeral (5, order) + repeatOnes (count - 5) order
| (9, order) ->
repeatOnes 1 order + getNumeral (1, order + 1)
| (_, _) -> ""
在FSI中执行此操作:
> [1..50] |> List.map convertToRoman
产生这个:
val it : string list =
["I"; "II"; "III"; "IV"; "V"; "VI"; "VII"; "VIII"; "IX"; "X"; "XI"; "XII";
"XIII"; "XIV"; "XV"; "XVI"; "XVII"; "XVIII"; "XIX"; "XX"; "XXI"; "XXII";
"XXIII"; "XXIV"; "XXV"; "XXVI"; "XXVII"; "XXVIII"; "XXIX"; "XXX"; "XXXI";
"XXXII"; "XXXIII"; "XXXIV"; "XXXV"; "XXXVI"; "XXXVII"; "XXXVIII"; "XXXIX";
"XL"; "XLI"; "XLII"; "XLIII"; "XLIV"; "XLV"; "XLVI"; "XLVII"; "XLVIII";
"XLIX"; "L"]
因此它似乎仍然有效。