I understand (hopefully) the way record syntax generates accessor functions, such that
data Person = Person { firstName :: String, lastName :: String }
will create firstName
and lastName
functions that take in a Person
-type value and return the corresponding fields. I’ve also noticed that it seems to be common practice to create wrapped types with a single record field prefixed with un
, which I assume is short for unwrap
as it can be used to unwrap and retrieve the underlying value. (If this is wrong, please correct me!)
One thing that’s a bit confusing, though, is when the field name is prefixed with an action verb, like:
newtype Writer w a = Writer { runWriter :: (a, w) }
As far as I can tell, runWriter
is merely an accessor function like firstName
or lastName
, returning what appears to be a tuple. Does it actually “run” anything when it’s called? If not, why is it common practice to use that field name?
My current guess: the Writer type is a monad and monads represent computations, so the retrieval of the underlying value is considered to be “executing” the monad.
A second guess: since Haskell is lazy, perhaps the underlying value of a monad isn’t evaluated until it gets unwrapped, setting off a chain of dependency evaluations… analogous to the Quantum Physics idea of observation triggering a wave function collapse.
Thoughts?
Edit: Looking at some example writer monad code, I’m definitely missing something here, as calling runWriter
does appear to execute some code, rather than just returning a record field. This seems weird to me… am I conceptualizing record fields wrong? Why does firstName person
just return a field while runWriter writer
executes code?
Edit 2: I think I might get it now… I’m not thinking “lazily” enough. When I see runWriter myWriter
and myWriter
is defined as a do
block, I think I should translate that in my head to runWriter(myWriter())
, as myWriter
is actually a function that returns the writer, and runWriter
triggers the evaluation of that writer-returning function… I think?