markrbower (11) [Avatar] Offline
#1
Am enjoying the book, and totally get the idea that the authors want users to learn a new programming paradigm. Just wish there more examples to try things out. Am trying to get Exercise 7.5.3 (have humans move towards mouse click locations) to run, but am hitting loads of roadblocks. Conceptually, it seems simple: Use a MouseAdaptor to acquire the mouse click locations (ev.getPoint) and then send that to the humans to calculate the angle from their current location to the location of the click. Making this work with FRP is a horse of another color. Best I can tell, I’m supposed to make a cell to hold the location of the click, a stream to take a snapshot of the Cell and convey the point, and have some way for humans to download the Point from that stream, and have all of this running in some kind of loop (like bites) so that it updates the scene. I made a copy (“bird.java”) of an existing main program (“dynamic.java”) and then have modified Animate.java (the MouseAdaptor provided by the authors), HomoSapiens.java (to get the stream into humans), and BitableHomoSapiens.java (to try to download the click location and change the trajectory). I would post the code, but problems abound: the only thing that compiles in the MouseAdaptor is a StreamLoop<Set<Point>> and it is not clear how to download the Point value from a StreamLoop<Set<Point>> object.

This seems like it should be a pretty simple (and fun!) thing to do, but that might be causing those who already know Sodium and FRP to forget how difficult it is to learn a new paradigm. Working examples online (I’ve looked, but can’t find any) would be helpful.
Stephen Blackheath (111) [Avatar] Offline
#2
Hi!

I'm a bit confused by what you wrote, but if you post what you've got already I'll take a look. I'll assume you want clues rather than a complete answer (though I haven't actually done this exercise).



Steve
markrbower (11) [Avatar] Offline
#3
Thank you for responding. Here is the relevant code, which is cut from three different programs. My thought was to copy the pattern of sBite, so I’m sure that added a lot of unnecessary code. My guess is that someone who knows how to do this (you) will be able to change just 3 or 4 lines; conceptually, it just seems like it should be easy.

bird.java (copy of dynamic.java)

static class State {
State() {

this.sTweets = new HashMap<>();
}
State(int nextID, Map<Integer, Cell<Character>> chars,
Map<Integer, Stream<Integer>> sBites,
Map<Integer, Stream<Integer>> sDestroys,
Map<Point, Stream<Point>> sTweets) {

this.sTweets = sTweets;
}

final Map<Point, Stream<Point>> sTweets;


State add(Cell<Character> chr, Stream<Integer> sBite,
Stream<Integer> sDestroy) {

return new State(nextID+1, chars, sBites, sDestroys, sTweets);
}



Animate.java:

private StreamLoop<Set<Point>> sTweet;

public Animate(Animation animation, List<Polygon> obstacles, StreamLoop<Set<Point>> sT)

addMouseListener(new MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent ev) {
cTweet = new Cell<Point>(ev.getPoint());
sTweet.snapshot(cTweet);
}
});



BitableHomoSapiens.java

public class BitableHomoSapiens {
public BitableHomoSapiens(
World world,
int self,
Point posInit,
Cell<Double> time,
Stream<Unit> sTick,
Stream<Set<Integer>> sBite,
Cell<List<Character>> scene,
StreamLoop<Set<Point>> sT)
{
final StreamLoop<Set<Point>> sTweet = sT;
...
Should I add something like “this.Bite…” at the end of the constructor?

As you can see, I have no idea how to proceed. None of the widgets examples or Chapter 2 patterns had anything like this in them. Ideally, I would just add a Stream to the MouseAdapter and read it in BitableHomoSapiens to extract the Point values, but it is not clear how to "connect the plumbing."

Any advice or clues would be appreciated.
Mark



Stephen Blackheath (111) [Avatar] Offline
#4
Hi Mark,

How about we declare it like this in Animate.java:

CellSink<Optional<Point>> tweet = new Cellsink<>(Optional.empty());

It would have a value when the mouse is down and no value when it's released:

public void mousePressed(java.awt.event.MouseEvent ev) {
tweet.send(Optional.of(ev.getPoint()));
}

public void mouseReleased(java.awt.event.MouseEvent ev) {
tweet.send(Optional.empty());
}

When you pass it through the code, use the type Cell<Optional<Point>> rather than CellSink. Try that and let me know if you're still stuck somewhere.


Steve
markrbower (11) [Avatar] Offline
#5
That worked! I made the changes you suggested to Animate, passed the variable through animate.create(), then through CreateCharacters(), then through BitableHomoSapiens, and then added the following to the HomoSapiens.Trajectory constructor:
Optional<Point> tp = tweet.sample();
if ( tp.isPresent() ) {
	Point pt = tp.get();
	System.out.println( "Last click: " + pt.getX() + " " + pt.getY() );
}

I will try to make it "pretty" and then post some sample code for others.

It all still seems a bit like voodoo with all of the mysterious type changes ("It's a CellSink, but pass it as a Cell..."), but perhaps it will make more sense as I read on.

Thanks, again!
Mark




Stephen Blackheath (111) [Avatar] Offline
#6
Hi Mark,

Great!

That's all legitimate FRP, but it would be more 'normal' and might help your understanding to pass the sampled value (tp) to the Trajectory constructor rather than 'tweet'. That way it's really clear from reading the code that tweet.sample() is being called in the context of a particular map() or snapshot() invocation.

CellSink exposes the ability to write into a Cell. This can only be used on the interface from the 'real world' to FRP land. Once inside FRP land, 'tweet' must be strictly treated as a Cell. So, you downcast it to Cell and then it's safe from anyone breaking the rules of FRP.


Steve