![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 14/03/2013 08:24 PM, Warp wrote:
> Orchid Win7 v1<voi### [at] dev null> wrote:
>> Again, the problem is that we need to write a method which examines TWO
>> objects which must be of THE SAME class.
>
> I don't understand at all what that even means.
>
> Start by explaining (briefly) what "examines" means in this context.
Consider another example: Let's say you want to do something like
public abstract class Tree
{
...
public abstract Tree Union(Tree other);
...
}
So we can now write SplayTree, HeapTree, SearchTree, etc as subclasses
of Tree. But the thing is... you can only Union() two trees together if
they are THE SAME TYPE of tree. So you can take the union of two
SplayTrees, or the union of two HeapTrees, but NOT the union of a
SplayTree and a HeapTree.
But the type signature above does not express this constraint. It says
that you can union *any* two objects so long as they are both Trees -
which is wrong.
That's the basic problem with writing a monad interface in C# (or Java,
for that matter). You could do a run-time type check and throw an
exception if the types don't match, of course. But I haven't yet figured
out how to enforce the constraint at compile-time.
(Having asked some questions on stack overflow, it appears it might
actually be possible in C# though... I'll give it a go tomorrow.)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Am 14.03.2013 22:20, schrieb Anthony D. Baye:
>
http://stackoverflow.com/questions/2704652/monad-in-plain-english-for-the-oop-programmer-with-no-fp-background/2704795#
> 2704795
I guess this one about wraps it up nicely (emphasis added):
--------------------------------
Monads are typically used to solve problems like:
* I need to make new capabilities for this type and still combine
old functions on this type to use the new capabilities.
* I need to capture a bunch of operations on types and represent
those operations as composable objects, building up larger and larger
compositions until I have just the right series of operations
represented, and then I need to start getting results out of the thing
* I NEED TO REPRESENT SIDE-EFFECTING OPERATIONS CLEANLY IN A
LANGUAGE THAT HATES SIDE EFFECTS
(Note that these are basically three ways of saying the same thing.)
--------------------------------
With the whole OO concept being /centered/ around operations with
side-effects (namely modifying the object's internal state), this boils
down to saying that monads are NOT NEEDED in an OO language. (Or, in
other words, that monads do something that is already inherent in the OO
concept anyway.)
I think it might also be fair to say that monads are a way to express
certain OO ideas in functional languages.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Am 14.03.2013 23:39, schrieb Orchid Win7 v1:
> On 14/03/2013 08:24 PM, Warp wrote:
>> Orchid Win7 v1<voi### [at] dev null> wrote:
>>> Again, the problem is that we need to write a method which examines TWO
>>> objects which must be of THE SAME class.
>>
>> I don't understand at all what that even means.
>>
>> Start by explaining (briefly) what "examines" means in this context.
>
> Consider another example: Let's say you want to do something like
>
> public abstract class Tree
> {
> ...
> public abstract Tree Union(Tree other);
> ...
> }
>
> So we can now write SplayTree, HeapTree, SearchTree, etc as subclasses
> of Tree. But the thing is... you can only Union() two trees together if
> they are THE SAME TYPE of tree. So you can take the union of two
> SplayTrees, or the union of two HeapTrees, but NOT the union of a
> SplayTree and a HeapTree.
Well, this can easily be solved by making Union non-abstract and having
it call more primitive abstract functions; e.g (using pseudocode as I
currently don't have C# syntax memorized):
public abstract class Tree
{
public abstract Tree copy();
public abstract Iterator<Leaf> leaves();
public abstract void addLeaf(Leaf l);
public final Tree Union(Tree other)
{
Tree newTree = this.copy();
foreach(Leaf i in other.leaves())
newTree.addLeaf(i);
}
}
There. Problem solved.
Note that in OO languages it is customary to use non-lazy evaluation
(because objects may change, so lazy evaluation is prone for effects
that OO programmers don't expect), so there's nothing conceptually wrong
with copying the leaves rather than creating some "meta-tree" that
provides tree-like operations on a compound of two tree objects.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> So we can now write SplayTree, HeapTree, SearchTree, etc as subclasses
>> of Tree. But the thing is... you can only Union() two trees together if
>> they are THE SAME TYPE of tree. So you can take the union of two
>> SplayTrees, or the union of two HeapTrees, but NOT the union of a
>> SplayTree and a HeapTree.
>
> Well, this can easily be solved by making Union non-abstract and having
> it call more primitive abstract functions; e.g (using pseudocode as I
> currently don't have C# syntax memorized):
>
> public abstract class Tree
> {
>
> public abstract Tree copy();
> public abstract Iterator<Leaf> leaves();
> public abstract void addLeaf(Leaf l);
>
> public final Tree Union(Tree other)
> {
> Tree newTree = this.copy();
> foreach(Leaf i in other.leaves())
> newTree.addLeaf(i);
> }
> }
>
> There. Problem solved.
Note that taking the union of (say) two heap trees is a O(log N)
operation, whereas what you just wrote is O(N).
You can, of course, NOT write an abstract interface, and just write a
concrete Union() method [with a different type signature] for each
concrete Tree class. That works just fine. [But now you can't write code
that works over any Tree type and expect to do unions.]
But anyway. The example illustrates the problem. Taking the Bind() of
two different monads isn't even *defined*. There's no sensible answer.
So until I can find a solution to that...
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 13/03/2013 09:30 PM, Orchid Win7 v1 wrote:
> OK, so just for giggles, I tried to implement monads in C#.
>
> The short version: It appears that I can create a class with forms a
> monad, however it appears to be impossible to define the concept of
> "being a monad" such that you can write code which polymorphically works
> for any monad.
It appears I missed the elephant in the room. Apparently C# already
*has* several classes which form monads, and even a special monad
comprehension syntax for dealing with them.
Consider the following Haskell parser:
identifier :: Parser String
identifier = do
leading <- many space
first <- letter
rest <- many alphanum
trailing <- many space
return ([first] ++ rest)
Now consider the following C# LINQ query:
Parser<string> identifier =
from leading in Parse.Whitespace.Many()
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
from trailing in Parse.Whitespace.Many()
select new string(first.Concat(rest).ToArray());
Notice any similarity?
C# *already* has monads. The designers of LINQ even explicitly mention
Haskell and monads as influencing their design.
So much for "only functional programmers understand monads and only
functional programmers need monads"... :-P Monads are in fact one of the
star features of a highly commercially successful programming platform.
(Although I'll admit LINQ is definitely tailored more towards
*container* monads rather than being a general monad framework.)
I notice in passing that there is no "interface" which describes all the
methods you have to implement to make a monad. (Or to make something
that LINQ will work on.) Rather, it uses a strange system of "extension
methods" - a very un-OO concept, if you look it up. But anyway, LINQ
queries let you easily write monadic expressions without drowning in a
sea of lambda functions.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp <war### [at] tag povray org> wrote:
> It almost looks like it's describing inheritance. What is
> "First, what is an "amplifier of types"? By that I mean some system
> which lets you take a type and turn it into a more special type. For
> example, in C# consider Nullable<T>. This is an amplifier of types. It
> lets you take a type, say int, and add a new capability to that type,
> namely, that now it can be null when it couldn't before."
> other than inheritance? The next paragraphs also seem to be talking
> about inheritance.
> Of course the text then proceeds into blabbering about something that's
> hard to understand and seems quite inconsequential. Something about
> binding (which sounds like dynamic binding in inheritance, but apparently
> isn't?)
Still waiting for an answer to this...
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> It almost looks like it's describing inheritance. What is
>
>> "First, what is an "amplifier of types"? By that I mean some system
>> which lets you take a type and turn it into a more special type. For
>> example, in C# consider Nullable<T>. This is an amplifier of types. It
>> lets you take a type, say int, and add a new capability to that type,
>> namely, that now it can be null when it couldn't before."
>
>> other than inheritance? The next paragraphs also seem to be talking
>> about inheritance.
>
>> Of course the text then proceeds into blabbering about something that's
>> hard to understand and seems quite inconsequential. Something about
>> binding (which sounds like dynamic binding in inheritance, but apparently
>> isn't?)
>
> Still waiting for an answer to this...
OK, so now I'm back from London, let's take a stab at this...
The originally quoted answer doesn't make a huge amount of sense to me.
I mean, I see where the guy is trying to go, but it's not a great metaphor.
Let's say you have a Customer type. Using this, you can construct a
List<Customer> type, which extends Customer with the ability to have
multiple values. Similarly, Parser<Customer> extends the Customer type
with the ability to read a customer from a string.
Except that, really, that's a rather odd way of looking at things. I
mean, a list of customers isn't really much like a customer at all -
it's a list! And a parser of customers isn't a customer either; it's a
thing that might produce a customer.
The "binding" refers to binding the result of a parser (or whatever) to
a function. In other words, you run the parser, and pass its result
through a function to generate the final result. Really, a monad is
simply a specific way of chaining operations together; nothing more
complicated than that.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Orchid Win7 v1 <voi### [at] dev null> wrote:
> Really, a monad is
> simply a specific way of chaining operations together; nothing more
> complicated than that.
And this is somehow different from just a regular function somehow?
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 01/04/2013 04:12 PM, Warp wrote:
> Orchid Win7 v1<voi### [at] dev null> wrote:
>> Really, a monad is
>> simply a specific way of chaining operations together; nothing more
>> complicated than that.
>
> And this is somehow different from just a regular function somehow?
Well, yeah, that's the crux of the matter.
In a pure language like Haskell, a *function* takes several inputs and
produces an output, and that's all it's allowed to do. If you want to do
something more complicated, you represent it as a monad.
Now, if you're working in an OO language, then you automatically have
access to facilities like I/O, global variables, exception handling and
so on. So you don't need a monad to represent these things.
But now suppose that you want some facility that the OO framework
doesn't natively support. Whether it's non-deterministic computation or
backtracking or partial failure or atomic transactions or whatever... A
monad is one possible way of dealing with these things.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On 28/03/2013 01:04 PM, Orchid Win7 v1 wrote:
> But anyway, LINQ
> queries let you easily write monadic expressions without drowning in a
> sea of lambda functions.
You'll be unsurprised to learn that I am currently about 40% of the way
through implementing Parsec in C#. It turns out to be reasonably easy,
although there are a few gotchas. (E.g., there is no C# function which
both inserts an element into a list *and* returns the list. Which is
annoying, since it seems you can't call void-functions from LINQ...)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |