Re: curried and/or closured value dispatch

Bryn Keller <[email protected]> Tue, 08 Mar 2005 17:56:56 -0800
Newsgroups gmane.comp.lang.nice.general
Message-ID <[email protected]>
Hi Steve,

In concept, this should work. However, you're running up against two 
problems: First, it's not currently possible to override locally defined 
methods, and second, it's not currently possible to use a dotted name as 
a constant for value dispatch. I'm not sure how hard these problems 
would be to fix, but I'd definitely like to see them fixed as well. 
Actually, now that I try to write a workaround, it looks like it's not 
possible to use an imported constant for value dispatch, only one that's 
defined in the same module. I'm sure these problems will be corrected in 
the future.

In the mean time, let's try another approach. What you need could be 
described as a lookup table. We'll just use higher-order functions to 
build a literal lookup table. You'll need to have the function always(), 
which is defined in nice.functional as:

/**
 * Returns a function which always returns the same result,
 * no matter what argument it's called with.
 */
<T,U> U->T always(T constant) = U u => constant;

It's not in .9.10, but it is in the CVS repository.  We'll need to box 
up all the methods you might want to call so they all have the same type 
signature (KeyEvent->void in this case). We'll write a special wrapper 
for some kinds, and for others, always() will suffice.

import java.awt.event.*;
import nice.functional;

let (int, int) NORTH = (0, -1);
let (int, int) SOUTH = (0,  1);
let (int, int) EAST  = (1,  0);
let (int, int) WEST  = (-1, 0);

KeyEvent->void moveWrapper((int,int)direction) = KeyEvent e => 
moveOrCharge(e, direction);

let Map<int, KeyEvent->void> actions = [
                           (KeyEvent.VK_8, moveWrapper(NORTH)),
                           (KeyEvent.VK_K, moveWrapper(NORTH)),
                        //etc...
                           (KeyEvent.VK_N, KeyEvent e => 
nextLevel(currentLevel + 1)),
                           //etc...
                            (KeyEvent.VK_Q, always(saveAndQuit)),
                           (KeyEvent.VK_R, always(restartLevel)),
                           (KeyEvent.VK_U, always(undoLastPush)),
                               (KeyEvent.VK_W, always(playFinale))
                                             
                                                   ].cast().listToMap();


void handleKeypress(KeyEvent e) {

    if ( !(currentlyAnimating || playingFinale) ) {
      let action = actions[e.getKeyCode()];
      if (action != null)
    action(e);     
    }   
}


Hope that helps,

Bryn


Steve Yegge wrote:

>Greetings,
>
>I'm trying to write a key handler in my NiceSwing app, and here's
>the meat of it:
>
>let (int, int) NORTH = (0, -1);
>let (int, int) SOUTH = (0,  1);
>let (int, int) EAST  = (1,  0);
>let (int, int) WEST  = (-1, 0);
>
>void handleKeypress(KeyEvent e) {
>    void handleKey(int code) {}
>
>    handleKey(KeyEvent.VK_UP)    = moveOrCharge(e, NORTH);
>    handleKey(KeyEvent.VK_8)     = moveOrCharge(e, NORTH);
>    handleKey(KeyEvent.VK_K)     = moveOrCharge(e, NORTH);
>
>    handleKey(KeyEvent.VK_DOWN)  = moveOrCharge(e, SOUTH);
>    handleKey(KeyEvent.VK_2)     = moveOrCharge(e, SOUTH);
>    handleKey(KeyEvent.VK_J)     = moveOrCharge(e, SOUTH);
>
>    handleKey(KeyEvent.VK_RIGHT) = moveOrCharge(e, EAST);
>    handleKey(KeyEvent.VK_6)     = moveOrCharge(e, EAST);
>    handleKey(KeyEvent.VK_L)     = moveOrCharge(e, EAST);
>
>    handleKey(KeyEvent.VK_LEFT)  = moveOrCharge(e, WEST);
>    handleKey(KeyEvent.VK_4)     = moveOrCharge(e, WEST);
>    handleKey(KeyEvent.VK_H)     = moveOrCharge(e, WEST);
>
>    handleKey(KeyEvent.VK_N) = nextLevel(currentLevel+1);
>    handleKey(KeyEvent.VK_P) = nextLevel(currentLevel-1);
>    handleKey(KeyEvent.VK_Q) = saveAndQuit();
>    handleKey(KeyEvent.VK_R) = restartLevel();
>    handleKey(KeyEvent.VK_U) = undoLastPush();
>    handleKey(KeyEvent.VK_W) = playFinale();
>
>    if ( !(currentlyAnimating || playingFinale) ) {
>	handleKey(e.getKeyCode());
>    }    
>}
>
>What I want is to be able to dispatch on the value of the key code,
>but pass the actual KeyEvent to the moveOrCharge function.
>
>I've tried all sorts of variations on this code, and none are working.
>The one above is an attempt to define them all internally to
>handleKeypress(), in the hopes that the sub-methods will close
>over the KeyEvent parameter.
>
>Another possibility would be to create curried versions that have
>the KeyEvent parameter pre-packaged.
>
>Here's some equivalent Java code to give the flavor of what I'm doing:
>
>	Map<Integer, int[]> mk = new HashMap<Integer, int[]>();
>	for (int k : new int[]{VK_UP,    VK_8, VK_K}) mk.put(k, NORTH);
>	for (int k : new int[]{VK_DOWN,  VK_2, VK_J}) mk.put(k, SOUTH);
>	for (int k : new int[]{VK_RIGHT, VK_6, VK_L}) mk.put(k, EAST);
>	for (int k : new int[]{VK_LEFT,  VK_4, VK_H}) mk.put(k, WEST);
>	MOVE_KEY_MAP = mk;
>
>    void handleKeypress ( KeyEvent e ) {
>	if ( m_currentlyAnimating || m_playingFinale ) return;
>	int[] dir = MOVE_KEY_MAP.get(e.getKeyCode());
>
>	if (dir != null) {
>	    moveOrCharge (e, dir[0], dir[1]);
>	}
>	else {
>	    switch (e.getKeyCode()) {
>	    case VK_N:  nextLevel(m_currentLevel+1); break;
>	    case VK_P:  nextLevel(m_currentLevel-1); break;
>	    case VK_Q:  saveAndQuit();  	     break;
>	    case VK_R:  restartLevel();   	     break;
>	    case VK_U:  undoLastPush(); 	     break;
>	    case VK_W:  playFinale();	 	     break; // test winning
>	    }
>	}
>    }
>
>First I'd love to know how to get it working, *any* way -- doesn't
>have to be value dispatch.  I'd prefer not to have to use a giant
>cascading if-statement, though.
>
>Second, I'd love to know how to do it reasonably elegantly.
>There's a lot of duplication in my Nice attempt above.  For instance,
>is it possible to do value dispatch by saying "call this one for any
>of these three particular values?"  Something like:
>
>handleKey([VK_UP, VK_8, VK_K]) = ...
>
>or perhaps:
>
>for (int code : [VK_UP, VK_8, VK_K]) handleKey(code) = ...
>
>Oh, and is it possible to do the equivalent of Java 1.5's new static
>import, so I can refer to VK_UP, etc. without prefixing the KeyEvent
>classname?  (Not a big deal, just wondering).
>
>Thanks again!
>
>-steve
>
>
>-------------------------------------------------------
>SF email is sponsored by - The IT Product Guide
>Read honest & candid reviews on hundreds of IT Products from real users.
>Discover which products truly live up to the hype. Start reading now.
>http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
>_______________________________________________
>Nice-info mailing list
>[email protected]
>https://lists.sourceforge.net/lists/listinfo/nice-info
>
>
>  
>



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click