Raul Miller-4 wrote:
>
> On Mon, Jan 18, 2010 at 6:37 AM, Viktor Cerovski
> <[email protected]> wrote:
>> That's true and important to emphasize: to fully use monads
>> in the Haskell sense of the word, we need a language that
>> supports what Haskell does: typed lambda calculus and
>> parametric types to begin with, or something equivalent to
>> that.
>>
>> So I'm not trying to define Haskell monads in J settings, that,
>> as I gather from surfing the web, seems to me impossible to
>> properly do in any of the other "standard" languages (the list is
>> long), but only to find an example of some operations that could
>> be considered as instances of Haskell monads.
> ...
>> [to fully use monads
>> in the Haskell sense of the word, we need a language that
>> supports what Haskell does: typed lambda calculus and
>> parametric types to begin with, or something equivalent to
>> that. [quote and emphasize added]]
> ...
>> Monads are considerably more tricky, because at first
>> glance, they are trying to solve a problem that does not even
>> appear as a problem in imperative languages.
>
> Personally, I have been deeply suspicious of Monads.
> [...]
>
Let us check out the infamous IO monad, particularly why we do
need parametric types, down to the last detail, in plain
English, and with the minimum use of Haskell and J, quoting only
one example from the link that Dan provided. This post is bit
longer but hopefully a quick read.
Let's consider a function that reads a character from a file:
getChar :: FileHandle -> Char
It takes one argument, a file handle of type FileHandle,
and returns the current character, of type Char, of the file
which handle it got. Such defined function, however, is *not*
pure: indeed, if we invoke it several times, we may easily get
different results, and function y=f(x), by its mathematical
definition, must *always* return the same y for the same x.
So sneaky Haskellians defined it like this:
getChar :: FileHandle -> IO Char
Notice the type: it is *not* Char, no, it is monadically encapsulated
or lifted Char. Wha'? What in the world is this IO screaming at us?
Well, it is a parametric type: IO is of type called Monad, which is defined
so that it takes *another* type as its argument, in this instance Char.
Is it pure, i.e does it always return the same value for the same
argument? First off, we would use it like:
...
a <- getChar handle; -- read the *first* char.
b <- getChar handle; -- read the *second* char.
...
As clear as day, a could get value, say, 'A', and b could be, say, 'B';
and the variable handle of course did not change in the code
snippet above.
So how do we check whether a function is for real a function?
Let's see in J:
(?0.0) -: (?0.0)
0
Here, we just demonstrated that verb ? is not a function.
Well uh, it's a generator, of random numbers.
Now we can finally do away with phony claims of purity by a
code snippet:
...
if getChar handle == getChar handle
then print "Pure..."
else print "Not pure! Ha!"
...
The only problem is, there is no predicate == provided
within IO to do the comparison. Clever move on Haskellians
part, but we already have a new strategy:
a=:?0.0
b=:?0.0
a-:b
0
So, the verb ? is still not a function. How about getChar?
To dispel any possible objection to our final proof that getChar
is not a function, we are going to be very precise about what
we print:
main = do{
...
a <- getChar handle; -- read the *first* char, then,
b <- getChar handle; -- read the *second* char.
if a==b
then print "a equal to b"
else print "a not equal to b!";
...
}
We meticulously prepare a file with all the different characters
in it, just to be sure, handle it to the program, and, Voila! we do get
the message "a not equal to b!"!
Now we notice something funny: we could compare a and b
because they are of the type Char, but the return type of getChar
is not Char---it is IO Char!
An immediate insight: y<-f x is *not* an assignment.
It resembles one so that it is easier to type programs,
without the need to use >>= (bind) and lambda functions like \a-> ....
Then, just to be sure: what does it mean to write:
a <- getChar handle; -- read the *first* char, then,
b <- getChar handle; -- read the *second* char.
It means the following: First do computation getChar handle,
which is a function (pure or not, we'll see) that returns some
IO Char result. Then, from such a returned IO Char, take the
Char part only, and assign it to a. Then, pass the whole returned
IO Char via syntactically hidden >>= to the next step of calculation,
which, of course, performs the next computation getChar handle,
assigns the Char part of the result to b, and so on. A step by step
description of a process is taking place, and <- (just like >>=) is
reminding of the direction in which it is headed.
But so what? a is not equal to b in our example, period. Even if
we don't know the exact values of two returned IO Char of each
getChar, if parts of them do not match, they *must* have different
values, and therefore, getChar cannot possibly be a function!
When in fact, something else is taking place: the two values are
different, no doubt, but the key of this part of The Mystery of Monads
is not in the values, but in the types of the getChar function. Parametric
type IO Char means: it is Char in the current environment of whatever
affects pure functions that IO provides to the program. Thus, a and b
are different, but so are the return types of the two getChar
functions, both of which, in its own part of the monadic process, is a
ginger-peachy P.O.E. that performs, so to speak, equivalent calculation
up to that change in the position of the next character in the file,
not the identical one. In other words, getChar would always give the
same result within the IO monadic environment in the same state.
Ingenious or what?
But wait, enough of this sophistry! Here is the fresh example:
main = do{
...
a <- do { x<-getChar handle; return x; };
b <- do { x<-getChar handle; return x; };
...
}
Now we have two monadic processes within the starting
one, where each getChar may be pure within its own do enclosure,
but a and b get their values *outside* the enclosure (after return
has finished), and, therefore, the two identically written do blocks,
become different, as if each one had created within itself an auxiliary
hidden type so that it can pretend getChar is pure. That's fishy.
Well: once in monad, always in monad---there is no way out of
it once a monad has been triggered. Return type of return in the
case of IO monad is, well, IO a, which compiler statically sorts out
in this case to be IO Char, and when everything turns out to be
matching, perhaps to Char, just like in C.
Not only that. Remember associativity? It allows us to remove
inner do's in the nested do {...}, and the other two laws make
return x; disappear (behave like identity), and we can transform
the last snippet into the equivalent one we had at the beginning.
> First, they are often represented in a way that I feel is
> confusing. For example, consider this misleading
> statement from today's Wikipedia:
>
> The primary uses of monads in functional programming
> are to express input/output (I/O) operations and changes
> in state without using language features that introduce
> side effects.
>
> Conceptually speaking a Monad will let you take a pure
> function F and produce a new "function except with side
> effects" FS which is based on F.
>
> In other words, monads are a language feature which
> allows people to write Haskell programs which use
> side effects -- and this should be trivially obvious since
> I/O is a canonical example of a side effect. Yet, false
> statements such as that which I found in the wikipedia
> pervade writeups on Monads.
>
> Second, current Monad implementations seem to be
> intrinsically wedded to "type systems". And type systems
> impose the illusion and sometimes constraint that function
> domains should be related in the contexts where that does
> not really fit the application.
>
> (I will agree that type systems can sometimes be useful,
> but given they way people usually use them -- and represent
> them -- I feel they invite unnecessary complexities.)
>
>> Once this has been accomplished, however, there is
>> suddenly a powerful way of talking about various types
>> of programs, be they sequential or not.
>
> Simplicity is powerful.
>
> As things currently stand, I feel that Monads are too
> complex for a language like J.
>
> --
> Raul
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
>
>
--
View this message in context:
http://old.nabble.com/Re%3A--Jprogramming--Monads-and-Categories-in-J-tp27213117s24193p27266459.html
Sent from the J Chat mailing list archive at Nabble.com.
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm