2017-01-14 5 views
1

に私はまだHaskellのを学習し、いくつかの機能をデバッグし、通常は特定の操作を開始したときの感覚を取得し、停止するためにタイムスタンプ機能を持っていながら:印刷タイムスタンプデバッグはHaskellの

doSomeAction :: String -> IO() 
doSomeAction arg1 = do 
    putStrLn =<< makeTime 
    theThingthatTakesAwhile arg1 
    putStrLn =<< makeTime 
    where 
    makeTime = (formatTime defaultTimeLocale "%Y%m%d%H%M%S") <$> getZonedTime 

は私=<<whereです<$>を含むIO文節でIOと対話する合理的な方法getZonedTime

λ> :t getZonedTime 
getZonedTime :: IO ZonedTime 

これは私や読者、または非慣用的な誤解ですか?

出力は次のとおりです。

まさに私が見たいものです
20170114152312 
Doing some long function.... 
20170114152336 

---それは私が必要なものを私に伝えます。その効果を得るにはちょうどputStrLn =<< somethingに変わっているようです。

答えて

3

コードは完全に問題ありません。ハスケルに慣れているプログラマーなら、すぐにそれを理解するはずです。私自身のスタイルで

は、しかし、私はletdo内のブロック好む傾向にある:

doSomeAction :: String -> IO() 
doSomeAction arg1 = do 
    let makeTime = formatTime defaultTimeLocale "%Y%m%d%H%M%S" <$> getZonedTime 
    putStrLn =<< makeTime 
    theThingthatTakesAwhile arg1 
    putStrLn =<< makeTime 

または多分

doSomeAction :: String -> IO() 
doSomeAction arg1 = do 
    let printTime = putStrLn . formatTime defaultTimeLocale "%Y%m%d%H%M%S" =<< getZonedTime 
    printTime 
    theThingthatTakesAwhile arg1 
    printTime 

のいくつかのバリエーションがなく、再び、それは個人の好みの問題です。

1

ロギングライブラリを使用すると、より効果的です。たとえば、hsloggerです。タイムスタンプ付きのメッセージを印刷できます。あなたはこの質問の下での用途の例を見ることができます:hslogger & Duplicate Log Lines

UPD:ログのタイムスタンプを持つ

ここでは、ログの初期化とモジュールの完全な例です:

import   Control.Concurrent  (threadDelay) 
import   System.IO     (stdout) 
import   System.Log.Formatter  (simpleLogFormatter) 
import   System.Log.Handler  (setFormatter) 
import   System.Log.Handler.Simple (streamHandler) 
import   System.Log.Logger   (Priority (DEBUG), debugM, rootLoggerName, 
              setHandlers, setLevel, updateGlobalLogger) 

initLogging :: IO() 
initLogging = do 
    stdOutHandler <- streamHandler stdout DEBUG >>= \lh -> return $ 
      setFormatter lh (simpleLogFormatter "[$loggername:$time] $msg") 
    updateGlobalLogger rootLoggerName (setLevel DEBUG . setHandlers [stdOutHandler]) 

doSomeAction :: String -> IO() 
doSomeAction arg1 = do 
    debugM "someAction" "before long thing" 
    theThingThatTakesAWhile arg1 
    debugM "someAction" "after long thing" 

theThingThatTakesAWhile :: String -> IO() 
theThingThatTakesAWhile arg = threadDelay (3 * 10^(6 :: Int)) >> putStrLn arg 

main :: IO() 
main = do 
    initLogging 
    doSomeAction "some long action" 

と出力:

[someAction:2017-01-16 17:19:49 MSK] before long thing 
some long action 
[someAction:2017-01-16 17:19:52 MSK] after long thing 

あなたはあなたのメッセージの正確なフォーマットを指定するためにtfLogFormatter関数を使用することができるよりもタイムスタンプ(秒だけ)として印刷される時間をしたい。

+0

内部で 'updateGlobalLogger rootLoggerName'を簡単に呼び出すことができるように、私の関数の外で初期化を宣言する方法を理解する助けになる例を挙げることができますか? – Mittenchops

+0

@Mittenchops私はロギング初期化の例を使って答えを更新しました。 – Shersh