I am learning functional programming style. In Don't Fear the Monads, Brian Beckman gave a brilliant introduction about Monad. He mentioned that Monad is about composition of functions so as to address complexity.
A Monad includes a
unit
function that transfers type T to an amplified type M(T); and a Bind function that, given function from T to M(U), transforms type M(T) to another type M(U). (U can be T, but is not necessarily).
In my understanding, the language implementing monad should be type-checked statically. Otherwise, type errors cannot be found during compilation and "Complexity" is not controlled. Is my understanding correct?
Statically Typed Languages Some common examples of programming languages that belong to this category are Java, Haskell, C, C++, C#, Scala, Kotlin, Fortran, Go, Pascal, and Swift.
Haskell is a statically typed language. Every expression in Haskell has a type, including functions and if statements. The compiler can usually infer the types of expressions, but you should generally write out the type signature for top level functions and expressions.
A statically-typed language is a language (such as Java, C, or C++) where variable types are known at compile time. In most of these languages, types must be expressly indicated by the programmer; in other cases (such as OCaml), type inference allows the programmer to not indicate their variable types.
Protection from Runtime Errors This is the main benefit of statically typed languages. Many runtime errors become compile time errors as the compiler ensures that you are writing 'correct' code. This leads to a much smoother development experience.
There are lots of implementations of monads in dynamically typed languages:
In general, the Church-Turing-Thesis tells us that everything that can be done in one language can also be done in every other language.
As you can probably tell from the selection of examples above, I am (mostly) a Ruby programmer. So, just as a joke, I took one of the examples above and re-implemented it in a language that I know absolutely nothing about, that is usually thought of as a not very powerful language, and that seems to be the only programming language on the planet for which I was not able to find a Monad tutorial. May I present to you … the Identity Monad in PHP:
<?php
class Identity {
protected $val;
public function __construct($val) { $this->val = $val; }
public static function m_return($a) { return new Identity($a); }
public static function m_bind($id_a, $f) { return $f($id_a->val); }
}
var_dump(Identity::m_bind(
Identity::m_return(1), function ($x) {
return Identity::m_return($x+1);
}
));
?>
No static types, no generics, no closures necessary.
Now, if you actually want to statically check monads, then you need a static type system. But that is more or less a tautology: if you want to statically check types, you need a static type checker. Duh.
With regards to your question:
In my understanding, the language implementing monad should be type-checked statically. Otherwise, type errors cannot be found during compilation and "Complexity" is not controlled. Is my understanding correct?
You are right, but this has nothing to do with monads. This is just about static type checking in general, and applies equally well to arrays, lists or even plain boring integers.
There is also a red herring here: if you look for example at monad implementations in C#, Java or C, they are much longer and much more complex than, say, the PHP example above. In particular, there's tons of types everywhere, so it certainly looks impressive. But the ugly truth is: C#'s, Java's and C's type systems aren't actually powerful enough to express the type of Monad
. In particular, Monad
is a rank-2 polymorphic type, but C# and Java only support rank-1 polymorphism (they call it "generics", but it's the same thing) and C doesn't support even that.
So, monads are in fact not statically type-checked in C#, Java and C. (That's for example the reason why the LINQ monad comprehensions are defined as a pattern and not as a type: because you simply cannot express the type in C#.) All the static type system does, is make the implementation much more complex, without actually helping. It requires a much more sophisticated type system such as Haskell's, to get actual type-safety for monads.
Note: what I wrote above only applies to the generic monad
type itself, as @Porges points out. You can certainly express the type of any specific monad, like List
or Maybe
, but you cannot express the type of Monad
itself. And this means that you cannot type-check the fact that "List
IS-A Monad
", and you cannot type-check generic operations that work on all instances of Monad
.
(Note that checking that Monad
also obeys the monad laws in addition to conforming to the monad type is probably too much even for Haskell's type system. You'd probably need dependent types and maybe even a full-blown automatic theorem prover for that.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With