Norvig's reboot of Strachey's [1966 checkers program](http://norvig.com/sciam/checkers-complete.html) (ab)uses default arguments to map CPL's 1960's era use of `let`-binding. Now, there are other [stupid tricks](https://www.mail-archive.com/kragen-discuss@canonical.org/msg00026.html) one can play with binding in python, but my current favorite involves misuse[0] of comprehensions. With a bit of effort, we even have `letrec`: print(min( f(6) for Y0 in [lambda y,f: lambda *x: f(y(y,f))(*x)] for f in [Y0(Y0,lambda fac: lambda n: 1 if n<2 else n*fac(n-1))])) Exercise 1: add one line to produce the classic `Y` Exercise 2*: modify `Y0` to support the classic mutual recursion between `even` and `odd` [0] or not exactly misuse? cf Wadler's [Comprehending Monads](http://ncatlab.org/nlab/files/WadlerMonads.pdf) (p19,infra): > [the existence of the map from the identity to the list monad] explains a trick occasionally used... ---- If anyone feels like taking another run at Cleese (a python VM as bare-metal OS*), it might be worth taking advantage of NetBSD [rump kernels](http://rumpkernel.org/). * in this case, the stupid python trick was loading and running a gcc-compiled C "hello world" program underneath a python supervisor. ---- Dave's Stupid Python Tricks (mark II) `Fun`: a toy for interpreting [GFM Tables](https://help.github.com/articles/github-flavored-markdown/#tables) per [McCarthy 1960](http://www-formal.stanford.edu/jmc/recursive/node2.html): ![Image 8.png](/media/224/Image%208.png) Fun = lambda s: min( globals().update(eval(com(par(s)))) for par in [lambda txt: [[f.strip() for f in pline(l.split('|'))] for pline in [ lambda xs: ((xs[0],'') if len(xs)==1 else xs if len(xs)==2 else xs[1:3] if len(xs)==4 else None) ] for l in txt.strip().split('\n') ]] for com in [lambda xs: compile(xs[0],xs[1:]) if xs and None not in xs else '[]' for nonsep in [lambda s: any(c not in ' -:' for c in s)] for compile in [lambda hdr,bdy: '[("{}",(lambda {}:{} None))]'.format( hdr[0], hdr[1], ' '.join(clause(b) for b in bdy if nonsep(b[0]+b[1]))) for clause in [lambda b: '({}) if ({}) else'.format( b[0], b[1] or 'True')]]]) if __name__ == "__main__": Fun(''' | fact | n | |------------:|:----| | 1 | n<2 | | n*fact(n-1) | | ''') print(fact(5)) Fun(''' gcd | x,y ----------:|:--- gcd(x-y,y) | y']] for js in [[i for i,l in enumerate(ls) if l[0]=='@']+[None]] for i,j in zip(js[:-1],js[1:]) for rk,rvs in [(ls[i],ls[i+1:j])]} print(':: :: ::\n'.join( expand(node, findcode(test)) for node in ['k & r','ansi'] for test in [r""" this is a test of barely-literate programming. :: :: :: First, we try an old-timer program: @k & r >main(@formal names@) >@formal declarations@ >{ > printf(@greetings@); >} > Not that we use them in this program (it is, after all, a constant function, cf. the 'K' combinator) but for nostalgia value, we have @formal names >argc, argv @formal declarations >int argc; >char *argv[]; and, of course, we should specify the value which the function takes at all arguments: @greetings >"Hello, world\n" :: :: :: Now, let's rewrite this in a more modern style: @ansi >@external declarations@ > >int main(@inline formal declarations@) >{ > printf(@greetings@); > @more boilerplate...@ >} > You'll notice that we have an 'int' in there. That's because once one has more than a few K of memory to play with during a compile, it turns out that silently assuming all params are machine words isn't the best tradeoff. Of course, now that we've declared that we're returning an int, we'd probably better do so: @more boilerplate... >return 0; We must declare the argument types as well as the return types: @inline formal declarations >int argc, char **argv, char **envp As in Pascal, the types are now specified in with the argument names. One might expect that we'd need some additional bookkeeping for printf() as well as main(), but luckily (if one is not the preprocessor) this is a matter of including the proper header file. @external declarations >#include :: :: :: (to get fancier, one might try piping output through "tcc -run", but it would probably be better to fill in the code sketched here and improve its robustness and input format) """])) ---- Reservoir sampling, AKA [deal](https://en.wikipedia.org/wiki/Reservoir_sampling). *(in APL, at 110 baud, that main expression would have been something like`HAND 5?52`)* import random;print(min( hand(deal(5,range(52))) for vals,suits in [("A23456789TJQK", "CDHS")] for hand in [lambda js: " ".join([ vals[v]+suits[s] for j in js for s,v in [divmod(j,13)]])] for resv in [lambda rs,xs,k: rs if not xs else min([resv([r if i!=j else xs[0] for i,r in enumerate(rs)], xs[1:],k+1) for j in [random.randint(0,k)]])] for deal in [lambda n,xs:resv(xs[:n],xs[n:],n)] )) ---- print((lambda d:d+repr(d)+"))")('print((lambda d:d+repr(d)+"))")('))