The Writer Monad
================

.. automodule:: hymn.types.writer
  :members:
  :show-inheritance:

.. function:: execute

  alias of :meth:`Writer.execute`

.. function:: run

  alias of :meth:`Writer.run`


Predefined Writers
------------------

.. autoclass:: ComplexWriter
.. autoclass:: DecimalWriter
.. autoclass:: FloatWriter
.. autoclass:: FractionWriter
.. autoclass:: ListWriter
.. autoclass:: IntWriter
.. autoclass:: StringWriter
.. autoclass:: TupleWriter


Hy Specific API
---------------

.. class:: writer-m

  alias of :class:`Writer`


Functions
^^^^^^^^^

.. function:: writer-with-type

  alias of :func:`writer_with_type`

.. function:: writer-with-type-of

  alias of :func:`writer_with_type_of`


Reader Macro
^^^^^^^^^^^^

.. function:: + [w]

  create a writer that logs ``w``


Writers
^^^^^^^

.. class:: complex-writer-m

  alias of :class:`ComplexWriter`

.. class:: decimal-writer-m

  alias of :class:`DecimalWriter`

.. class:: float-writer-m

  alias of :class:`FloatWriter`

.. class:: fraction-writer-m

  alias of :class:`FractionWriter`

.. class:: list-writer-m

  alias of :class:`ListWriter`

.. class:: int-writer-m

  alias of :class:`IntWriter`

.. class:: string-writer-m

  alias of :class:`StringWriter`

.. class:: tuple-writer-m

  alias of :class:`TupleWriter`


Examples
--------


Do Notation
^^^^^^^^^^^

.. code-block:: clojure

  => (require hymn.dsl)
  => (import [hymn.types.writer [tell]])
  => (do-monad [_ (tell 1) _ (tell 2)] nil)
  IntWriter((None, 3))
  => (do-monad [_ (tell "hello ") _ (tell "world!")] nil)
  StrWriter((None, 'hello world!'))


Operations
^^^^^^^^^^

:func:`writer` creates a :class:`Writer`

.. code-block:: clojure

  => (import [hymn.types.writer [writer]])
  => (writer nil 1)
  IntWriter((None, 1))

:func:`tell` adds message into accumulated values of writer

.. code-block:: clojure

  => (import [hymn.types.writer [tell writer]])
  => (.run (tell 1))
  (None, 1)
  => (.run (>> (writer 1 1) tell))
  (None, 2)

:func:`tell` and :func:`writer` are smart enough to create writer of
appropriate type

.. code-block:: clojure

  => (import [hymn.types.writer [tell writer]])
  => (writer nil "a")
  StrWriter((None, 'a'))
  => (writer nil 1)
  IntWriter((None, 1))
  => (writer nil 1.0)
  FloatWriter((None, 1.0))
  => (writer nil (, 1))
  TupleWriter((None, (1,)))
  => (writer nil [1])
  ListWriter((None, [1]))
  => (tell "a")
  StrWriter((None, 'a'))
  => (tell 1)
  IntWriter((None, 1))
  => (tell 1.0)
  FloatWriter((None, 1.0))
  => (tell (, 1))
  TupleWriter((None, (1,)))
  => (tell [1])
  ListWriter((None, [1]))

:func:`listen` get the value of the writer

.. code-block:: clojure

  => (import [hymn.types.writer [listen writer]])
  => (listen (writer "value" 42))
  IntWriter((('value', 42), 42))

:func:`censor` apply function to the output

.. code-block:: clojure

  => (import [hymn.types.writer [censor tell]])
  => (require hymn.dsl)
  => (def logs (do-monad [_ (tell [1]) _ (tell [2]) _ (tell [3])] nil))
  => (.execute logs)
  [1, 2, 3]
  => (.execute (censor sum logs))
  6


Reader Macro
^^^^^^^^^^^^

.. code-block:: clojure

  => (require hymn.dsl)
  => (require hymn.types.writer)
  => ;; reader macro + works like tell
  => #+1
  IntWriter((None, 1))
  => (.execute #+1)
  1
  => (do-monad [_ #+1 _ #+2 _ #+4] 42)
  IntWriter((42, 7))
