12 дней Рождества с F#


Я реализовал 12 дней Рождества, просто используя соответствующий шаблон. Это не очень эффективно, так как он выполняет 12 повторов, каждый из которых выполняет свой итерации (возможно от 12 до 1... не хвостовая рекурсия окочурится тут хоть?) но я думаю, что я могу жить с этим на данный момент. Меня больше волнует обучения, как идиоматические F# - это написано. Бы на F# программистом быть больше заинтересованными в создании типов и т. д.?

module Christmas
let getOrdinal num =
    match num with
    | 1 -> sprintf "%ist" num
    | 2 -> sprintf "%ind" num
    | 3 -> sprintf "%ird" num
    | _ -> sprintf "%ith" num

let getPreamble num =
    sprintf "On the %s day of Christmas, my true love gave to me" (getOrdinal num)

let rec getVerse verse num = 
    match num with
    | 12 -> getVerse (List.append verse ["12 drummers drumming"]) (num - 1)
    | 11 -> getVerse (List.append verse ["11 pipers piping"]) (num - 1)
    | 10 -> getVerse (List.append verse ["10 lords a-leaping"]) (num - 1)
    | 9 -> getVerse (List.append verse ["9 ladies dancing"]) (num - 1)
    | 8 -> getVerse (List.append verse ["8 maids a-milking"]) (num - 1)
    | 7 -> getVerse (List.append verse ["7 swans a-swimming"]) (num - 1)
    | 6 -> getVerse (List.append verse ["6 geese a-laying"]) (num - 1)
    | 5 -> getVerse (List.append verse ["5 golden rings"]) (num - 1)
    | 4 -> getVerse (List.append verse ["4 calling birds"]) (num - 1)
    | 3 -> getVerse (List.append verse ["3 French hens"]) (num - 1)
    | 2 -> getVerse (List.append verse ["2 turtle doves, and"]) (num - 1)
    | _ -> List.append verse ["A partridge in a pear tree"]

let composeVerse num =
    List.append [getPreamble num] (getVerse [] num)
    |> List.fold (fun r s -> r + s + "\n") ""


[1 .. 12]
|> Seq.iter (fun a -> printfn "%s" (composeVerse a))


143
6
f#
задан 26 марта 2018 в 02:03 Источник Поделиться
Комментарии
2 ответа

В целом следует избегать список.дописывать за присоединение к поодиночке-связанный список-это довольно неэффективно.

Я думаю, что ваш getVerse функция является, вероятно, делаете слишком много. Вы можете иметь функцию, чтобы получить строку, которая просто int -> string

Рекурсия может быть не так, если вы переключитесь на список осмысления (в for...in синтаксис). Рекурсия-это редко требуется в F#.

Даже не складывая можно избежать здесь, так как он проще в использовании String.concat.

Со всеми этими изменениями и еще парочку:

let ordinalSuffix = function 1 -> "st" | 2 -> "nd" | 3 -> "rd" | _ -> "th"

let preamble num =
sprintf "On the %i%s day of Christmas, my true love gave to me" num (ordinalSuffix num)

let line num =
match num with
| 12 -> "12 drummers drumming"
| 11 -> "11 pipers piping"
| 10 -> "10 lords a-leaping"
| 9 -> "9 ladies dancing"
| 8 -> "8 maids a-milking"
| 7 -> "7 swans a-swimming"
| 6 -> "6 geese a-laying"
| 5 -> "5 golden rings"
| 4 -> "4 calling birds"
| 3 -> "3 French hens"
| 2 -> "2 turtle doves, and"
| _ -> "A partridge in a pear tree"

let verse num =
preamble num :: [ for i in num .. -1 .. 1 -> line i ]
|> String.concat "\n"

[1 .. 12] |> List.map verse |> String.concat "\n\n" |> printfn "%s"

3
ответ дан 26 марта 2018 в 12:03 Источник Поделиться

Я думаю, что предложение TheQuickBownFox весьма элегантные. С немного твист (использование List.mapFold) надо только позвонить line num один раз в номер:

module Christmas =

let getOrdinal num =
match num with
| 1 -> sprintf "%ist" num
| 2 -> sprintf "%ind" num
| 3 -> sprintf "%ird" num
| _ -> sprintf "%ith" num

let getPreamble num =
sprintf "On the %s day of Christmas, my true love gave to me" (getOrdinal num)

let getVerseLine num =
match num with
| 12 -> "12 drummers drumming"
| 11 -> "11 pipers piping"
| 10 -> "10 lords a-leaping"
| 9 -> "9 ladies dancing"
| 8 -> "8 maids a-milking"
| 7 -> "7 swans a-swimming"
| 6 -> "6 geese a-laying"
| 5 -> "5 golden rings"
| 4 -> "4 calling birds"
| 3 -> "3 French hens"
| 2 -> "2 turtle doves, and"
| _ -> "A partridge in a pear tree"

let composeVerse num verseLines =
let verse = (getVerseLine num)::verseLines
(getPreamble num)::verse, verse

let getVerses=
fst ([1 .. 12] |> List.mapFold (fun verseLines num -> composeVerse num verseLines) [])

2
ответ дан 26 марта 2018 в 01:03 Источник Поделиться