F# F中数到罗马数字函数的进一步优化#

F# F中数到罗马数字函数的进一步优化#,f#,functional-programming,F#,Functional Programming,我是F#的新手,我很好奇这是否还可以进一步优化。我不太确定我是否也做对了。我对最后一行特别好奇,因为它看起来真的很长很可怕 我在谷歌上搜索过,但只显示了罗马数字对数字的解决方案,所以我很难进行比较 type RomanDigit = I | IV | V | IX let rec romanNumeral number = let values = [ 9; 5; 4; 1 ] let capture number values = values

我是F#的新手,我很好奇这是否还可以进一步优化。我不太确定我是否也做对了。我对最后一行特别好奇,因为它看起来真的很长很可怕

我在谷歌上搜索过,但只显示了罗马数字对数字的解决方案,所以我很难进行比较

type RomanDigit = I | IV | V | IX
let rec romanNumeral number =
    let values = [ 9; 5; 4; 1 ]
    let capture number values =
            values
            |> Seq.find ( fun x -> number >= x )
    let toRomanDigit x =
        match x with
        | 9 -> IX
        | 5 -> V
        | 4 -> IV
        | 1 -> I
    match number with
    | 0 -> []
    | int -> Seq.toList ( Seq.concat [ [ toRomanDigit ( capture number values ) ]; romanNumeral ( number - ( capture number values ) ) ] )

感谢所有能帮我解决这个问题的人。

如果我必须用一个有歧视的联合体来代表罗马字母,我不会包括IV和IX

type RomanDigit = I|V|X

let numberToRoman n =       
   let (r, diff) =
        if   n > 8 then [X], n - 10
        elif n > 3 then [V], n -  5
        else [], n
   if diff < 0 then I::r
   else r @ (List.replicate diff I)
类型RomanDigit=I | V | X
设numberton=
let(r,diff)=
如果n>8,则[X],n-10
如果n>3,则[V],n-5
else[],n
如果差异<0,则I::r
else r@(List.replicate diff I)
然后,基于此解决方案,您可以进一步将其扩展到所有数字

这是我的第一次尝试,使用折叠和部分应用程序:

type RomanDigit = I|V|X|L|C|D|M

let numberToRoman n i v x = 
    let (r, diff) =
        if   n > 8 then [x], n - 10
        elif n > 3 then [v], n -  5
        else [], n
    if diff < 0 then i::r
    else r @ (List.replicate diff i)

let allDigits (n:int) =
    let (_, f) = 
        [(I,V); (X,L); (C,D)] 
        |> List.fold (fun (n, f) (i, v) -> 
            (n / 10, fun x -> (numberToRoman (n % 10) i v x) @ f i)) (n, (fun _ -> []))
    f M
类型RomanDigit=I | V | X | L | C | D | M
设numberton i v x=
let(r,diff)=
如果n>8,则[x],n-10
如果n>3,则[v],n-5
else[],n
如果差异<0,则i::r
else r@(List.replicate diff i)
让所有数字(n:int)=
让(u,f)=
[(I,V);(X,L);(C,D)]
|>列表。折叠(乐趣(n,f)(i,v)->
(n/10,fun x->(numberToRoman(n%10)i v x)@fi))(n,(fun->[]))
f M

递归查找可从值中减去的最大数字表示的略短方法(使用List.find):

let单位=
[1000,“M”
900,“厘米”
500,“D”
400,“CD”
100,“C”
90,“XC”
50,“L”
40,“XL”
10,“X”
9,“九”
5,“V”
4,“四”
1,“我”]
设rec TOROMANNUMEAL=函数
| 0 -> ""
|n->

让x,s=units |>List.find(fun(x,s)->x下面是@Philip Trelford答案的尾部递归版本:

let toRomanNumeral n =
    let rec iter acc n =
        match n with
        | 0 -> acc
        | n ->
            let x, s = units |> List.find (fun (x, _) -> x <= n)
            iter (acc + s) (n-x)

    iter "" n
n=
让我们重新考虑一下=
匹配
|0->acc
|n->

让x,s=units |>List.find(fun(x,|)->x初始建议:不要使用
Seq
到处使用数组(
Seq.*
函数比
array.*
要慢得多)可能
fun(x,s)->x我想问一下
n
用于什么样的模式?在toRomanNumeral函数中,n是生成数字的非零整数余数for@Chad它可能是(有趣的)->x
let toRomanNumeral n =
    let rec iter acc n =
        match n with
        | 0 -> acc
        | n ->
            let x, s = units |> List.find (fun (x, _) -> x <= n)
            iter (acc + s) (n-x)

    iter "" n