0

我想知道是否可以在 Javascript 中拥有相互递归的对象,如果可以,如何实现?

目标:

我想要三个对象:

  1. 一个表示Boolean具有两个值的类型,True并且False
  2. 代表类型True对象的一个Boolean
  3. 代表类型False对象的一个Boolean

诀窍是我想问True对象它的类型,我应该取回Boolean对象,我想问一个Boolean对象它的值,我应该取回 2 个对象:True对象和False对象。

但它应该完全是相互递归的,因为我得到了这样的东西(尽管它不一定必须完全像这样):

True 
// {name : "True", type : [Object object]}

False
// {name : "False", type : [Object object]}

Boolean 
// {name : "Boolean", values : [Object object]}

Boolean.values  
// {True: [Object object], False: [Object object]}

True.type
// {name : "Boolean", values : [Object object]}

False.type
// {name : "Boolean", values : [Object object]}

Boolean.values.True 
// {name : "True", type: [Object object]}

Boolean.values.True.type 
// {name : "Boolean", values : [Object object]}

Boolean.values.True.type.values 
// {True : [Object object], False: [Object object]}

等等...

如果有帮助,它们应该满足以下属性:

Boolean === Boolean.values.True.type 
Boolean === Boolean.values.True.type.values.True.type

True === Boolean.values.True
True === True.type.values.True.type.values.True.type.values.True

False === Boolean.values.False
False === True.type.values.False

并且这样做的能力应该是无限的

笔记

这些可以是函数而不是对象。呼叫不必完全像这样。

4

2 回答 2

2

干得好:

//Define the top level objects but avoid recursion
var True = {};
var False = {};
var Boolean = {
    values: {
        True: True,
        False: False
    }
};

//Create the recursion
True.type = Boolean;
False.type = Boolean;
于 2014-11-14T17:52:09.790 回答
1

这很简单:

var Boolean = {
    name: "Boolean",
    values: {
        True: {
            name: "True"
        },
        False: {
            name: "False"
        }
    }
};

var True = Boolean.values.True;

var False = Boolean.values.False;

True.type = Boolean;

False.type = Boolean;

您是否正在尝试创建代数数据类型


编辑:这就是我创建代数数据类型的方式:

function data(constructors) {
    var factory = function (constructor) {
        this.constructor = constructor || this;
    };

    var type = factory.prototype = {};

    for (var name in constructors) {
        var fields = constructors[name];

        if (fields) {
            var body = ["    var data = new " + name + "(arguments.callee);"];
            var length = fields.length;
            var params = [];

            for (var i = 0; i < length; i++) {
                var param = "arg" + i;
                body.push("    data." + fields[i] + " = " + param + ";");
                params.push(param);
            }

            body.unshift("return function (" + params.join(", ") + ") {");
            body.push("    return data;", "};");

            type[name] = Function(name, body.join("\n"))(factory);
        } else type[name] = new factory;
    }

    return type;
}

使用 data 函数,我们可以定义代数数据类型如下:

var Boolean = data({
    True: null,
    False: null
});

var True = Boolean.True;
var False = Boolean.False;

var List = data({
    Nil: null,
    Cons: ["head", "tail"]
});

var Nil = List.Nil;
var Cons = List.Cons;

它具有以下不变量:

Object.getPrototypeOf(True) === Boolean;
Object.getPrototypeOf(False) === Boolean;

Object.getPrototypeOf(Nil) === List;
Object.getPrototypeOf(Cons(0, Nil)) === List;

True.constructor === True;
False.constructor === False;

Nil.constructor === Nil;
Cons(0, Nil).constructor === Cons;

使用它,您可以创建纯函数,如下所示:

List.map = function (f) {
    switch (this.constructor) {
    case Nil: return Nil;
    case Cons:
        var x = this.head;
        var xs = this.tail;
        return Cons(f(x), xs.map(f));
    }
};

function map(f, a) {
    return a.map(f);
}

您可以按如下方式使用它:

function toList(a) {
    var list = Nil;
    for (var i = a.length - 1; i >= 0; i--) list = Cons(a[i], list);
    return list;
}

var xs = toList([1,2,3]);

var ys = map(function (a) {
    return a * 2;
}, xs);

希望有帮助。

于 2014-11-14T17:51:12.813 回答