2014-10-22 64 views
1
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

我不明白你的问题 - 你很明显在多个地方调用'getStringRepresentation',代码显示正常(如果有点复杂) - 问题到底是什么? – 2014-10-22 04:13:31

+0

我觉得这真的很愚蠢: | (8,order) - > getNumeral(5,order)+ getNumeral(1,order)+ getNumeral(1,order)+ getNumeral(1,order) – Vlad 2014-10-22 05:29:06

+0

为什么不是'|(8,order) - > getNumeral(5 ,order)+ getNumeral(3,order)' – 2014-10-22 10:28:19

回答

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)所有occurances这样的:

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

所以它似乎是仍在工作。

相关问题