Thursday, June 12, 2008

Let There Be Local Variables

Actually, there aren't any. There are only function parameters. But there's a workaround: use functions.

Suppose you're writing a token analyser for some input. 'token-generator is a generator function. You need to determine the type of a token - return 'string if you think it's a string, 'char, 'int, etc. Naïvely, you might

(def token-type (token-generator)
(get-token-type (token-generator)))

(def get-token-type (tok)
(if (is (tok 0 #\")) 'string
(is (tok 0 #\#) 'char)
(is-digit (tok 0)) 'int))

So you get your input from 'token-generator, but you're really interested in 'tok. So the function 'get-token-type provides the local variable 'tok for you to work with. The disadvantage is that your namespace gets polluted with a zillion little functions that are only useful to their immediate neighbours. Wouldn't it be nice to, like, click Refactor > Inline Method like you can in a real language?

Well, you can.

(def token-type (token-generator)
((fn (tok)
(if (is (tok 0 #\")) 'string
(is (tok 0 #\#) 'char)
(is-digit (tok 0) 'int))) (token-generator)))

The ( (fn (tok) (if blah)) (token-generator) ) is a call to an anonymous function that declares the 'tok parameter for you to work with.

Now your namespace is no longer polluted, but you have this damned ugly thing in the middle of your function. No ordinary human is expected to read this.

Enter 'let

'let is a macro that transforms its humanly-readable input into something resembling the mess above.

(def token-type (token-generator)
(let tok (token-generator)
(if (is (tok 0 #\")) 'string
(is (tok 0 #\#) 'char)
(is-digit (tok 0) 'int))))

'let lets you pretend you are actually declaring a local variable. Coming from another language, you might think that this is, really and truly, a local variable. It's not. Behind the scenes, it's an anonymous function creating a lexically scoped 'tok parameter. But you don't care. You have your local variable.

Here is the pattern:

(let a b stuff)


((fn (a) stuff) b)

'with is a more general purpose macro that does the same thing, but for multiple variables.

(with (a 1 b 2 c 3) stuff)


((fn (a b c) stuff) 1 2 3)

'let exists because in the special case of binding just one variable, we don't need parens to separate the variable bindings from the body of the code. Just because you write in lisp doesn't mean you actually like parens ...


Unknown said...

Heya are using Wordpress for your blog platform? I'm new to the blog world but I'm trying to get started and set up my own. Do you need any coding expertise to make your own blog? Any help would be really appreciated! hotmail sign in email

Bongol said...

We find lots of learning after reading this very useful article . cara menggugurkan hamil - Vận tải Con thoi said...

Cảm ơn bạn đã chia sẻ, nếu cần chành xe đi đà nẵng thì a/c liên hệ bên mình nhé. Hotline: 0903751981

er86uhxxuq said...

"Museum makes use of 3D printing to take fragile maquette by Thomas Hart Benton on tour through the States". "How expiring patents are ushering within the next technology of 3D printing". Copyright covers an expression in a tangible, mounted medium and often lasts for the lifetime of the author plus 70 years thereafter. If someone makes a statue, they could have a copyright mark on the appearance of that go cool towels statue, so if someone sees that statue, they cannot then distribute designs to print an similar or comparable statue. 3D fashions could be generated from 2D photos taken at a 3D photograph sales space. In 1974, David E. H. Jones laid out the idea of 3D printing in his regular column Ariadne within the journal New Scientist.