Skip to content

Instantly share code, notes, and snippets.

@jonifreeman
Created April 17, 2013 07:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonifreeman/5402450 to your computer and use it in GitHub Desktop.
Save jonifreeman/5402450 to your computer and use it in GitHub Desktop.
Do-notation for Fantasy Land
/*
$do {
x <- foo
y <- bar
z <- baz
return x * y * z
}
Desugars into:
foo.chain(function(x) {
return bar.chain(function(y) {
return baz.map(function(z) {
return x * y * z
})
})
})
*/
macro $do {
case { $a:ident <- $ma:expr return $b:expr } => {
$ma.map(function($a) {
return $b;
});
}
case { $a:ident <- $ma:expr $rest ... } => {
$ma.chain(function($a) {
return $do { $rest ... }
});
}
}
$do {
x <- foo
y <- bar
z <- baz
return x*y*z
}
@bradphelan
Copy link

Could you emulate fsharp's computation expressions here and add more keywords? So for example

var lista = $seq {
  $yield 10;
  $yield 20;
}

var listb = $seq {
  $yield 100;
  $yield 200;
}

$do {
  x <- lista
  y <- list b
  return x*y*z;
}

or something like that

@jonifreeman
Copy link
Author

Simple example,

macro seq {
  case { $($yield $x) ... } => {
    [$x (,) ...]
  }
}

var lista = seq {
  $yield 10
  $yield 20
}

// lista = [10, 20]

@bradphelan
Copy link

Couldn't figure out yield but I got you a better do notation that allows standard var bindings between monadic let bindings

macro $do {
  case {$base ...} => {
    (function(){
        $doBody { $base ... }
   }())
  }
}


macro $doBody {

  case {var $a:ident = $ma; $rest ... } => {
      var $a = $ma;
      return $doBody { 
        $rest ... 
      }

  } 

  case { var $a:ident <= $ma:expr; return $b:expr; } => {
    $ma.map(function($a) {
      return $b;
    });
  }
  case { var $a:ident <= $ma:expr; $rest ... } => {
    $ma.chain(function($a) {
       return function(){ $doBody { $rest ... }}()
    });
  }



}


$do { 
  var l0 = [10,20];
  var x <= l0;
  var l1 = [30,40];
  var y <= l1;
  var l2 = [50,60];
  var z <= r; 
  return x * y;
}

generates

(function () {
    var l0$2516 = [
            10,
            20
        ];
    return l0$2516.chain(function (x$2502) {
        return function () {
            var l1$2515 = [
                    30,
                    40
                ];
            return l1$2515.chain(function (y$2507) {
                return function () {
                    var l2$2514 = [
                            50,
                            60
                        ];
                    return r.map(function (z$2512) {
                        return x$2502 * y$2507;
                    });
                }();
            });
        }();
    });
}());

@bradphelan
Copy link

@jonifreeman I mean a lazy yield ( generator )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment