admin管理员组

文章数量:1356319

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
Add a ment  | 

1 Answer 1

Reset to default 5

It 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
);

本文标签: