Showing posts with label scheme. Show all posts
Showing posts with label scheme. Show all posts

Wednesday, January 28, 2009

Brain Rules

I just read John Medina’s book Brain Rules. It is a book about how our brains work. What I find most interesting is how it applies to learning.

Attention

Our brains are able to pay attention to three things. It can be characterized by these questions.

  • Does it want to kill me?
  • Can I have sex with it?
  • Does it remind me of anything?

All three questions are relevant to how you give a presentation. If everyone seems to be dozing off they can be awakened by I sudden sound or a picture of something sexy. But these measures are just that, attention grabbers, and if a presentation is so boring that I have to slam the table all the time I’m definitely doing something wrong.

The third question: Does it remind me of anything? is different. It is very important both to giving presentations and to learning. If I can find a way while giving a presentation to have the audience relate to my subject in any way, they are more likely to pay attention. It’s the same with learning. If I’m learning something that reminds me of something else it will be easier for me to put it in a context that means something to me and that will enable me to learn it much better.

I find this very interesting since lately I’ve found that I like doing things that I suck at. The things I like and suck at are very diverse. I have started to like skateboarding, playing Guitar Hero, and even carpentry. I think that it is because I know more now and even if I’m no good at these things they remind me of other things that I’m better at. And just as important, they widen my frame of reference, so next time when maybe I have to weld something I wont find the entrance barrier to high to even imagine doing it. The more I recognize, the more I relate to, the more I like. It is a good loop.

Memory

In the book Medina also talks about memory. There are, at least, two kinds of memory, short-term memory and long-term memory. The short-term memory is our working memory and it is good for very short periods of time. To store something in long-term memory, repetition is required. The more I repeat something, the better I will learn it.

The best books I have read that take advantage of repetitions without being boring are The Little Schemer-series, The Little Schemer, The Seasoned Schemer and The Reasoned Schemer. These books are built up as a series of questions in one column and the answers in another. The difficulty increases gradually as you read more.

The point of The Little Schemer is to teach to think recursively in Scheme. It does a great job of teaching this, probably because of all the repetitions that are involved.

The point of The Seasoned Schemer is to teach more advanced concepts of functional programming in Scheme, such as continuations.

The point of The Reasoned Schemer is to teach logic programming in a functional context.

It is interesting that the concepts taught in the books are quite complex and still they never feel hard when presented in this way. I highly recommend them to anyone.

Another interesting thing about repetition is that it seems to be happening while we sleep. When we are sleeping our brains keep repeating things that we learned during the day. After going to sleep while reading The Seasoned Schemer, I remember waking up one morning and finally getting how continuations work. Quite a good feeling.

Stress

Stress affect learning in a bad way for almost everybody. Stress is defined, to allow researchers to measure it, as having three criteria.

  • It has to create physical arousement.
  • If you could avoid it, you would.
  • It has to feel like it is out of your control.

If any of the above is true, it is said to be stress. When we are stressed our brains cannot focus on the task at hand and this will decrease our learning abilities severely.

You can also listen to John Medina talking about the book on the Ruby on Rails Podcast.

Friday, December 19, 2008

The Y-Combinator

I finally found the time to grok the Y-combinator. There are already multiple examples available but I am to thick to get them and, therefore, wanted to derive it myself.

The Y-combinator is a wonderful piece of software that allows you to create self-referential programs without built-in support. That is, it allows me to create anonymous recursive functions. This is best shown by an example.

; The factorial function
(define fact
  (lambda (n)
    (if (< n 2) 1 (* n (fact (- n 1))))))

In the recursive function above the fact refers to itself by name. This relies on the name being available before it is actually defined. To avoid this we can send the function as a parameter to itself. Like so:

; Define a local variable g as the function.
; The function takes a function (itself) as an extra parameter.
; The function is called with itself as a parameter:  (g g 5)).
; This doesn't compile since the function h (that is g) requires 
; an additional parameter.
(let ((g (lambda (h n)
           (if (< n 2) 1 (* n (h  (- n 1)))))))
  (g g 5))

; The working version needs h to also call itself (h h (- n 1)).
(let ((g (lambda (h n)
           (if (< n 2) 1 (* n (h h (- n 1)))))))
  (g g 5))

We can now abstract over the h parameter with a technique reminiscent of currying.

; A new lambda is abstracted over h.
; Note that the function calls to g and h need to change ((g g) 5)) 
; and ((h h) (- n 1)) to ensure that they agree with the definitions.
(let ((g (lambda (h)
           (lambda (n)
             (if (< n 2) 1 (* n ((h h) (- n 1))))))))
  ((g g) 5))

We can now abstract over n and (h h) creating a new lambda with the parameters q and m.

; Function f is declared locally with the parameters q and m 
; and then called directly (f (h h) n).
(let ((g (lambda (h)
           (lambda (n)
             (let ((f (lambda (q m)
                        (if (< m 2) 1 (* m (q (- m 1)))))))               
               (f (h h) n)))))
      ((g g) 5)))

Notice that f is independent of it’s context and can be moved to the top level.

; f moved to the top level.
(let ((f (lambda (q m)
           (if (< m 2) 1 (* m (q (- m 1)))))))
  (let ((g (lambda (h)
             (lambda (n)
               (f (h h) n)))))
    ((g g) 5)))

I can now abstract over q to isolate the definition of fact.

; Notice that the inner function of f is the original fact function.
(let ((f (lambda (q) 
           (lambda (m)
             (if (< m 2) 1 (* m (q (- m 1))))))))
  (let ((g (lambda (h)
             (lambda (n)
               ((f (h h)) n)))))
    ((g g) 5)))


Now I abstract over the local variable f and declare a new variable Y. The call to ((g g) 5) is replaced (g g) and moved to the Y function instead.

; A new variable Y is created for the abstraction over f.
; The function call is moved to the application of Y.
(let ((Y (lambda (f)
           (let ((g (lambda (h)
                      (lambda (n)
                        ((f (h h)) n)))))
             (g g)))))
  ((Y (lambda (q) 
        (lambda (m)
          (if (< m 2) 1 (* m (q (- m 1))))))) 5))

Finally we replace the local variable Y with a the function Y, the Y-combinator.

(define Y
  (lambda (f)
    (let ((g (lambda (h)
               (lambda (n)
                 ((f (h h)) n)))))
      (g g))))

Excellent!