2014-10-22 33 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"] 

所以它似乎是仍在工作。

相關問題