2011-04-06 17 views
6

Dosya ve verilerin bazı işlemlerini yapmak için bir çerçeve oluşturmaya çalışıyorum. Mücadele ettiğim bir alan, çerçevenin bir kayıt fonksiyonunun nasıl sağlanacağıdır ve çerçevenin kullanımda kayıt hakkında herhangi bir bilgi sahibi olmadan mesajların raporlanmasını sağlar.Bir printf stil günlüğü argümanında bir F # işlevi nasıl oluşturabilirim?

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 

İdeal bu kod çalışmak istiyorum, ama ben logger işlevi geçmesine nasıl çalışamaz. Maalesef

+0

Bu şununla ilgini çekebilir: http://stackoverflow.com/questions/5277902/printf-style-logging-for-f – Daniel

+0

Bunu gördüm, ama yapmadığım gibi bana yardım etmiyor ' çerçevenin log4net hakkında bilinmesini isteyin –

+0

İlk cevabı kontrol edin, log4net ile ilgisi yoktur. – Daniel

cevap

10

, diğer fonksiyonlara parametre olarak printf gibi işlevleri geçmek ve daha sonra kullanamazsınız birden çok farklı bağımsız değişkenle . Sorun, printf'un Printf.TextWriterFormat<'a> -> 'a türünde genel bir işlevi olmasıdır. Tür parametresi 'a için değiştirilen gerçek tür, printf her kullanıldığında farklı olan bazı işlev türüdür (örn. "%s" vb. Için).

F # içinde, kendisinin genel bir işlevi olan bir işlevin parametresi olamaz. Genel işlev bazı küresel işlevler olmak zorundadır, ancak bunu aslında dizeyle bir şey yapan işlevle parametreleştirebilirsiniz. Bu kprintf ne temelde, ancak işlevini daha iyi adlandırabilir: olacağını kaydedici parametreli fonksiyon

let logPrintf logger format = 
    Printf.kprintf logger format 

örneği: Tomas işaret ettiği gibi

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 # işlevleri can' Polimorfik argümanlar gerektirir. Bu durumda, Tomas'ın yaklaşımının oldukça güzel olduğunu düşünüyorum çünkü muhtemelen sadece oturum açmak için kullanılan bir string -> unit işlevini geçmeniz gerekiyor.

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 } 

: Eğer gerçekten bir polimorfik fonksiyonunun eşdeğeri etrafında geçmek istiyorum yoksa

Ancak, bir geçici çözüm bu tür bir örneğini tek jenerik yöntemi ile basit bir türünü oluşturmak ve geçmektir tür kesmesi ile daha güzel bu işi yapmak için, basit bir yardımcı fonksiyonu ile bir modül tanımlayabiliriz:

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 

Bu sonuç Tomas'ın çözümü çok benziyor, ama sen nasıl tanımladığına biraz daha fazla esneklik sağlar senin aslında olabilir ya da olmayabilir logger Bu durumda sizin için yararlı olun.

+0

+1 Genel işlevlerden kaçınabileceğiniz gibi ilk yaklaşımınızı beğeniyorum. –

+0

Güzel yaklaşım. Tomas'ı doğru cevap olarak işaretledim, ama muhtemelen kullanacağım bu yaklaşımı seviyorum –

İlgili konular