Haskell I/O Handler is my friend now
Tags: haskell
Published: 2023-05-07 03:02:57

---
title: Haskell I/O Handler is my friend now
published: true
description: 
tags: haskell
//cover_image: https://direct_url_to_image.jpg
---

I'm learning Haskell and it feeds me some new experiences, but I'm scary against its difficulties sometimes. (Actually so many times.)


At a glance, Haskell's I/O handler looks difficult but not actually. 

I figured out that Haskell's I/O handler is so simple and there is no difference with other language's ones like python's file like object.

Let's go with a concrete example. 

I wrote logging function for my interest like below.(Please ignore detail and structures, naming.)

```haskell
module Main where

import Data.Time (UTCTime, getCurrentTime)
import Prelude hiding (log)
import System.IO (stdout, Handle, openFile, IOMode (WriteMode), hFlush, hClose, hPutStrLn)

data Severity
  = Debug
  | Info
  | Warning
  | Error
  deriving (Ord, Eq)

severityLabel :: Severity -> Char
severityLabel Debug = 'D'
severityLabel Info = 'I'
severityLabel Warning = 'W'
severityLabel Error = 'E'

newtype LogFormatter = LogFormatter {format :: UTCTime -> Severity -> String -> String}

data Logger = Logger
  { loggerSeverity :: Severity,
    loggerHandler :: Handle,
    loggerFormatter :: LogFormatter
  }

log :: String -> Logger -> IO ()
log msg logger = do
  timestamp <- getCurrentTime
  let formatter = loggerFormatter logger
      severity = loggerSeverity logger
      handler = loggerHandler logger
  hPutStrLn handler (format formatter timestamp severity msg)
  hFlush handler

basicFormatter :: LogFormatter
basicFormatter = LogFormatter formatter
  where
    formatter t s msg = show t <> " - " <> [severityLabel s] <> ": " <> msg

stdInLogger :: Severity -> Logger
stdInLogger sev = Logger sev stdout basicFormatter

main :: IO ()
main = do
  let debugLogger = stdInLogger Debug
  log "this is logger" debugLogger

  let logfilePath = "out.log"
  hdl <- openFile logfilePath WriteMode
  let fileLogger = Logger Debug hdl basicFormatter
  log "this is on file" fileLogger
  hClose hdl
``` 

This code generates like `2023-05-07 02:27:25.997054484 UTC - D: <arbitrary message>` to stdout and a logfile.


When I am going to display some messages to stdout, I use `print` and `putStrLn` usually.

As well as I am goint to write out some messages to any files, I use `openFile` and `writeFile` usually.

In above example case, I have to make the something to write out to real world via I/O handler abstraction, so I guess my function `log` is the one of core concept of Haskell's I/O handleing.

```haskell
log msg logger = do
  timestamp <- getCurrentTime
  let formatter = loggerFormatter logger
      severity = loggerSeverity logger
      handler = loggerHandler logger
  hPutStrLn handler (format formatter timestamp severity msg)
  hFlush handler
``` 

`log` uses `h` prefixed function for `System.IO.Handle`. So this is 
 all things about Haskell's I/O handling.

I just do passing `System.IO.Handle` type something to the I/O handle wrapper and this wrapper just writes some messages to handler's buffer and finally flushes, NO DIFFICULTIES! YAY!

Haskell is difficult to me. This truth is maybe never changed forever to me. 

But I learned those difficurlties are from some impressions.

Forgetting type system, Monad, etc and treating as a just function makes me more easy to understanding what is it.

Now Haskell's I/O handling is no fear, it is my friend (maybe).