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

Reply via email to