如何在没有递归的情况下两次调用相同的函数

时间:2014-10-22 04:05:46

标签: f#

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),我也认为递归可以使用一些清理,但我不知道如何。

任何想法如何调用该函数两次?

1 个答案:

答案 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"]

因此它似乎仍然有效。