My last question here: How to store data of a functional chain of Monoidal List?
had many great responses and one of them suggested to implement some sort of type structure in JavaScript:
const TYPE = Symbol();
const typeOf = t => x => x == null
? x
: Object.assign(x, {
[TYPE]: t
});
const isType = t => x => x == null
? false
: x[TYPE] === t;
const Foo = x => typeOf(Foo)(x);
console.log(
isType(Foo)(1) // false
, isType(Foo)([]) // false
, isType(Foo)({}) // false
, isType(Foo)(x => x) // false
, isType(Foo)(true) // false
, isType(Foo)(undefined) // false
, isType(Foo)(null) // false
);
console.log(
isType(Foo)(Foo(1)) // true
, isType(Foo)(Foo([])) // true
, isType(Foo)(Foo({})) // true
, isType(Foo)(Foo(x => x)) // true
, isType(Foo)(Foo(true)) // true
, isType(Foo)(Foo(undefined)) // false
, isType(Foo)(Foo(null)) // false
);
console.log(Foo(1) + Foo(2)); //3
My last question here: How to store data of a functional chain of Monoidal List?
had many great responses and one of them suggested to implement some sort of type structure in JavaScript:
const TYPE = Symbol();
const typeOf = t => x => x == null
? x
: Object.assign(x, {
[TYPE]: t
});
const isType = t => x => x == null
? false
: x[TYPE] === t;
const Foo = x => typeOf(Foo)(x);
console.log(
isType(Foo)(1) // false
, isType(Foo)([]) // false
, isType(Foo)({}) // false
, isType(Foo)(x => x) // false
, isType(Foo)(true) // false
, isType(Foo)(undefined) // false
, isType(Foo)(null) // false
);
console.log(
isType(Foo)(Foo(1)) // true
, isType(Foo)(Foo([])) // true
, isType(Foo)(Foo({})) // true
, isType(Foo)(Foo(x => x)) // true
, isType(Foo)(Foo(true)) // true
, isType(Foo)(Foo(undefined)) // false
, isType(Foo)(Foo(null)) // false
);
console.log(Foo(1) + Foo(2)); //3
While I thought this is a great idea, another member suggests this is inconsistent since Object.assign is a mutable operation and it should not be allowed in Functional Programming context.
In response, there is another idea to use Proxy instead, so I have tried to implement the similar system by myself.
The result is unfortunately very poor since Proxy
seems only to accept Object.
Works as the example
var target = {};
var p = new Proxy(target, {});
p.a = 37; // operation forwarded to the target
console.log(target.a); // 37. The operation has been properly forwarded
"Uncaught TypeError: Cannot create proxy with a non-object as target or handler"
var target = 5;
var p = new Proxy(target, {});
p.a = 37; // operation forwarded to the target
console.log(target.a); // 37. The operation has been properly forwarded
I also considered to take advantage of Object.create, but does not work in similar manner of Proxy
.
Basically, I recognise this is a challenge to implement Inheritance (object-oriented programming) in functional programming with dynamic typing/ duck typing and reflection.
Therefore, I really want to make this implementation work in ES6 Proxy context.
Any great ideas? Thanks.
Share Improve this question edited Jun 21, 2022 at 12:25 Morten 4,6077 gold badges31 silver badges31 bronze badges asked Jul 14, 2018 at 21:29 user6440264user6440264 3-
3
I think you have misunderstood what Proxy is. The whole point it to have functions in the second object to handle the "proxying" and of course the first argument has to be an object. Without it it will just pass whatever to the target and it will be mutated just as before. You can pass a new object as the first argument to
Object.assign
and then it will not mutate the original object. eg.Object.assign({}, x, { [TYPE]: t })
. In ES2018 you can do{ ...x, [TYPE]: t }
. – Sylwester Commented Jul 14, 2018 at 21:58 -
@Sylwester wow, this is not documented at all, and
{ ...x, ...y}
notation works in the current node.js enviroment. Thanks a lot ! – user6440264 Commented Jul 14, 2018 at 22:32 - @bayesian-study - Seems fairly well-documented to me. In the spec (here, which takes you here, which says "1. If Type(target) is not Object, throw a TypeError exception."), on MDN "target - A target object (can be any sort of object, including a native array, a function or even another proxy) to wrap with Proxy." – T.J. Crowder Commented Jul 15, 2018 at 8:10
1 Answer
Reset to default 5It turns out,
- Symbol()
- Object.assign()
- Proxy
all of them are not necessary to implement Reflection (puter programming) at least for this topic.
See my code below:
const selfAware = i => i[i] = i;
const isAware = i => (i[i] === i);
const I = i => (i === I) || (i == null)
? i
: selfAware(Object(i));
const amI = i => (i === I)
? true
: (i == null)
? false
: isAware(i);
const ss = I(6);
console.log(ss);
console.log(ss[ss]);
//self-similarity
console.log(ss[ss][ss]);
const obj1 = {
a: 2
};
const obj2 = I(obj1);
console.log(obj1);
console.log(obj2);
console.log(
I("Hello world!").toString() //Yes, it works!
);
console.log(I(1) + I(2)); //3
console.log(
(I) //[Function: I]
);
console.log(
(I)(I) //[Function: I]
);
console.log(
(I)(I)(I) //[Function: I]
);
console.log(
(I)(I)(I)(I) //[Function: I]
);
console.log("============================");
console.log(
amI(I) //true
, amI(1) // false
, amI([]) // false
, amI({}) // false
, amI(x => x) // false
, amI(true) // false
, amI(false) // false
, amI(undefined) // false
, amI(null) // false
);
console.log(
amI(I(I)) // true
, amI(I(1)) // true
, amI(I([])) // true
, amI(I({})) // true
, amI(I(x => x)) // true
, amI(I(true)) // true
, amI(I(false)) // true
, amI(I(undefined)) // false
, amI(I(null)) // false
);