読者です 読者をやめる 読者になる 読者になる

SICP的な状態を共有する複数のクロージャをJavaScriptでどう書くか

某展示会の学術系ブースで、このようなSICP的な状態を共有する複数のクロージャJavaScriptで書きたいわけだが、

"use strict"

var [getVal, setVal] = (function () {
    var v
    return [function () {
        return v
    }, function (new_v) {
        v = new_v
    }]
})()

setVal(42)
console.log(getVal())

JavaScriptの動作確認には node を使っています)

流石にこのように無名関数をバリバリ書こうとは思わないだろうので、それを解消する提案、というようなものを見ました。

提案されていた手法は、特別な記法でこの例の v のような変数をマークアップし、プリプロセッサのようなもので、もっとプレーンな書き方をしたJavaScriptから、このようなコードに変換する、というものでしたが、それについてはこの記事の本題ではありません。

Pythonで書くと、こんな感じになるでしょうか。

#! /usr/local/bin/python3

def mk_val():
    v = None
    def get_val():
        return v
    def set_val(new_v):
        nonlocal v
        v = new_v
    return get_val, set_val

get_val, set_val = mk_val()

set_val(42)
print(get_val())

Pythonではlamdaがあえてかなり使いにくく設計されており、このように明示的に手続きに名前を付けるスタイルになります*1

このPythonの場合を踏まえて、最初の例を考えてみると、こういうスタイルが出てきます。

"use strict"

function mkVal() {
    var v
    function getVal() {
        return v
    }
    function setVal(new_v) {
        v = new_v
    }
    return [getVal, setVal]
}

var [getVal, setVal] = mkVal()

setVal(42)
console.log(getVal())

SICP中でも、どうしてもlambdaが必要な場合は使っていますが、それよりもネストしたdefineのほうが自然な場合はそちらが多用されているような気がします。どうでしょうか?

*1:Python3以降ならこのようにnonlocal文でこのような変数の書き換えを共有できますが、2以前はJavaでやるようにboxingが必要で、そもそもこういうのはPythonではあまりencourageされていない、と言えばそういうことなのかもしれませんが。