Nim can be Haskell This is an example from the real project. This code reads application config from json with defaults handling in functional style. It uses data macro from the nimboost library to generate immutable data structures, constructors, copy operators, and functional types and control structures from nimfp library.

import json,
       future,
       fp,
       boost.typeutils

data HttpConfig, exported, copy:
  host: string
  port: int
data HttpConfigDef, exported:
  host = "localhost".some
  port = 8280.some

data SmtpConfig, exported:
  host: string
  port: Option[int]
  credentials: Option[tuple[user: string, pass: string]]
  emailFrom: string
  emailTo: string
data SmtpConfigDef, exported:
  host = string.none
  port = int.none.some
  credentials = none(tuple[user: string, pass: string]).some
  emailFrom = string.none
  emailTo = string.none

data DbConfig, exported:
  host: string
  port: int
  dbName: string
  user: Option[string]
  password: Option[string]
  createTables: bool
data DbConfigDef, exported:
  host = "localhost".some
  port = 5432.some
  dbName = string.none
  user = string.none.some
  password = string.none.some
  createTables = true.some

data LogConfig, exported, copy:
  file: Option[string]
  debug: bool
data LogConfigDef, exported:
  file = string.none.some
  debug = false.some

data ServiceConfig, exported:
  http: HttpConfig
  db: DbConfig
  smtp: Option[SmtpConfig]
  log: LogConfig
data ServiceConfigDef, exported:
  http = initHttpConfigDef()
  db = initDbConfigDef()
  smtp = initSmtpConfigDef()
  log = initLogConfigDef()

proc defaultConfig: ServiceConfigDef = initServiceConfigDef()

proc getConfig(d: HttpConfigDef): Option[HttpConfig] = act do:
  h <- d.host
  p <- d.port
  yield initHttpConfig(host = h, port = p)

proc getConfig(d: SmtpConfigDef): Option[SmtpConfig] = act do:
  h <- d.host
  p <- d.port
  c <- d.credentials
  f <- d.emailFrom
  t <- d.emailTo
  yield initSmtpConfig(host = h, port = p, credentials = c, emailFrom = f, emailTo = t)

proc getConfig(d: DbConfigDef): Option[DbConfig] = act do:
  h <- d.host
  p <- d.port
  db <- d.dbName
  user <- d.user
  pass <- d.password
  createTables <- d.createTables
  yield initDbConfig(host = h, port = p, dbName = db, user = user, password = pass, createTables = createTables)

proc getConfig(d: LogConfigDef): Option[LogConfig] = act do:
  file <- d.file
  debug <- d.debug
  yield initLogConfig(file = file, debug = debug)

proc getConfig(d: ServiceConfigDef): Option[ServiceConfig] = act do:
  http <- d.http.getConfig
  db <- d.db.getConfig
  smtp <- d.smtp.getConfig
  log <- d.log.getConfig
  yield initServiceConfig(http = http, db = db, smtp = smtp.some, log = log)

template getOption(n: JsonNode, name: untyped): untyped =
  mixin defValue
  const notFound = "Required parameter \"" & astToStr(name) & "\" not found"
  when type(defValue.name.elemType) is Option:
    var x: defValue.name.elemType
    (n.some.rightS >>= (mget(astToStr(name)) >=> mvalue(type(x.get))))
    .optionT.map((v: type(x.get)) => v.some).getOrElseF(() => defValue.name.asEither(notFound))
  else:
    (n.some.rightS >>= (mget(astToStr(name)) >=> mvalue(defValue.name.elemType)))
    .optionT.getOrElseF(() => defValue.name.asEither(notFound))

template getOptionT(n: JsonNode, name: untyped): untyped =
  mixin defValue
  n.getOption(name).map((v: type(defValue.name.get)) => v.some).optionT

proc parseHttpConfig(
  node: Option[JsonNode],
  defValue: HttpConfigDef
): EitherS[HttpConfig] =
  node.map do(n: JsonNode) -> auto:
    act do:
      host <- n.getOption(host)
      port <- n.getOption(port)
      yield initHttpConfig(host = host, port = port)
  .getOrElse(defValue.getConfig.asEither("HTTP configuration not found"))

proc parseDbConfig(
  node: Option[JsonNode],
  defValue: DbConfigDef
): EitherS[DbConfig] =
  node.map do(n: JsonNode) -> auto:
    act do:
      host <- n.getOption(host)
      port <- n.getOption(port)
      dbName <- n.getOption(dbName)
      user <- n.getOption(user)
      password <- n.getOption(password)
      createTables <- n.getOption(createTables)
      yield initDbConfig(host = host, port = port, dbName = dbName, user = user, password = password, createTables = createTables)
  .getOrElse(defValue.getConfig.asEither("Database configuration not found"))

proc parseSmtpConfig*(
  node: Option[JsonNode],
  defValue: SmtpConfigDef
): EitherS[Option[SmtpConfig]] =
  node.map do(n: JsonNode) -> auto:
    act do:
      host <- n.getOption(host)
      port <- n.getOption(port)
      credentials <- act do:
        u <- n.mget("user").optionT.flatMapF((v: JsonNode) => value(string, v))
        p <- n.mget("pass").optionT.flatMapF((v: JsonNode) => value(string, v))
        yield (user: u, pass: p)
      .run
      emailFrom <- n.getOption(emailFrom)
      emailTo <- n.getOption(emailTo)
      yield initSmtpConfig(host = host, port = port, credentials = credentials, emailFrom = emailFrom, emailTo = emailTo)
  .sequence

proc parseLogConfig(
  node: Option[JsonNode],
  defValue: LogConfigDef
): EitherS[LogConfig] =
  node.map do(n: JsonNode) -> auto:
    act do:
      file <- n.getOption(file)
      debug <- n.getOption(debug)
      yield initLogConfig(file = file, debug = debug)
  .getOrElse(defValue.getConfig.asEither("Log configuration not found"))

proc parseConfig*(
  node: Option[JsonNode],
  defValue: ServiceConfigDef = defaultConfig(),
  overrideHttpHost = string.none,
  overrideHttpPort = int.none,
  overrideLogFile = string.none,
  overrideLogDebug = bool.none
): EitherS[ServiceConfig] = act do:
  httpNode <- node.mget("http")
  http <- act do:
    h1 <- parseHttpConfig(httpNode, defValue.http).mapLeft(e => "HTTP configuration: " & e)
    h2 <- overrideHttpHost.map(v => h1.copyHttpConfig(host = v)).getOrElse(h1).rightS
    yield overrideHttpPort.map(v => h2.copyHttpConfig(port = v)).getOrElse(h2)
  dbNode <- node.mget("db")
  db <- parseDbConfig(dbNode, defValue.db).mapLeft(e => "Database configuration: " & e)
  smtpNode <- node.mget("smtp")
  smtp <- parseSmtpConfig(smtpNode, defValue.smtp).mapLeft(e => "SMTP configuration: " & e)
  logNode <- node.mget("log")
  log <- act do:
    l1 <- parseLogConfig(logNode, defValue.log).mapLeft(e => "Log configuration: " & e)
    l2 <- overrideLogFile.map(v => l1.copyLogConfig(file = v.some)).getOrElse(l1).rightS
    yield overrideLogDebug.map(v => l2.copyLogConfig(debug = v)).getOrElse(l2)
  yield initServiceConfig(http = http, db = db, smtp = smtp, log = log)

2017-03-16 07:03:20
This is really awesome and shows off Nim's best feature
2017-03-18 09:14:47