[racket] Rosetta Sokoban Solution

From: Sean Kanaley (skanaley at gmail.com)
Date: Mon Jun 10 17:48:55 EDT 2013

It doesn't have to be exactly PicoLisp.  I would be happy with a thin 
wrapper library that simply translates super-long-names into names.  
Define being called "define" because it equals the English spelling 
isn't too compelling or else German programmers are in trouble.  define 
is definieren.  I imagine define-syntax-parameter is 
definieren-schalggendlahg-paravolddennneinen and they probably use 230 
width margins as a default...else they don't use full words.  In Pico, 
define = de.  Many newish languages use def. Haskell goes off of 
formatting and "=" (a single character is about as good as it gets...).  
Arc's print = pr, etc.  It's not good when a /functional/ language's 
main function-defining-construct takes the same total characters as 3 
other languages combined (def+de+=).

The following is halfway about Racket conventions/style, halfway about 
pattern matching is evil (esp. without type inference), and is mainly me 
rambling, so be advised...

I have thought further about mixed data and verbosity, and I believe the 
fundamental issue is static typing, the lack of, and trying to simulate 
it with fancier types (at the expense of verbosity).  Mixed data without 
static types thus has the verbosity downside but without the 
hypothetical safety upside...the struct amounts to a built-in /comment/ 
about what is supposed to be its data, but it's really just a list with 
lengthier access functions and lack of list-powered functions to operate 
on it.  Lack of static typing means (struct pos (x y)) sure looks like 
something that contains numbers but in untyped Racket it's really just 
(list any/c any/c), without the ability to treat it as a list.  So 
something like e.g. distance from 0 in the moves on a square grid sense is:

(+ (pos-x p) (pos-y p))

instead of:

(apply + p)

which really should be:

(app + p)

Then, if you change the struct, your code is secretly wrong everywhere 
you pattern match.  One is "supposed" to abstract with functions.  In 
SICP it's a given that accessors are in terms of caadaaar and such, 
versus relying on the fact that it's actually /at/ the position referred 
to by caadaaar, exactly what pattern matching does.  Many example 
problems for the purposes of demonstrating the value of abstraction have 
the reader redefine the datatype, requiring changes to /only/ the 
accessors, say cadaar instead of cdadar.  Pattern matching undoes this 
advantage and the programmer is in a situation where every usage of the 
struct must be tracked down or suffer runtime errors.  This disadvantage 
is minimized with static typing and type inference.  Haskell can tell 
you that either 1. a String is not an Int within some ADT or that 2. 
there aren't enough positions matched against in the first place. The 
syntax is also superior:

(match-define (cons (pos x y) ps) ps0

versus, in Haskell:

(Pos x y):ps' = ps

Or in "short Racket":

(mdef (cons (cons x y) ps) ps0

or even:

(mde ((x.y).ps) ps0

and we're at half the length of normal Racket, or:

caar, cdar, and cdr respectively to compose the "struct" access 
functions with the list ones with the addition of a single letter (caar 
vs. (compose pos-x car)), or, lastly, to be fully SICP compliant, using 
names that the struct maker in Racket would've come up with, except 
potentially much shorter than the auto-generated ones.  I'm aware these 
can be renamed, but there's still the disadvantage that structs aren't 
lists.

As for going pure cons, I don't believe caar is a spaghetti code version 
of the pattern match above.  In the programmer's mind x has to be 
constantly thought of as the most recent position's x coord all the way 
through the section where it's in scope, or else he can't be using it 
correctly.  He must know what x really/is/, not /where/ he got it from.  
Pattern matching emphasises the /where/. It's semi-necessary though in 
supposedly good coding style because the struct "should" have a solid 
name like item and fields with solid names like "weight", meaning that 
accessing a couple things is:

(item-weight i)
(item-value i)
etc.

instead of:

(car i)
(cadr i)

This verbosity encourages the use of the matcher,

(define-match (item w v) i

Yet that is nearly as long in total character length as the long 
accessors thanks to deeffiinnneee-maaattchhh, and forever ties w to 
whatever happens to be in the left-most position.

Pattern matching issues aside, I believe Racket could benefit from 
chopping 50% of the letters out of its identifiers.

list-ref = nth
define = def
define-values = defs
define-X = def-X
apply = app
vector-set! = vec!
set-box! = box! (in general, the "!" indicates a setter, so do away with 
the "set-")
print = pr
display = disp
string-X = str-X
append-map = map* / mappend / mapp
null? = nil?
lambda = delete entirely, because pressing ctrl+\ and getting an actual 
lambda is vastly superior, or replace with "\" to keep it simple

On 06/10/2013 02:28 PM, Matthias Felleisen wrote:
>
> On Jun 10, 2013, at 1:49 PM, Sean Kanaley wrote:
>
>> But if I had to choose which language seems to actually produce 
>> better code, I would have to side with PicoLisp. 
>
> I wonder whether we could implement pico as a language and then write
>
>  #lang racket/pico
>
> and just reuse the PicoLisp code.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130610/a0ec2910/attachment-0001.html>

Posted on the users mailing list.