for (int ctr = 1; ctr <= gregorianCalendar.GetMonthsInYear(gregorianCalendar.GetYear(startOfYear)); ctr++) {
Console.Write(" {0,2}", ctr);
Console.WriteLine("{0,12}{1,15:MMMM}",
gregorianCalendar.GetDaysInMonth(gregorianCalendar.GetYear(startOfMonth), gregorianCalendar.GetMonth(startOfMonth)),
startOfMonth);
startOfMonth = gregorianCalendar.AddMonths(startOfMonth, 1);
}
Я пытался написать тот же код на F#, но я не знаю, что такое {0, 2} и {0,12}{1,15:MMMM}, что они делают и какой из них эквивалентен F#. Основной целью здесь является эквивалент F# приведенного выше кода C#. Но я был бы рад, если бы вы кратко объяснили форматы выше.
Заметки:
gregorianCalendar является экземпляром System.Globalization.GregorianCalendar.startOfYear — это экземпляр DateTime со значением DateTime(2023, 1, 1).startOfMonth — это экземпляр DateTime, значение которого совпадает со значением startOfYear при инициализации. Он используется для перебора месяцев.




{0, 2} и {0,12}{1,15:MM} — это строки формата.
В этом случае {0, 2} будет управлять шириной ctr (в данном случае длиной 2 символа).
{0,12}{1,15:MM} возьмет вывод из gregorianCalendar.GetDaysInMonth и отформатирует его в 12-символьную строку, а startOfMonth будет 15-символьной строкой (начиная с индекса 1) с полным названием месяца (MMMM предоставляет полное название месяца для указанной даты).
Дополнительные сведения см. здесь: https://learn.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting.
Я не знаю F#, но я думаю, что это не слишком отличается. См. здесь, пожалуй, для примера: F# string.Format.
Если вам нужен буквальный перевод на F#, он выглядит очень похоже:
open System
open System.Globalization
let gregorianCalendar = GregorianCalendar()
let startOfYear = DateTime(2023, 1, 1)
let mutable startOfMonth = startOfYear
for ctr = 1 to gregorianCalendar.GetMonthsInYear(gregorianCalendar.GetYear(startOfYear)) do
Console.Write(" {0,2}", ctr)
Console.WriteLine("{0,12}{1,15:MMMM}",
gregorianCalendar.GetDaysInMonth(gregorianCalendar.GetYear(startOfMonth), gregorianCalendar.GetMonth(startOfMonth)),
startOfMonth)
startOfMonth <- gregorianCalendar.AddMonths(startOfMonth, 1)
Однако многие разработчики F# предпочитают избегать изменяемых переменных и побочных эффектов. Таким образом, следующее более идиоматично:
// compute month starts with no side-effects
let nMonths = gregorianCalendar.GetMonthsInYear(gregorianCalendar.GetYear(startOfYear))
let startsOfMonths =
(startOfYear, [| 1 .. nMonths-1 |])
||> Array.scan (fun startOfMonth _ ->
gregorianCalendar.AddMonths(startOfMonth, 1))
// write results to console
for ctr = 1 to nMonths do
let startOfMonth = startsOfMonths[ctr-1]
Console.Write(" {0,2}", ctr)
Console.WriteLine("{0,12}{1,15:MMMM}",
gregorianCalendar.GetDaysInMonth(gregorianCalendar.GetYear(startOfMonth), gregorianCalendar.GetMonth(startOfMonth)),
startOfMonth)
Вот несколько разных переводов, от попытки изменить как можно меньше до более продвинутого.
open System
open System.Globalization
let now, today = DateTime.Now, DateTime.Today
let startOfYear = DateTime(now.Year, now.Month, 1)
let g = GregorianCalendar()
let range = [1.. g.GetMonthsInYear(g.GetYear(startOfYear))]
let runViaFor() =
let mutable startOfMonth = today.AddDays(float (-1* (today.Day - 1)))
for ctr in range do
printf "%2i" ctr
printfn "%12i%15s" (g.GetDaysInMonth(g.GetYear(startOfMonth), g.GetMonth(startOfMonth))) (startOfMonth.ToString("MMMM"))
startOfMonth <- g.AddMonths(startOfMonth, 1)
()
let runViaSeq() =
let mutable startOfMonth = today.AddDays(float (-1* (today.Day - 1)))
range
|> Seq.iter(fun ctr ->
printf "%2i" ctr
printfn "%12i%15s" (g.GetDaysInMonth(g.GetYear(startOfMonth), g.GetMonth(startOfMonth))) (startOfMonth.ToString("MMMM"))
startOfMonth <- g.AddMonths(startOfMonth, 1)
)
let runViaFold() =
let startOfMonth = today.AddDays(float (-1* (today.Day - 1)))
(startOfMonth, range)
||> Seq.fold(fun startOfMonth ctr ->
printf "%2i" ctr
printfn "%12i%15s" (g.GetDaysInMonth(g.GetYear(startOfMonth), g.GetMonth(startOfMonth))) (startOfMonth.ToString("MMMM"))
g.AddMonths(startOfMonth, 1)
)
|> ignore<DateTime>
let withRefactors today =
let addDays (dt:DateTime) (i:int) = float i |> dt.AddDays
let getStartOfMonth(dt:DateTime) = dt.Day - 1 |> (*) -1 |> addDays dt
let getLastDayOfMonth(startOfMonth:DateTime) =
let year = g.GetYear(startOfMonth)
let month = g.GetMonth(startOfMonth)
g.GetDaysInMonth(year, month)
let printRow (startOfMonth:DateTime) ctr =
printf "%2i" ctr
printfn "%12i%15s" (getLastDayOfMonth startOfMonth) (startOfMonth.ToString("MMMM"))
let printAndGet startOfMonth ctr =
printRow startOfMonth ctr
g.AddMonths(startOfMonth, 1)
(getStartOfMonth today, range)
||> Seq.fold printAndGet
|> ignore<DateTime>
printfn "For:"
runViaFor()
printfn "----"
printfn "Seq:"
runViaSeq()
printfn "----"
printfn "Fold:"
runViaFold()
printfn "----"
printfn "Ref:"
withRefactors today
printfn "----"
образец вывода: