Prereleasing hxmonads

108 views
Skip to first unread message

Simon Krajewski

unread,
Jan 21, 2012, 4:08:40 PM1/21/12
to haxe...@googlegroups.com
Hello,

I've been working on a monadic macro processor the last few days and
would like to release the first version. Check it out at
http://code.google.com/p/hxmonads/

Most I have to say about it is posted on the intro and example pages, so
I won't repeat everyhing here. Try it if you have use for stuff like
this and check the asynchronous possibilities in particular. Also,
please report any bugs you encounter! I extensively tested it with
arrays on the platforms supported by munit, but there might still be
issues on other platforms and with other monadic types.

Regards
Simon

Luca

unread,
Jan 21, 2012, 5:31:26 PM1/21/12
to haxe...@googlegroups.com
monax or hxmonads, which is better? There's only one way to find out.

FIIIGHHTTT! 

excuse me, please. Just been watching some Harry Hill

Stephane Le Dorze

unread,
Jan 22, 2012, 8:59:29 AM1/22/12
to haxe...@googlegroups.com
Yeaahhh Fight!!
But then I wish Nicolas would bring it at the right level (for haXe 3 ??) :p

Stephane

Philippe Elsass

unread,
Jan 22, 2012, 9:17:49 AM1/22/12
to haxe...@googlegroups.com

I must say the wiki examples are really helpful. I'm really curious about the handling of the asynchronous methods.

Simon Krajewski

unread,
Jan 22, 2012, 9:35:50 AM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 15:17, schrieb Philippe Elsass:
>
> I must say the wiki examples are really helpful. I'm really curious
> about the handling of the asynchronous methods.
>

I just committed the FlashIO class I used for the Flash Console example,
check it our here:
http://code.google.com/p/hxmonads/source/browse/trunk/misc/FlashIO.hx

You should be able to run the wiki example with it. getLine()'s job is
it to return a Future (which is currently initialized with null, I will
change that to Option later) and connect that Future's complete() method
to whatever event completes it. Here it's just pushed onto an Array and
each enter keyboard event pops the latest future and completes it with
the input.

It should be easy to write connector methods like getLine in this
example. Candidates are functions like queryDatabase(), loadPage(),
delayMe() and any other async interface you may encounter.

Regards
Simon

blackdog

unread,
Jan 22, 2012, 1:44:17 PM1/22/12
to haxe...@googlegroups.com

What do you mean? Integrate into the compiler proper? If so, that was my
first thought. I like how the hxmonad future works, but I'd prefer to
have a standard lib Future, being used by a standard monad impl. Anyway
great to see all this effort, and the benefits macros bring to the table.

R


--
Simplicity is the ultimate sophistication. ~ Leonardo da Vinci

Simon Krajewski

unread,
Jan 22, 2012, 2:04:17 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 19:44, schrieb blackdog:
> What do you mean? Integrate into the compiler proper? If so, that was my
> first thought. I like how the hxmonad future works, but I'd prefer to
> have a standard lib Future, being used by a standard monad impl. Anyway
> great to see all this effort, and the benefits macros bring to the table.

I want standard Future (and Option) too. My Future implementation is
little more than a proof of concept and could easily be replaced by a
proper implementation. I considered using the Stax Future, but I didn't
want to add a dependency just for that.

Integrating monads into the compiler would be great, but I don't see
that happening anytime soon. I actually wanted to give it a try, but I
wouldn't even get as far as setting up a proper incremental OCaml
compilation for haxe.

Regards
Simon

Stephane Le Dorze

unread,
Jan 22, 2012, 2:37:02 PM1/22/12
to haxe...@googlegroups.com
Just to let you know that Laurence is working ATM on a Stax refactor to shrink the cost associated by using parts of Stax, so the principal cons (the generated code size) will decrease, thanks Laurence! :)

About your Monad implementation; I think you have to think about extensibility; from what I've seen, some functionnality is closed in the API.
Knowing this was a prerelease, I can understand it could be a temporary design choice, just warning here, for the best ;)

My 2 cents! :)
Stephane

Laurence Taylor

unread,
Jan 22, 2012, 3:04:14 PM1/22/12
to haxe...@googlegroups.com
You should consider using git. Satisfying dependencies on project import is as simple as:

git submodule init
git submodule update

There is a version here which has most of the principle improvements I was looking for, and some explanation. Feedback would be appreciated, I think a wee bit more discussion is to be had before pushing to master.

regards,
Laurence

Simon Krajewski

unread,
Jan 22, 2012, 3:11:40 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 20:37, schrieb Stephane Le Dorze:
> About your Monad implementation; I think you have to think about
> extensibility; from what I've seen, some functionnality is closed in
> the API.
> Knowing this was a prerelease, I can understand it could be a
> temporary design choice, just warning here, for the best ;)

What do you mean by extensibility? Making it work for new types is as
easy as writing the monadic class and either put it into hxm.monads
folder or use Monad.addMonadPath("mymonads") to let the processor know
where to look. Then, if the name relationship to the base class is not
simply BaseName + "Monad", you can use Monad.addAlias("FastList",
"Iterable").

There's even a hxm.core.Resolver.defineFunc method to define own monadic
functions, which will be inlined as expressions into your code. That's
how the guard function is currently implemented, although I don't really
like this approach anymore because it's impossible to get code completion.

Simon

Simon Krajewski

unread,
Jan 22, 2012, 3:23:24 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 21:04, schrieb Laurence Taylor:
You should consider using git. Satisfying dependencies on project import is as simple as:

git submodule init
git submodule update

There is a version here which has most of the principle improvements I was looking for, and some explanation. Feedback would be appreciated, I think a wee bit more discussion is to be had before pushing to master.

regards,
Laurence

Your Prelude.hx has some <<<<<<< HEAD
>>>>>>> Moved Tuple4 and Tuple5 to Tuples.hx

stuff and I get errors like
../../com.github/stax/src/main/haxe/Prelude.hx:127: lines 127-129 : Class not found : JValue
../../com.github/stax/src/main/haxe/Prelude.hx:180: lines 180-234 : Duplicate class field declaration : entuple

I will try to make my FutureMonad work with Stax Future though.

Simon

Laurence Taylor

unread,
Jan 22, 2012, 3:41:54 PM1/22/12
to haxe...@googlegroups.com
My fault, some merge gunk. one sec


--

Laurence Taylor

unread,
Jan 22, 2012, 3:46:07 PM1/22/12
to haxe...@googlegroups.com
ok, should be fine now.

--

Simon Krajewski

unread,
Jan 22, 2012, 4:09:28 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 21:46, schrieb Laurence Taylor:
> ok, should be fine now.
>

Ah thanks, it works just fine after renaming complete to deliver and
addListener to deliverTo. I consider basing my monadic classes on the
Stax classes. It makes sense for Option and Future, but what other
classes could use a monadic behaviour?

Simon

Marc Weber

unread,
Jan 22, 2012, 4:28:36 PM1/22/12
to haxelang
Excerpts from Laurence Taylor's message of Sun Jan 22 21:04:14 +0100 2012:

> git submodule init
> git submodule update

Do you really propagate this kind of "poor mans dependency management"?

Exapmle:

lib-a has git submodule tink_macros (hash e784e )
lib-b has git submodule tink_macros (hash 45434 )

your app depends on both..

How could it look like instead?


lib-a has a file "{depneds-on: [ "tink_macros > 2.0" ]}"
lib-b has a file "{depneds-on: [ "tink_macros > 1.0" ]}"

haxe automatically understands that either version will suffice and pick
the latest.

This would scale much better IMHO.
Does something like this already exist?

> > [ ..] but I wouldn't


> > even get as far as setting up a proper incremental OCaml compilation for
> > haxe.

Can you explain little more?

Marc Weber

Simon Krajewski

unread,
Jan 22, 2012, 5:13:55 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 22:09, schrieb Simon Krajewski:
> Am 22.01.2012 21:46, schrieb Laurence Taylor:
>> ok, should be fine now.
>>

I just checked your version of Stax more thoroughly. While certainly
much better than what I remember it to be, there are still scents of
dependency hell. For example, Future uses OptionOps, which happens to
throw a Stax.error in one place, which causes the evil empire of Stax.hx
to be included, which pretty much includes everything. However, the
binary size penalty is not that bad, around 40kb for a .swf. It just
feels rather unclean having to include all that stuff when all you want
is a simple Future/Option implementation.

I think the basic classes (Option, Future, Either... I might be missing
some) need even more separation from some of their fancy methods that
require inclusion of other modules. I would actually release them and
their Ops classes as a separate core library that might have prospects
of making it to the real std. This should be within reason if we focus
on keeping it small and simple. What do you think?

Simon

Laurence Taylor

unread,
Jan 22, 2012, 5:29:16 PM1/22/12
to haxe...@googlegroups.com
There is more to be done, definitely. I came at it from the angle of Typedefs and Lambdas, no doubt you'll want different optimisations. Either unpick it yourself and issue a pull request or make out a ticket. 

Marc's right in that everyone is on slightly different tracks and the mechanisms aren't straight forward.

For example, you can commit to a git repository from an unrelated code base, but if you then want to use that code base and alias out your packages, is there a way of doing that?

I don't know, but something along those lines would allow everyone to add things and still have a unified repository without the submodule stuff.

regards,
Laurence




Simon

Simon Krajewski

unread,
Jan 22, 2012, 5:39:12 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 22:28, schrieb Marc Weber:
> Can you explain little more?

Using ocamlbuild, it would _always_ recompile the whole project, even if
I changed one of the gen-classes. I couldn't figure out what ocamldep's
problem was and eventually just gave up because no one else on the
internet seemed to have that problem. Or explaining in German puns: I
guess I was too much of an Ocamldepp to use ocamldep.

Simon

Simon Krajewski

unread,
Jan 22, 2012, 5:56:24 PM1/22/12
to haxe...@googlegroups.com
Am 22.01.2012 23:29, schrieb Laurence Taylor:
> I came at it from the angle of Typedefs and Lambdas, no doubt you'll
> want different optimisations.

Unfortunately, that's the best argument against a std inclusion and the
reason we have to find a lowest common denominator, which might not be
much more than the pure data definitions and very few extension methods.
It's easy to make an argument for OptionOps.get() and
OptionOps.toOption(), but OptionOps.zipWith() and OptionOps.getOrElse()
are not std material, as I'm sure even the hardcore Lambda crowd will
agree on.

We really need a std committee for this kind of stuff.

Simon

Marc Weber

unread,
Jan 22, 2012, 6:00:12 PM1/22/12
to haxelang
Why do you think ocamldep is the right tool?
N.C used ocamake to create the makefile.
And that exactly is what my patch was about which he rejected.
It documented how to recreate the makefile.

See here:
http://lists.motion-twin.com/pipermail/haxe/2010-July/036911.html
and http://lists.motion-twin.com/pipermail/haxe/2010-August/037532.html

I have to admit that bin/haxe occasionally segfaults when using the
makefile. Because I didn't do any additional hacking (except the short
lamdas patches) I didn't investigate..

I would like to fix all those 'documentation issues' - but I'm blocked
:(

There have been no replies to "in source documentation" either.

About the same issue I asked Franco. He told me he just wrote his own
script recompiling the backend and link that.

In anyway the compilation of haxe is not friendly to devs.

Yes - I do "scream" - but only because it hurts seeing improvements
rejected - and then seeing other devs spending time on it again.

Most up to date version can be found here and should apply to current
HaXe version: http://mawercer.de/~marc/install-ml.patch

Marc Weber

Stephane Le Dorze

unread,
Jan 22, 2012, 6:14:30 PM1/22/12
to haxe...@googlegroups.com
I'm in the hardcore Lambda crowd.

zip, zipWith, zipWithIndex, getOrElse, etc..

Actually *ARE* the kind of stuff that I would love to see in an Std (and that I love it is in Scala / Haskell and the like).
As they are the most commonly used combinators - otherwise your Option is just a container and you'll soon or later implement this stuff in your code (often at several places).

I think the question is not the right one for Extensions:
Could we improve the mecanism so that they would incurs no code generation if not by a project?
(I would really love that actually!)

Stephane

Simon Krajewski

unread,
Jan 22, 2012, 6:40:14 PM1/22/12
to haxe...@googlegroups.com
Am 23.01.2012 00:14, schrieb Stephane Le Dorze:
> I'm in the hardcore Lambda crowd.
>
> zip, zipWith, zipWithIndex, getOrElse, etc..
>
> Actually *ARE* the kind of stuff that I would love to see in an Std
> (and that I love it is in Scala / Haskell and the like).
> As they are the most commonly used combinators - otherwise your Option
> is just a container

Yes, and that is the basic use of an option: you separate having some
value from having no value. That's what normal people do with Option,
they conditionally return it from some function and switch on it in
order to branch, and that's in my opinion what the std should cater to.

I'd even accept no functionality at all, which might not make much sense
in the context of Option. Consider Future though, I just made an
implementation compatible by renaming some method calls. It would be so
much better if the std had a typedef defining what a Future has to have
_in a minimal implementation_. You can then still use
UltraLambdaFutureLib and it will be compatible as long as it upholds to
the laws set be the std.

So yes, I think the first step is to define a set of interfaces (which
would be typedefs) in the std for commonly used data structures. Only
then can the second step be taken, which is providing implementations
for the commonly used operations on these commonly used data structures.

Also, we need some naming conventions. OptionExtension, OptionExt,
OptionEx, OptionOps, OptionFuncs... it's pointless arguing here because
none is better than the other. So Nicolas should just state his
favorite, we hide that information somewhere in the docs and point
anyone not employing it there.

Simon

Marc Weber

unread,
Jan 24, 2012, 6:50:26 PM1/24/12
to haxelang
Excerpts from Stephane Le Dorze's message of Sun Jan 22 14:59:29 +0100 2012:
> Yeaahhh Fight!!
I'd prefer collaboration.


hxmonads:
+ completion
+ determines type (by using Context.type and some "unification" magic)
Thus you can get rid of the MonadType.do({ ..) and Monad.do is enough
+ definitely supports "nested monads" by simple syntax.
- implements the yield operator the HaXe way - thus if you would
implement State or parser like structures it may not be as optimezd
as teh map like interafce for monax?

Stephane, Simon: Am I correct about what I say that those are the main
differences ? Did I misse anything else?

If thats correct how do you feel about merging?

Marc Weber

Simon Krajewski

unread,
Jan 24, 2012, 9:06:13 PM1/24/12
to haxe...@googlegroups.com
Am 25.01.2012 00:50, schrieb Marc Weber:
> + definitely supports "nested monads" by simple syntax.
> - implements the yield operator the HaXe way - thus if you would
> implement State or parser like structures it may not be as optimezd
> as teh map like interafce for monax?

The yield operator has been a big issue for me because returning [a] is
totally impractical from a performance point of view. I'm not sure how
to optimize this and any input is very welcome! Are there any examples
of Monax working on iterables that clearly show the difference?

Stephane really seems to be into optimizing this kind of stuff, which is
definitely hxmonad's weakness at the moment. So I see plenty of room for
collaboration too.

Simon

Stephane Le Dorze

unread,
Jan 25, 2012, 5:24:50 AM1/25/12
to haxe...@googlegroups.com
In fact,

 - Monax already support completion.

 - I also have an automatic type detection locally working for some time (need to push it) which prevent specifying the monad Type.
   but I didn't pushed it because it did not played well with the NodeJs specific callback syntax (in this case NodeJs Monad need to be specified) but it will changed based on recent haxe 3.0 specs from Nicolas (yuhuuu!!)

 - About nested Monads; I really prefer to remain explicit; the reason is that it is less expressive simply because one cannot use a normal block code (!).

I have not done yet some type specific optimizations; nor have I done Iterables specific handling (which I find a very neat Idea!).
If such things would be brought to Monax, then it should be done without touching Monax core code.

Monax goal is to bring optimizable Monads Instances, not pre optimized Monads Instances.

My 2 cents,
Stephane :)

Simon Krajewski

unread,
Jan 25, 2012, 5:39:01 AM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 11:24, schrieb Stephane Le Dorze:
> - About nested Monads; I really prefer to remain explicit; the reason
> is that it is less expressive simply because one cannot use a normal
> block code (!).

There's a difference though: a nested monad is bound to an identifier:

y <= [1];
x <= { ... } // Nested

y <= [1];
{ ... } // Normal code block


Simon

Stephane Le Dorze

unread,
Jan 25, 2012, 6:09:09 AM1/25/12
to haxe...@googlegroups.com
Below the reason why the expressivity is kept in Monax:
In Monax : ..
        x <= y
        t <= ret(Monad.dO({
          v <= Some(12);
          ret(v);
        }));
..

^  you shortcut that to something like this in hxMonads:
        x <= y
        t <= {
          v <= Some(12);
          ret(v);
        };

but then you loose the ability to do that:

x <=  { // normal code returning a Monad
  var monadicValue = calcultateAMonadicValue();
  monadicValue;
}

that's all - below some more use cases (not very relevant to the formentionned point).

(((

x <=  Monad.dO({ // normal code returning a value to be lift in the same Monad (so no ret to lift into a new one)
  value <- [5, 6];
  ret(value);
})

or

x <=  Monad.dO({
  value <- [[5, 3], [6, 7]]; // Array of Array in the Array monad
  value; // we kind of flatten it by not returning via ret.
})


Note that this is not acceptable:

x <= [5,6];
{
  trace("toto");
}

but this is Ok:

x <= [5,6];
  trace("debug output..");
  [7,8]; // ok; code here returns a Monadic value
}

or

x <= [5,6];
[12, 13];

or

x <= [5,6];
ret(12);

))) 

I don't want to spend too much time in this topic (I spend already so much on monads in previous threads).
I hope it brings the light.

That's said; maybe a short cut could be brought to lighten the syntax of this:

        x <= y
        t <= ret(Monad.dO({
          v <= Some(12);
          ret(v);
        }));

To something like :

        x <= y
        t <= retDo({
          v <= Some(12);
          ret(v);
        });

But it surely is NOT the same case as normal code and should be explicitely separated.

:)
Stephane

Simon Krajewski

unread,
Jan 25, 2012, 6:22:04 AM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 12:09, schrieb Stephane Le Dorze:
> but then you loose the ability to do that:
>
> x <= { // normal code returning a Monad
> var monadicValue = calcultateAMonadicValue();
> monadicValue;
> }

Ah, I see your point. In that case I will change it to the following
behaviour:

y <= [1];
x <= { ... } // block is expected to return a monadic value (Array)
z <= return { ... } // Nested, can return anything. Value will be lifted.

Stephane Le Dorze

unread,
Jan 25, 2012, 6:41:36 AM1/25/12
to haxe...@googlegroups.com
Cool! (was afraid to go into a lengthy thread)

Stephane Le Dorze

unread,
Jan 25, 2012, 7:18:15 AM1/25/12
to haxe...@googlegroups.com
New Monax version with no more need to specify the Monad type.
Instances now requiers to add a simple method to make that available.

Example:

      Monad.dO({
        v <= Some([10, 20]);        
        w <= ret(Monad.dO({
          x <= v;
          ret(x + 2);
        }));
        ret(w);
      });

equivalent to

Some([10, 20]).map(function (v) return v.map(function (x) return x+2))

(but more optimized - modulo the JS target suffering of expression encoding overhead)


Stephane

P.S.: Like discussed with Simon there could be definitively some syntactic enhancements.

Stephane Le Dorze

unread,
Jan 25, 2012, 7:18:47 AM1/25/12
to haxe...@googlegroups.com
So please also accept;

x <= return 1;

Simon Krajewski

unread,
Jan 25, 2012, 7:24:34 AM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 13:18, schrieb Stephane Le Dorze:
> Monad.dO({
> v <= Some([10, 20]);
> w <= ret(Monad.dO({
> x <= v;
> ret(x + 2);
> }));
> ret(w);
> });

That doesn't compile for me:
com.mindrocks.monads.Option<Array<Int>> has no field monad

Simon

Stephane Le Dorze

unread,
Jan 25, 2012, 7:52:41 AM1/25/12
to haxe...@googlegroups.com
Be use to use the lastest code.

In which you may find this (it needs to be brought in scope with using):


@:native("Option_Monad") class OptionM {
  
  @:macro public static function dO(body : Expr) return
    Monad._dO("OptionM", body, Context)
    
  public static function monad<T>(o : Option<T>)           <<<<<<<<<<<<<<<<<<< Mandatory/
    return OptionM
  

Stephane Le Dorze

unread,
Jan 25, 2012, 7:54:57 AM1/25/12
to haxe...@googlegroups.com
Again a new version (Monx 1.3) has been released (enough for today).

It implements Simon's idea (while still being able to define optimizations to your code): 

 Monad.dO({
        v <= Some([10, 20]);        
        w <= return {
          x <= v;
          return x + 2;
        };
        return w;
      });

Have fun!

Stephane

Simon Krajewski

unread,
Jan 25, 2012, 8:02:27 AM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 13:52, schrieb Stephane Le Dorze:
> In which you may find this (it needs to be brought in scope with using):

Well that's subtle... It compiles now, but I get an exception:
VerifyError: Error #1014: Class com.mindrocks.monads::MonadOp could
not be found.

Removing the #if macro ... #end part within that enum makes it work.

Simon

Stephane Le Dorze

unread,
Jan 25, 2012, 8:06:36 AM1/25/12
to haxe...@googlegroups.com
That's the way Monad instances are used; it provides an extensible mecanism and one is not locked with only one solution for a datatype.

Mmmm.. not sure about the macro stuff and the error (sounds very strange to me - are you using it from another macro???)
Please, post an issue to Monax github (I'll look later, no much time right now). :)

Have an awesome day!
Stephane

Marc Weber

unread,
Jan 25, 2012, 8:08:51 AM1/25/12
to haxelang
Excerpts from Simon Krajewski's message of Wed Jan 25 12:22:04 +0100 2012:


> y <= [1];
> x <= { ... } // block is expected to return a monadic value (Array)

What about introducing "do" ?

Monad.do{
x <= do({
...
})
}

which is then replaced by Monad.do?

I'm not sure its good to create many additional "HaXe specific" rules
you have to learn.

your proposal return {} behaving like {} would .. is making things
counter intuitive.

Whatever you do - I'll be happy.

And having such "do" => "Monad.do" rewriting could be used for more
purposes. Eg if you have a parser and if you want your own "extensions"
you could tell a "monad builder" to rewrite spaces by MyParser.spaces
etc.

Marc Weber

Simon Krajewski

unread,
Jan 25, 2012, 8:19:05 AM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 14:08, schrieb Marc Weber:
> What about introducing "do" ?
>
> Monad.do{
> x<= do({
> ...
> })
> }
>
> which is then replaced by Monad.do?

I had that idea too at some point, but the syntax is rejected by the
compiler with do being a keyword that expects a while.

> your proposal return {} behaving like {} would .. is making things
> counter intuitive.

Yes, I already agreed to drop that behaviour. I also might have to drop
the usage of return because with normal code blocks, there are pretty
much two kinds of return: the normal haxe return and the monadic yield.
I'm not sure yet how to go on about this.

Simon

Stephane Le Dorze

unread,
Jan 25, 2012, 8:24:32 AM1/25/12
to haxe...@googlegroups.com
If you look at Monax, you see that you CAN actually add stuff such as spaces and the like..
Look at thos gets and puts:


       StateM .dO({
        passedState <= gets();
        puts("2");
        state <= gets(); 
        return 'passed state: '+passedState+' new state: '+state;
      }).runState("1");


they've just been brought via the Instance Monad like this:


class StateM {

  public static function monad<S,T>(o : State<S,T>)
    return StateM

  @:macro public static function dO(body : Expr) return
    Monad._dO("StateM", body, Context, Monad.noOpt)

  static public function ret <S,T>(i:T):State<S,T> {
    return function(s:S){ return {state:s, value:i}; };
  }

  static public function flatMap <S,T,SU, U>(a:State<S,T>, f: T -> State<S,U>):State<S,U>{
    return function(state){
      var s = a(state);
      return f(s.value)(s.state);
    }
  }

  static public function gets <S>():State<S,S>{
    return function(s:S){
        return {
          state: s,
          value: s
        };
    };
  }

  static public function puts <S,T>(s:S):State<S,T>{
    return function(_:S){
        return {
          state: s,
          value: null
        };
    };
  }

  static public inline function runState <S,T>(f:State<S,T>, s:S):T{
    return f(s).value;
  }
  
}

Stephane Le Dorze

unread,
Jan 25, 2012, 8:27:49 AM1/25/12
to haxe...@googlegroups.com
Yes, that's what I told you.

However it can be dodged like this:

return {{
  2;
}};

So I have considered it now.. and release the new version.
(people change, right??? :) )

Marc Weber

unread,
Jan 25, 2012, 8:28:10 AM1/25/12
to haxelang
If do doesn't work use do_ dO or such. Its easiest for everybody if we
keep monadic and HaXe syntax separated.
Ruby calls this "POLS" (principle of least suprise).

If we want shorter syntax we should rewrite the parser so that we can
have ruby or scala like syntax for objects and methods, ...

We could also make HaXe allow "do" in that context.

Marc Weber

Simon Krajewski

unread,
Jan 25, 2012, 8:36:26 AM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 14:06, schrieb Stephane Le Dorze:
> Mmmm.. not sure about the macro stuff and the error

It might be Flash target related. Seems like the empty enum is
completely omitted from the output swf. Might be default behaviour for
swf output, I'm not sure. You can also avoid the problem by putting your
#if enum around the whole macro-only functions, not into their
definitions like you do with _dO.

Simon

Stephane Le Dorze

unread,
Jan 25, 2012, 8:37:01 AM1/25/12
to haxe...@googlegroups.com
or maybe we could use 

  w <= return {
   // normal code
  }

and 

        w <= return <{ // '<' to indicate we're using a nested Monad...
          x <= v;
          return x + 2;
        };

What do you think???

Stephane

Stephane Le Dorze

unread,
Jan 25, 2012, 8:39:33 AM1/25/12
to haxe...@googlegroups.com
Sorry, it does not pass the lexer.
Anyway got to really stop now.

bybye

Simon Krajewski

unread,
Jan 25, 2012, 8:43:41 AM1/25/12
to haxe...@googlegroups.com

I don't get why this requires a different syntax. You should be able to
infer the type of block by checking its content: if there's a <= bind,
it's automatically a nested monad, else it's a normal block. This should
even be sufficient to determine the type of return to use.

What am I missing?

Simon

Marc Weber

unread,
Jan 25, 2012, 8:48:21 AM1/25/12
to haxelang
Excerpts from Stephane Le Dorze's message of Wed Jan 25 14:39:33 +0100 2012:

> > w <= return <{ // '<' to indicate we're using a nested Monad...
> > x <= v;
> > return x + 2;
> > };

or {{ as you told if that works. We sohuld not overload {} (HaXe blocks) with monadic
behaviour.

Having one "key word" which means "attention! this is a monad" such as
"dO" will be more helpful than having to remember <{ and Monad.do.
I'd vote for
Monad.dO({
x <= return dO {
}
})

Then all people knowing monads understand what's happening without
looking up documentation.

Marc Weber

Stephane Le Dorze

unread,
Jan 25, 2012, 8:52:15 AM1/25/12
to haxe...@googlegroups.com
Sorry, no.

An array monadic block (for instance) can start with 
{
  [x, y, z];
}

this is will iterate over the three values without binding them.

[x,y,z].flatMap(function (_) <restOfMonad>)

This is the normal behavior of a Monad.

Marc Weber

unread,
Jan 25, 2012, 8:55:22 AM1/25/12
to haxelang
Excerpts from Simon Krajewski's message of Wed Jan 25 14:43:41 +0100 2012:
> What am I missing?
That you can ignore the "return" value.
do {
foo();
bar();
return "result"
}

instead of

do {
a <= foo()
b <= bar()
return a + b;
}

Marc Weber

Simon Krajewski

unread,
Jan 25, 2012, 9:05:18 AM1/25/12
to haxe...@googlegroups.com

I see, that makes sense. So we really need a dinstinguishable syntax for
both cases I guess. I'm a little afraid of this making the whole thing
hard to grasp for "normal" users, as you can see I'm already having
trouble recognizing the difference.

I might stick with the infer-it-approach, but think of a syntactic way
to mark blocks where inference fails as "monadic".

Simon

Marc Weber

unread,
Jan 25, 2012, 9:17:11 AM1/25/12
to haxelang
Excerpts from Simon Krajewski's message of Wed Jan 25 15:05:18 +0100 2012:

> hard to grasp for "normal" users, as you can see I'm already having
> trouble recognizing the difference.
That's why I vote for one syntax and keyword "dO" everybody can lookup easily.

You need a use case?
do {
expect_text "["; // future monad : send "[" to server, parser monad: consume "["
expect_many (one_of "012356");
expect_text "]";
}

In that case the monadic version differs from a non monadic because it
processes input.

Without monad sugar, what would happen?
future case: all requests would be sent, but order would not be
guaranteed (because waiting for replies would not happen)


monad case: nothing because expect_text would return a function
processing parser state.

There is a difference :)

Marc Weber

Simon Krajewski

unread,
Jan 25, 2012, 12:01:53 PM1/25/12
to haxe...@googlegroups.com
Am 25.01.2012 15:17, schrieb Marc Weber:
> There is a difference :)
>
I don't doubt that (anymore). The question is if this difference has to
be made explicitely by the user, or could partially be inferred by the
typer. It's kind of like haxe type inference, only on block level and
with monadic/normal instead of types.

Simon

Reply all
Reply to author
Forward
0 new messages