В данный момент я пытаюсь выучить F # и столкнулся с проблемой, которую не могу решить и не могу найти ответы на нее в Google.
Изначально я хотел функцию журнала, которая работала бы как семейство функций printf, с помощью которой я мог бы предоставить строку формата и ряд аргументов (статически проверенных), но которая добавляла бы небольшие метаданные перед распечаткой. При поиске, я обнаружил, что это возможно с помощью функции, подобной следующей:
let LogToConsole level (format:Printf.TextWriterFormat<'T>) =
let extendedFormat = (Printf.TextWriterFormat<string->string->'T> ("%s %s: " + format.Value))
let date = DateTime.UtcNow.ToString "yyyy-MM-dd HH:mm:ss.fff"
let lvl = string level
printfn extendedFormat date lvl
с функцией printfn
в качестве последней строки этой функции позволяет использовать магию, аналогичную varargs синтаксиса printf, посредством которой возвращается частично примененный метод printfn, позволяющий вызывающей стороне завершить применение аргументов.
Однако, если у меня есть несколько таких функций с одной и той же сигнатурой, скажем, LogToConsole
, LogToFile
и другие, как я мог бы написать функцию, которая бы вызывала их все, сохраняя магию частичного применения?
Essential Я ищу, как я мог бы реализовать функцию MultiLog
это позволило бы мне вызывать несколько printf-подобных функций из одного вызова функции, например, в функции ResultIWant ниже:
type LogFunction<'T> = LogLevel -> Printf.TextWriterFormat<'T> -> 'T
let MultiLog<'T> (loggers:LogFunction<'T>[]) level (format:Printf.TextWriterFormat<'T>) :'T =
loggers
|> Seq.map (fun f -> f level format)
|> ?????????
let TheResultIWant =
let MyLog = MultiLog [LogToConsole; LogToFile]
MyLog INFO "Text written to %i outputs" 2
Возможно, суть этого вопроса можно уловить более кратко: учитывая список функций с одинаковой сигнатурой, как я могу частично применить их все с одинаковыми аргументами?
type ThreeArg = string -> int -> bool -> unit
let funcs: ThreeArg seq = [func1; func2; func3]
let MagicFunction = ?????
// I'd like this to be valid
let partiallyApplied = MagicFunction funcs "string"
// I'd also like this to be valid
let partiallyApplied = MagicFunction funcs "string" 255
// and this (fullyApplied will be `unit`)
let fullyApplied = MagicFunction funcs "string" 255 true