Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Nomads. Javascript Nomads

Name: Anonymous 2008-04-12 21:42

So I was thinking of writing a simple parser in Javascript. Then decided a simple combinator a la Parsec could be good. Had a little fiddle:


/* State monad in Haskell */

// Simple tuple                                                                                                                                               
function tuple(x,y) { return function(f) { return f(x,y); } }
function fst(t) { return t(function(x,y) { return x; }); }
function snd(t) { return t(function(x,y) { return y; }); }

// Monadic operations                                                                                                                                         

// Equvilent to >>=                                                                                                                                           
function bindM(m,k)                                                                                                      
{  
    return function (s) {                                                                                                                       
        tmp = m(s);
        a = fst(tmp); s_ = snd(tmp);
        return k(a)(s_);
    }
}

// Equvilent to >>                                                                                                                                            
function thenM(m,k) {
    return bindM(m,function(_){return k;});
}

function returnM(v) {                                                                                                                         
    return function (s) {                                                                                                                       
        return tuple(v,s);
    }
}

function evalS(m,s) {
    return fst(m(s));
}

function getS(s) {
    return tuple(s,s);
}

function putS(s) {
    return function(_) {
        return tuple(null,s);
    }
}

/* Simple examples: */
alert(
    evalS(
        thenM( putS("Woo!") , bindM( getS , returnM ) )
        ,2));

alert(
    evalS(
        thenM( putS("Woo!") , getS )
        ,2));


But then I decided a parser like that would probably be as slow as shit. I'll still probably implement it, though. Good fun.

Name: Anonymous 2008-04-12 21:47


alert(  
    evalS(
        thenM( bindM( getS , function(n) { return putS(n+1); } )
             , getS
             )
        ,1));

→ 2

OH SHIT IS DAT SOME PURELY FUNCTIONAL MUTATION

Name: Anonymous 2008-04-12 21:48

Equvilent

Name: Anonymous 2008-04-12 21:53

Even after reading the JavaScript for Nomads, I don't really understand Nomads. Someone explain to me Nomads. Please.

Name: Anonymous 2008-04-12 21:53

>>3
Ahaha. I murdered that spelling.

Name: Anonymous 2008-04-12 21:57

>>4
Just a way to express computation and keep track of it, in the same way CPS is useful for controlling the flow of computation.

This state monad implementation just relies on clever use of closures. The tuple bit at the top is just an implementation of cons. That's a clever use of closures imho. Similarly, the state monad implemented above stores data in closures.

Name: Anonymous 2008-04-13 11:13

>>7
Get out of my thread.

Name: Anonymous 2008-04-13 17:10


function parens(s) {
  return choice_( doM( char_('(')
                     , thenM
                     , parens
                     , thenM
                     , char_(')')
                     , thenM
                     , parens
                     )
                , returnM(null)
                )(s);
}


...

print("Parse output:");
try { print(parse(parens, "(()()")); }
catch (e) {
  if (typeof e == 'function') print("Parse failed: " + snd(e));
  else throw e;
}

Parse output:

Parse failed: Unexpected end of input, expected ')'

...

print("Parse output:");
try { print(parse(parens, "(()()")); }
catch (e) {
  if (typeof e == 'function') print("Parse failed: " + snd(e));
  else throw e;
}


Parse output:

null

Name: Anonymous 2008-04-13 17:11

Er,

print("Parse output:");
try { print(parse(parens, "(()())")); }
catch (e) {
  if (typeof e == 'function') print("Parse failed: " + snd(e));
  else throw e;
}


Parse output:

null

Name: Anonymous 2008-04-13 17:13

Works fairly nicely.

A tell thee what, though, it's a right bugger to code for without static typing. Most of the expressions are closures so you can't get proper type errors when you accidentally put a value there instead of an action, or whatever. Monads in Javascript = possible, but could be annoying to write code for.

Name: Anonymous 2008-04-13 17:17

>>9
Oh, PLUS. I wanted to write

var parens = choice_( doM( ... parens .. ) , ...)

I.e. the parser is recursive, but Javascript has the second `parens' as undefined, which I wasn't aware of, but there you go. Doesn't support recursive declarations. So I had to declare it as a function and explicatively pass the state. Kind of annoying.

Anyone know a way to recursively declare variables? (Other than having a self-evaluating thunk)

Name: Grawp 2008-04-13 17:46

RON PAUL /prog/,

I have discovered an amazing site. Turn the volume for your computer ON, and go to http://blocked.on.nimp.org with Internet Explorer. After going there with Internet Explorer, go there with Mozilla Firefox.

Name: Anonymous 2008-04-13 18:11

>>13
/r/ ban

Name: Anonymous 2008-04-13 19:07

*Parsec> :l parsec.hs
[1 of 1] Compiling Parsec           ( parsec.hs, interpreted )
Ok, modules loaded: Parsec.
*Parsec> run parens "()"
()
*Parsec> run parens "(()"
parse error at (line 1, column 4):
unexpected end of input
expecting "(" or ")"

Name: Anonymous 2008-04-13 19:07

js> load("javascript-parser-monad.js")
load("javascript-parser-monad.js")
js> parseParens("()")
parseParens("()")
Parse output:
null
js> parseParens("(()")
parseParens("(()")
Parse output:
Parse failed: Unexpected end of input, expected ')', input:


Ariiiiight.

Name: Anonymous 2008-04-13 19:09

>>16
cool

Name: Anonymous 2008-04-13 21:20

Parsec:

//////////////////////////////
// Parser combinator library
//////////////////////////////
 
// Based on http://legacy.cs.uu.nl/daan/download/parsec/parsec.html
 
//////////////////////////////
// Monad stuff
 
function bindM(m ,k)
{
    return function (s) {
    tmp = m(s);
    a = tmp[0]; s_ = tmp[1];
    return k(a)(s_);
    }
}
function thenM(m,k) { return bindM(m,function(_){return k;}); }
function returnM(v) { return function (s) { return [v,s]; } }
function evalS(m,s) { return m(s)[0]; }
function getS(s) { return [s,s]; }
function putS(s) { return function(_) { return [null,s]; } }
 
function doM(m) {
    if (arguments.length == 1) return m;
    else if (arguments.length % 2 && arguments.length >= 2) {
    var rest = Array.prototype.slice.call(arguments).slice(2);
    return arguments[1](m, doM.apply(this, rest));
    }
    else throw ("doM: Error: Arguments mismatch.");
}
 
function mapM(k,l) {
    if (l.length > 0) return doM(
    k(l[0])
      , bindM
      , function (item) { return doM(
      mapM(k,l.slice(1))
      , bindM
      , function (rest) {
          if (rest)
          return returnM(item.concat(rest)); 
          else
          return returnM(item);
      }
      ); }
    );
    else
    return returnM(null);
}
 
//////////////////////////////
// Parse stuff
 
function parse(parser, input) { return evalS(parser, input); }
 
function throwInt(msg,input) {
    var e = new Error();
    e.message = [msg,input];
    e.name = 'PARSE_ERROR'; throw e;
}
 
 
//////////////////////////////
/// Combinators
 
function choice_(m,k) {
  return function (s) {
      try {
      return m(s); 
      }
      catch (e) {
      switch (e.name) {
      case 'PARSE_ERROR':
          if (e.message[1].length != s.length) throw e;
          else return k(s);
          break;
      default:
          throw e;
      }
      }
  }
}
 
function try_(m) {
  return function (s) {
      try {
      return m(s); 
      }
      catch (e) {
      switch (e.name) {
      case 'PARSE_ERROR':
          e.message[1] = s; // Pretend we haven't consumed input
          throw e;
          break;
      default:
          throw e;
      }
      }
  }
}
 
var letter_ = doM(
    getS
  , bindM
  , function (input) {
      if (input.length == 0)
      return throwInt("Unexpected end of input, expected letter",input);
      if (input.match(/^[a-z]/i))
      return doM( putS(input.slice(1)) ,thenM, returnM(input[0]) );
      else    
        return throwInt("Expected letter ([a-zA-Z])",input);
  }
);
 
function char_(c) {
    return doM(
     getS
      , bindM
      , function (input) {
      if (input.length == 0)
          return throwInt("Unexpected end of input, expected '" + c + "'",input);
      if (input[0] == c)
          return doM( putS(input.slice(1)) ,thenM, returnM(c) );
      else
          return throwInt("Expected character '" + c + "'",input);
      }
    );
}
 
function string_(str) {
    return mapM(char_,str);
}
 
 
 
 
//////////////////////////////
// Run a parser
//////////////////////////////
 
/*
run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x
*/
function run(parser,string) {
    print("Parse output:");
    try {
    print(parse(parser,string));
    }
    catch (e) {
    switch (e.name) {
    case 'PARSE_ERROR':
        print("Parse failed: " + e.message[0] + ", input: " + e.message[1]);
        break;
    default:
        throw e;
    }
    }
}
 
 
//////////////////////////////
// Example parsers
//////////////////////////////
// from http://legacy.cs.uu.nl/daan/download/parsec/parsec.html
 
/*
parens  :: Parser ()
parens  = do{ char '('
            ; parens
            ; char ')'
            ; parens
            }
        <|> return ()
*/
// Parse some parentheses
function parens(s) {
  return choice_( doM( char_('(')
                     , thenM
                     , parens
             , thenM
             , char_(')')
              , thenM
               , parens
                       )
        , returnM(null)
        )(s);
}
 
/*
testOr  =   string "(a)"
        <|> string "(b)"
*/
var testOr = choice_( string_("(a)")
            , string_("(b)") );
 
/*
testOr1 = do{ char '('
            ; char 'a' <|> char 'b'
            ; char ')'
            }
*/
var testOr1 = doM( char_('(')
         , thenM
         , choice_( char_('a') , char_('b') )
         , thenM
         , char_(')')
         );
 
/*
testOr2 =   try (string "(a)")
        <|> string "(b)"
*/
var testOr2 = choice_( try_( string_("(a)") )
             , string_("(b)")
             );
 
/*
testOr3 =   do{ try (string "(a"); char ')'; return "(a)" }
        <|> string "(b)"
*/
var testOr3 = choice_( doM( try_( string_("(a") )
              , thenM
              , char_(')')
              , thenM
              , returnM("(a)")
              )
             , string_("(b)")
             )
 
/*
nesting :: Parser Int
nesting = do{ char '('
            ; n <- nesting
            ; char ')'
            ; m <- nesting
            ; return (max (n+1) m)
            }
        <|> return 0    
*/
 
function nesting(s) {
    return choice_(
    doM(
        char_('(')
      , thenM
      , nesting
      , bindM
      , function (n) {
          return doM(
          char_(')')
        , thenM
        , nesting
        , bindM
        , function (m) {
            return returnM(Math.max(n+1, m));
           }
          );
            })
    , returnM(0)
    )(s);
}

Name: Anonymous 2009-02-25 7:46

Testor.

Name: Anonymous 2009-02-25 8:07


standards which are probably   the most illegible   coding guidelines for.

Name: Anonymous 2009-03-06 8:10

Case if you really   need to do   that for us   which means we   have both first   class continuations and.

Name: Anonymous 2009-03-06 8:42

Penii My bad the   proper plurar form.

Name: Anonymous 2010-12-17 1:40

This post brought to you by the Gay Nigger Association of America

Name: Sgt.Kabukiman 2012-05-22 3:18

All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy
 All work and no play makes Jack a dull boy

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List