3
votes

I am learning about monads in the book 'Learn You a Haskell for Great Good!' by Miran Lipovaca. I am reading about how the Control.Monad.Writer module exports the Writer w a type along with its Monad instance and some useful functions for dealing with values of this type.

For the following code:

newtype Writer w a = Writer { runWriter :: (a,w) }

I know that the a type parameter represents the type of some value, and the w type parameter represents the type of the attached monoid value. Am I correct in saying that by passing w and a to the Writer type constructor, you get a Writer monad in return, with this monad only having one function which is the runWriter function?

In the book it says that the runWriter function takes a tuple that's wrapped in a Writer newtype and unwraps it, returning a simple tuple. However the type declaration of runWriter is runWriter :: (a,w), it doesn't take any parameters as input. How does runWriter take a tuple that's wrapped in a newtype and return just a simple tuple?

1

1 Answers

5
votes

Am I correct in saying that by passing w and a to the Writer type constructor, you get a Writer monad in return,

No, Writer w is the monad (assuming Monoid w). Writer w a is a type.

with this monad only having one function which is the runWriter function?

No, the type Writer w a is, essentially, a pair type (a,w). There are no functions inside.

You can pretend that the type is defined in the following way

newtype Writer w a = Writer (a,w)

and that there is a separate convenience "unwrapping" function

runWriter :: Writer w a -> (a,w)
runWriter (Writer p) = p

You can think of these functions as being mutual inverses:

Writer :: (a,w) -> Writer w a        -- "wrapper"
runWriter :: Writer w a -> (a,w)     -- "unwrapper"

Using the record syntax in data declarations indeed defines functions taking an implicit argument (in addition to the data type itself). Any type

data T = MkT { f :: Int, g :: String }

defines the data type T, data constructor MkT, and functions f, g having an implicit T argument,

f :: T -> Int               -- f (MkT i _) = i
g :: T -> String            -- g (MkT _ s) = s

Record syntax with newtypes works in the same way, except that there must be exactly one field (named runWriter, in your example).