scalapuzzlers / scalapuzzlers.github.com

Github Pages behind scalapuzzlers.com
www.scalapuzzlers.com
161 stars 53 forks source link

Adaptive Reasoning: adapting to () #74

Closed som-snytt closed 11 years ago

som-snytt commented 11 years ago

From the ML, the perils of adapting to Tuple0 aka Unit value.

som-snytt commented 11 years ago

I think this makes use of Andrew's suggestions from the superseded PR, although it may not be as simple at-a-glance as he'd like.

It plays on the current value of userName, as suggested, and shows the one-character change to make it work as expected.

I neglected to add humo(u)r.

The html might be iffy.

demobox commented 11 years ago

@som-snytt Thanks for the updated submission. I like! Couple of small comments. @nermin Thoughts from your side..?

demobox commented 11 years ago

Ah, I see the reason now for the object Test extends App. Executing val printer = new Printer{ prompt } "directly" in the REPL results in

scala> val printer = new Printer{ prompt }
Yes, Master> printer: Printer = $anon$1@76ad043
...

which unfortunately rather gives the game away :-( Here's a potential version that gets around that:

var userName: String = "root"

class Printer(labeller: =>Unit) {
  def print(message: =>String, labelled: Boolean = false) {
    if (labelled) labeller
    Console println s"$message  $message"  // repeat message to make sure it gets thru
  }   
}

class Greeter(printer: Printer) {
  def greet(whom: String) {
    userName = whom      // to whom are we speaking?
    printer print (if (userName == "root") "I am Master of the Universe!" else "hello, world.")
  }
}

def prompt() {
  Console print (if (userName == "root") "Yes, Master> " else s"$userName$$ ")
}

new Greeter(printer = new Printer { prompt }) greet "paulp" // prints "Yes, Master> hello, world.  hello, world."
demobox commented 11 years ago

I think this makes use of Andrew's suggestions from the superseded PR, although it may not be as simple at-a-glance as he'd like.

grin.

I guess my personal "puzzler aesthetic" is a one-line statement or single command that appears obvious but still does something totally unexpected is the goal for which to aim.

I this particular case, I think if we work back from the explanation we feel the "puzzling" part is the fact that the argument to Printer is evaluated immediately. We're currently using this fact to produce two unexpected effects:

If we can reduce this to one unexpected effect it the puzzler will hopefully be quicker and easier to scan and still be as puzzling. If we take the first effect, we could use something like:

var userName: String = "root"

class Printer(labeller: =>Unit) {
  def print(message: =>String) {
    labeller
    Console println s"$message  $message"  // repeat message to make sure it gets thru
  }   
}

class Greeter(printer: Printer) {
  def greet(whom: String) {
    userName = whom      // to whom are we speaking?
    printer print s"Hello, $whom!"
  }
}

def prompt() {
  Console print (if (userName == "root") "Yes, Master> " else s"$userName$$ ")
}

new Greeter(printer = new Printer { prompt }) greet "paulp" // prints "Yes, Master> Hello, paulp!  Hello, paulp!"

If we go for the second effect, we could use something like this (similar to the discussion item from the first submission):

class Printer(labeller: =>Unit) {
  def print(message: =>String, labelled: Boolean = false) {
    if (labelled) labeller
    Console println s"$message  $message"  // repeat message to make sure it gets thru
  }   
}

def prompt() {
  Console print "puzzler$ "
}

new Printer { prompt } print (message = "Hello, world!", labelled = true) // prints "puzzler$ Hello, world!  Hello, world!"
new Printer { prompt } print (message = "Hello, world!")  // also prints "puzzler$ Hello, world!  Hello, world!"

@som-snytt will no doubt guess correctly that I personally my preference would be for the second version as it's shorter, avoids vars (the use of which doesn't really feel like a "good example" to me) and hopefully is still puzzling because it's easy enough to reason correctly about what the first print does and thus to (hopefully) just as easily set up a false expectation for the second one.

With the first version, the re-assignment to a var in the greet function might be "weird" enough for users to have more difficulty trying to figure out what the expected result should be. That would make the puzzler less puzzling.

Curious to hear everyone's thoughts!

som-snytt commented 11 years ago

OK, here's the demobox version.

I am pleased that, although the puzzler is about adapting to (), the puzzler doesn't actually print ().

Although that would have been pretty funny.

som-snytt commented 11 years ago

The answer starts with an outdated comment about evaluation of message. I remember now why I wanted emphasize that, but it's not a big deal. If you're unsure about what =>Unit means, you'll see =>String nearby and feel reassured.

I couldn't figure out how to annotate a non-diff line at the commit.

demobox commented 11 years ago

Merged: https://github.com/scalapuzzlers/scalapuzzlers.github.com/commit/1a06386c503570af5e6381180e803ed8fe510034 See http://scalapuzzlers.com/#pzzlr-036

Thanks, @som-snytt !