
Haskell, Monads and Purity - akerl_
http://jelv.is/blog/Haskell-Monads-and-Purity/
======
spion
I think that the misconception the author talks about happens because a noun
is used for the properties of an object.

An adjective such as "monadic" can be used instead: "In Haskell, IO actions
are monadic because the IO type has a flatMap (bind) operator and a unit
(return) function which satisfy left identity, right identity and
associativity".

All of the above are the properties (traits?) of the IO datatype. Monads (in
Haskell) don't "exist" by themselves, they're just a property.

~~~
dllthomas
I think a part of it is a slight weirdness of Haskell typeclasses. In math,
the noun "monad" refers to is a triple containing a functor and two natural
transformations. The equivalent noun in Haskell would be the typeclass
_instance_ for a particular type. However, because Haskell (basically) only
allows one instance per type, you select different instances by choosing a
different (possibly equivalent, as with newtype) type, and so there is some
natural conflation that arises in the language people use to talk about these
things.

The dynamic may be slightly clearer for semigroups. In mathematics, a
semigroup is a pair containing a set and an (associative) operation on that
set. In Haskell we say things like "ByteString is a semigroup" but that's
short for "there is a semigroup where the set is all possible ByteStrings" and
you assume the people you're talking to understand what the operation is
because there is only one instance of Semigroup commonly defined for
ByteString.

------
MichaelDickens
I think there's an important difference between saying Haskell uses monads to
do IO and we use rings to do arithmetic. In Haskell, understanding monads
helps you do lots of tasks more effectively, since so many data types are
monads: IO, Maybe, lists, ...

In math, there are other uses for rings, but if you're using them, it helps to
know a little ring theory. Similarly, if you want to use any of the other
Haskell monads, it helps to know how monads work.

~~~
Chinjut
You say "I think there's an important difference", but then, you end up saying
precisely the same things about monads and rings. What was the difference?

------
lpw25
> This is why unsafePerformIO is unsafe: it’s completely foreign to the
> programming model

Maybe, although it is also not _type safe_ because Haskell doesn't have a
value restriction for polymorphism. (or looked at another way Haskell's value
restriction assumes that function application is a value).

~~~
tikhonj
And, by extension, we don't have a value restriction _because_ unsafePerformIO
is foreign to our programming model. If it was actually part of the
abstraction, Haskell would be a lot more like ML!

------
dschiptsov
why, it is just an ADT which could be implemented in almost any language.
Something like tagging a value with a type-tag and then define whole bunch of
constructors and selectors, and then procedures which removes the tag, applies
a given procedure and sticks the the tag to the result.

    
    
      (cons 'safe x)
    

OK, In Haskell this stuff could be type-checked, which means only that the
arguments to functions and its return values are of correct type (tags are
present).

But calling this a "safety" is a silly meme.)

~~~
chongli
Why is it silly? Haskell libraries derive a lot of safety benefit out of being
able to type-check different kinds of effects. One example is the STM library
which uses this property to prohibit IO within an atomic transaction. Since
transactions may be aborted and/or repeated, it's important to ensure no
interaction with the outside world takes place within them lest these effects
be repeated.

~~~
dschiptsov
Because it has nothing to do with safety, but with manipulating of specialized
data-structures. "Instantiation of a value of a given type" in Haskell is
what? Calling a "type-constructor" which is just what? Constructor - a
procedure which returns a data-structure.

Now, how CL style type-tagging is fundamentally different form what Haskell
does

What Haskell does in no more "safer" than if I do tag-checking at runtime.
(That's why CL is called a strong-typed language). So this is why it is a
silly meme.

The idea that compile-time checks is much better than runtime checks is also
not obvious (Java's and other commercial languages nonsense about type safety
aside - Java is no more safe than CL).

What is better - to clutter the code with explicit type annotation or clutter
the code with explicit type-tag checking in the runtime code is another
question.)

I personally love Lisp and Erlang with "everything is a pointer to a tagged
value" semantics.

~~~
freyrs3
Safety as you're using is not the concept that Haskeller's refer to when they
talk about the language. "Type safety" is a very precise term that refers to
several proofs about the semantics of the language.

See:
[http://jspha.com/posts/all_you_wanted_to_know_about_types_bu...](http://jspha.com/posts/all_you_wanted_to_know_about_types_but_were_afraid_to_ask/#formal-
terminology)

~~~
dschiptsov
OK. All I am trying to say is that there are different kinds of strong-typed
languages, and neither one is "safer" or superior.

~~~
the_af
I don't think that's true, though. There _are_ "safer" languages (for the
informal notion of safety we're discussing). You're free to argue that the
safety you gain in one language is not worth the effort, but you cannot argue
that every language is equally safe.

~~~
dschiptsov
Why no? The technical term "type safety" as described in the link above,
implies that each value has a type, this type doesn't change during the
evolution of a program, etc. How does it differ from the guarantees we have in
so-called strong-typed languages?

The fact that compiler is refusing to compile type-mismatching expression for
a simple built-in types doesn't imply that it is "safer". Other languages,
notably Lisp and Erlang will catch and signal the same error later, at
runtime.

I am not a Haskell guru, but what I see, especially in the case of Monads, is
an implicit type-tagging with additional tag - name it State, or IO, or Safe
and then type-checking against them.

I cannot see the fundamental difference which gives that "extra safety".

~~~
imanaccount247
>How does it differ from the guarantees we have in so-called strong-typed
languages?

If you mean "dynamically typed" languages, then it differs in that they do not
have types.

>The fact that compiler is refusing to compile type-mismatching expression for
a simple built-in types doesn't imply that it is "safer"

No, it does not imply that. It means that.

>Other languages, notably Lisp and Erlang will catch and signal the same error
later, at runtime.

Precisely. So if that piece of code was not executed, you do not know that it
is incorrect. If that branch is only followed rarely, your incorrect code is
out there in production waiting to blow up when it finally does run that
branch.

>I am not a Haskell guru, but what I see, especially in the case of Monads, is
an implicit type-tagging with additional tag

The article in question does a good job of explaining monads.

------
teyfille
Haskell's rhetoric has always seemed a bit Pharisaical to me: "Though the
runtime is impure, Our Code is uncontaminated by the taint of side effects".

~~~
serve_yay
I don't know what that word means, to me it has always seemed a bit silly. The
whole point of software is its side effects, you will always have some. So
instead of admitting that, you do a little dance to pretend side effects don't
really happen in your program. It's very strange to me.

~~~
dllthomas
On the contrary, the whole point of software is its _effects_. They are only
_side_ effects if you're not able to encode the effects in the type of the
function. Haskell doesn't treat effects as _less_ important, it treats them as
_more_ important by allowing (and, as a consequence, forcing) you to reason
about them explicitly in compiler-checked ways. This lets you do great things
like have STM transactions with a guarantee that retrying them won't screw
anything up. It also lets you define your own kinds of effects that you want
to track and plumb them through your system in a coherent way. And it lets you
write code that doesn't care what kind of effects it's working with, and yet
which can still be used in contexts like STM that need to apply restrictions.

~~~
marcosdumay
What I'm not liking about this line of reasoning is that in practice Haskell
seems to not go far enough[1].

Yes, you have to declare your effects. In practice that means that most of
your code returns IO, and isn't constrained anymore. I don't know if this is a
library feature, or an essential feature of the language[2], but it would be
very interesting for example to put a GUI together by computing events in
functions that returned an "Event" monad, widgets in functions that returned a
"GUI" monad, database access in functions in a "DB" monad, etc. Instead, all
of those operate on IO.

[1] A completely subjective assessment. [2] I've though for a short while on
how to code that, but didn't got any idea I liked.

~~~
tikhonj
It's not clear that that's the distinction that makes the most sense. I think
typing based on capability makes more sense than typing based on purpose. So
you would have a type like FSRead and FSWrite which could only read and write
from the filesystem, for example. (Ideally with a nice way to combine the
two!)

Of course, you can do this as a library. In fact, this is an example use
case[1] for Safe Haskell which also prevents people from circumventing your
types with unsafePerformIO and friends.

Moreover, some existing libraries already take similar approaches. FRP
libraries extract reactive systems (like events but also continuously changing
signals) into their own types. A button gives you a _stream_ of type Event ()
rather than an explicit callback system using the IO type. Check out reactive-
banana[2] (my favorite FRP library from the current crop) for a nice example.

Similarly, people use custom monads to ensure things get initialized
correctly, which has a similar effect to what you're talking about. The
Haskell DevIL bindings for Repa[3] come to mind because they have an IL type
which lets you load images and ensures the image loader is initialized
correctly exactly once.

Sure, in the end, everything will need to be threaded through IO and main to
actually run, but you can—and people do—make your intermediate APIs safer by
creating additional distinctions between effects.

[1]:
[http://www.haskell.org/ghc/docs/7.8.3/html/users_guide/safe-...](http://www.haskell.org/ghc/docs/7.8.3/html/users_guide/safe-
haskell.html#idp28666848)

[2]: [http://hackage.haskell.org/package/reactive-
banana](http://hackage.haskell.org/package/reactive-banana)

[3]: [http://hackage.haskell.org/package/repa-
devil](http://hackage.haskell.org/package/repa-devil)

~~~
marcosdumay
That's great to know. Looks like I have a ton of stuff to read now.

------
brandonbloom
I sighed at the title, but was glad that I read the first paragraph. Very well
put!

I guess that I've got to read the rest of the article now too...

~~~
tikhonj
Yeah, this was more of a draft than a finished article. I didn't realize
anyone was following my blog :P. It's a working title at best—it doesn't
really reflect what I wanted to talk about... but then, I'm not sure the
second half or so does either.

~~~
carterschonwald
is all of the code meant to be invisible? :)

~~~
tikhonj
Oh, that's a weird bug with the fonts... which I thought I had fixed.
Unfortunately, I can't reproduce it locally, so I'm not sure I can do much
about it right now.

~~~
carterschonwald
looks fine now

