Thursday, March 30, 2006

 

Python Monad

It looks like I've got a Python monad working in the Simple Lambda Evaluator:
E:\work\lambda>python elle.py
------------------------------------------------------------------------------
((#pyseq((#pycall "print")((#cons "hello")((#cons "world")#nil))))(\x.((#pycall
"print")((#cons "wow")#nil))))
------------------------------------------------------------------------------
hello world
wow
['#', None]
So far I've only tested output - input will have to wait a while. The significant changes made to the evaluator include:
  1. A new cell type (#) containing a raw python value;
  2. Builtin functions #pyseq and #pycall. The #pycall function accepts two arguments: the name of the Python function, and a list of arguments;
  3. Additional builtin functions #cons etc... that aren't strictly required, but ensure that the handling of lists by elle and the evaluator is consistent.
I must admit to having had great reluctance in introducing these builtin functions, but am relieved that the implementation is quite clean. For example, below is an snippet of code:
_car = [ '\\', 'c', [ '@', [ 'V', 'c' ], [ '\\', 'h', [ '\\', 't', [ 'V', 'h' ] ] ] ] ]
_cdr = [ '\\', 'c', [ '@', [ 'V', 'c' ], [ '\\', 'h', [ '\\', 't', [ 'V', 't' ] ] ] ] ]
_true = [ '\\', 'x', [ '\\', 'y', [ 'V', 'x' ] ] ]
_false = [ '\\', 'x', [ '\\', 'y', [ 'V', 'y' ] ] ]
_nil = [ '\\', 'c', _true ]
_nullq = [ '\\', 'c', [ '@', [ 'V', 'c' ], [ '\\', 'h', [ '\\', 't', _false ] ] ] ]

def nullq( cell ):
    """Return True if at the end of the list, else False
    """
    return bool( _arg( [ '@', [ '@', [ '@', _nullq, cell ], [ 'N', 1 ] ], [ 'N', 0 ] ], 'N' ) )

def car( cell ):
    "First element of a list"
    root = [ '@', _car, cell ]
    reduce( root )
    return root

def pyval( cell ):
    "Extract python value from cell"
    if cell[ 0 ] in 'N"#':
        return cell[ 1 ]
    else:
        raise "Bad python cell '%s'" % cell[ 0 ]

def _pycall( stack ):
    "(#pycall  )"
    if len( stack ) < 3:
        raise "Not enough arguments"
    fn = _arg( stack[ -2 ][ 2 ], '"' )
    el = stack[ -3 ][ 2 ]

    args = []
    while not nullq( el ):
        args.append( pyval( car( el ) ) )
        el = cdr( el )
    stack[ -3 ][ 0 ] = "#"
    stack[ -3 ][ 1 ] = pyfunc( fn )( *tuple( args ) )
Now that is not too bad - the function nullq() (testing for the end of the list) builds a cell representation of an expression, and uses the evaluator to calculate a (Python) boolean (True if at the end of the list). A similar trick is used by car() and cdr(). The pyval() function is also quite simple: if the cell can be interpreted by Python its value gets extracted.

In essence, all that the builtin implementations of #car, #cdr etc... do is enforce a lambda expression. The underlying evaluation does not take any short cuts - the lambda expressions are still evaluated.


This page is powered by Blogger. Isn't yours?