2011-04-06 3 views
6

파일 및 데이터의 일부 처리를위한 프레임 워크를 만들려고합니다. 내가 고민하고있는 한 가지 영역은 프레임 워크에 로깅 기능을 제공하여 프레임 워크가 사용중인 로깅에 대한 지식 없이도 메시지를보고 할 수 있도록하는 방법입니다.printf 스타일 로깅 인수로 F # 함수를 만드는 방법은 무엇입니까?

let testLogger (source:seq<'a>) logger = 
    logger "Testing..." 
    let length = source |> Seq.length 
    logger "Got a length of %d" length 


let logger format = Printf.kprintf (printfn "%A: %s" System.DateTime.Now) format 
testLogger [1; 2; 3] logger 

가 이상적으로이 코드가 작동 싶지만에서 로거 기능을 전달하는 방법을 밖으로 작동하지 않을 수 있습니다. 불행하게도

+0

당신은 이것에 흥미가있을 것입니다 : http://stackoverflow.com/questions/5277902/printf-style-logging-for-f – Daniel

+0

나는 그것을 보았습니다. 그러나 그것은 제가 도움이되지 않습니다. 프레임 워크가 log4net에 대해 알기를 원합니다 –

+0

첫 번째 답변을 확인하십시오. log4net과 아무 관련이 없습니다. – Daniel

답변

10

, 당신은 다른 함수에 매개 변수로 printf 같은 함수를 통과 한 후 사용할 수 없습니다 복수의 다른 인수가있는 . 문제는 printf이 유형 Printf.TextWriterFormat<'a> -> 'a의 일반적인 기능이라는 것입니다. 유형 매개 변수 'a으로 대체 된 실제 유형은 printf을 사용할 때마다 다른 함수 유형입니다 (예 : "%s"의 경우 'a == string -> unit 등).

F #에서는 자체 함수 인 매개 변수를 가질 수 없습니다. 제네릭 함수는 전역 함수 여야하지만 실제로 문자열과 함께하는 함수로 매개 변수화 할 수 있습니다. 이 kprintf이 무엇을 근본적으로, 그러나 당신이 당신의 기능을 더 나은 이름을 지정할 수 있습니다 : 것 로거에 의해 파라미터 기능

let logPrintf logger format = 
    Printf.kprintf logger format 

예를 : 토마스가 지적 하듯이

let testLogger (source:seq<'a>) logger = 
    logPrintf logger "Testing..." 
    let length = source |> Seq.length 
    logPrintf logger "Got a length of %d" length 


let logger = printfn "%A: %s" System.DateTime.Now 
testLogger [1; 2; 3] logger 
12

, F 번호의 기능을 할 수있는 ' 다형 인자가 필요합니다. 이 경우 로깅에 사용되는 string -> unit 함수를 전달할 수 있어야하기 때문에 Tomas의 접근 방식이 매우 유용하다고 생각합니다.

type ILogger = abstract Log : Printf.StringFormat<'a,unit> -> 'a 

let testLogger (source:seq<'a>) (logger:ILogger) = 
    logger.Log "Testing..." 
    let length = source |> Seq.length   
    logger.Log "Got a length of %d" length 

let logger = { 
    new ILogger with member __.Log format = 
     Printf.kprintf (printfn "%A: %s" System.DateTime.Now) format } 

: 당신이 정말 다형성 함수의 해당 주위에 전달하려는 경우

그러나, 한 가지 해결 방법은 해당 유형의 인스턴스를 하나의 일반적인 방법으로 간단한 유형을 생성하고, 전달하는 것입니다 형식 유추를 더 잘이 일을하려면, 당신은 간단한 도우미 기능 모듈을 정의 할 수 있습니다 :

module Log = 
    let logWith (logger : ILogger) = logger.Log 

let testLogger2 (source:seq<'a>) logger = 
    Log.logWith logger "Testing..." 
    let length = source |> Seq.length   
    Log.logWith logger "Got a length of %d" length 

이 최종 결과는 토마스의 솔루션처럼 많이 보이지만, 당신이 정의하는 방법에 좀 더 유연성을 제공하여 로거, 실제로 또는 그렇지 않을 수도 있음 이 경우에 당신에게 유용 할 것입니다.

+0

+1 글로벌 기능을 피할 수있는 첫 번째 방법이 마음에 듭니다. –

+0

좋은 접근 방법. 저는 Tomas를 올바른 답으로 표시했습니다,하지만 저는이 접근법을 좋아합니다. –

관련 문제