如何存储Monoidal List功能链的数据? [英] How to store data of a functional chain of Monoidal List?

查看:182
本文介绍了如何存储Monoidal List功能链的数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我先前问题的高级主题:

This is an advanced topic of my prior question here:

如何存储功能链的数据?

简短的想法是

以下简单函数:

const L = a => L;

表格

L
L(1)
L(1)(2)
...

这似乎形成一个列表,但实际数据根本没有存储,所以如果需要存储[1,2]这样的数据,那么最聪明的做法是什么?任务完成了吗?

This seems to form a list but the actual data is not stored at all, so if it's required to store the data such as [1,2], what is the smartest practice to have the task done?

其中一个突出的想法来自@ user633183,我将其标记为已接受的答案(请参阅问题链接),另一个版本的curried函数也是由@MatíasFidemraizer提供。

One of the prominent ideas is from @user633183 which I marked as an accepted answer(see the Question link), and another version of the curried function is also provided by @Matías Fidemraizer .

所以这里是:

const L = a => {
  const m = list => x => !x
    ? list
    : m([...list, x]);
  return m([])(a);
}; 

const list1 = (L)(1)(2)(3); //lazy : no data evaluation here
const list2 = (L)(4)(5)(6);

console.log(list1()) // now evaluated by the tail ()
console.log(list2())  

我真正喜欢的是懒惰评价。

What I really like is it turns out lazy evaluation.

虽然给定的方法满足我提到的,但是这个函数已经失去了外部结构或者我必须使用mentiion:

Although the given approach satisfies what I mentioned, this function has lost the outer structure or I must mentiion:

 const L = a => L;

形成一个列表,从根本上给我们一个 identity element <的.org / wiki / Algebraic_structurerel =nofollow noreferrer>代数结构 / a>,可能还有 Monoid Magma

which forms list and more fundamentally gives us an algebraic structure of identity element, potentially along with Monoid or Magma.

Monoids和身份最简单的例子之一是数字和字符串 [数组] $ j

One of the easiest examples of Monoids and identity is number and "Strings" and [Array] in JavaScript.

0 + a === a === a + 0
1 * a === a === a * 1

在字符串中,空的quoate 是标识元素。

In Strings, the empty quoate "" is the identity element.

  "" + "Hello world" === "Hello world" === "Hello world" + ""

同样适用于 [数组]

同样适用于 L

(L)(a) === (a) === (a)(L)

const L = a => L;

const a = L(5); // number is wrapped or "lift" to Type:L
                // Similarity of String and Array
                // "5"  [5]

//left identity
console.log(
  (L)(a) === (a)    //true 
);
 
//right identity
console.log(
  (a) === (a)(L)    //true
); 

以及明显的身份不变性:

and the obvious identity immutability:

const L = a => L;
 
console.log(
  (L)(L) === (L)    //true
); 
console.log(
  (L)(L)(L) === (L)    //true
); 
console.log(
  (L)(L)(L)(L) === (L)    //true
); 

以下内容:

const L = a => L;

const a = (L)(1)(2)(3);
const b = (L)(1)(L)(2)(3)(L);

 
console.log(
   (a) === (b)    //true 
);
 

实现的最聪明或最优雅的方式(非常实用且无突变(无 Array.push )) L 满足3个要求:

一个简单的函数:

const L = a => L;

已经满足我们已经看到的身份法。

already satisfies the identity law as we already have seen.

虽然 L 符合身份法,但没有访问列出/累积数据的方法。

Although L satisfies the identity law, there is no method to access to the listed/accumulated data.

(我在上一个问题中提供的答案提供了数据累积能力,但违反了身份法。)

(Answers provided in my previous question provide the data accumulation ability, but breaks the Identity law.)

懒惰评估似乎是正确的方法,因此提供更清晰的规范:

Lazy evaluation seems the correct approach, so providing a clearer specification:

const L = a => L; // needs to enhance to satisfy the requirements

const a = (L)(1)(2)(3);
const b = (L)(1)(L)(2)(3)(L);


console.log(
   (a) === (b)    //true 
);

console.log(
   (a).eval()    //[1, 2, 3]
);

console.log(
   (b).eval()    //[1, 2, 3]
);



要求3 - Monoid联合法



除了突出的识别结构外,Monoids还满足联想法

(a * b) * c === a * b * c === a * (b * c)

这只是意味着展平列表,换句话说,结构不包含嵌套列表。

This simply means "flatten the list", in other words, the structure does not contain nested lists.

[a,[b,c]] 不好。

示例:

const L = a => L; // needs to enhance to satisfy the requirements

const a = (L)(1)(2);
const b = (L)(3)(4);
const c = (L)(99);

const ab = (a)(b);
const bc = (b)(c);
const abc1 = (ab)(c);
const abc2 = (a)(bc);

console.log(
   abc1 === abc2  // true for Associative
);

console.log(
   (ab).eval()    //[1, 2, 3, 4]
);

console.log(
   (abc1).eval()   //[1, 2, 3, 4, 99]
);
console.log(
   (abc2).eval()   //[1, 2, 3, 4, 99]
);

这是实现3个要求的全部 L 作为一个幺半群。

That is all for 3 requirements to implement L as a monoid.

这对函数式编程来说是一个很大的挑战,实际上我自己尝试了一段时间,但问过前面的问题,这是非常好的练习分享我自己的挑战并听取人们的意见并阅读优雅的代码。

This is a great challenge for functional programming to me, and actually I tried by myself for a while, but asking the previous questions, it's very good practice to share my own challenge and hear the people and read their elegant code.

谢谢。

推荐答案

更新



以下是@ user633183引入的标记技术的库存版本。

Update

Here's a curried version of tag technique introduced by @user633183.

我更换了名称标签/是要输入内容。

I replaced the name tag/is to type stuff.

  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

typeOf <进行重构/ code>和 isType

如果(EVAL)被应用,整个评估过程被调用。

If (EVAL) is applied, the whole evaluation process is called.

因为它是一个幺半群,我将使用 M L

Since it's a monoid, I will use M not L.

使用 JSON.stringfy验证一些帮助函数

成功,

Monoids


  • 身份

  • Associative

列表


  • 累积

  • 懒惰评估

规范分为每个简洁函数,它们的组成如下:

specifications are divided into every concise function, and the composition of them is the code below:

  //Debug/validation use-----------------
  const equalJSON = a => b => JSON.stringify(a) === JSON.stringify(b);
  const logEq = a => b => {
    const result = equalJSON(a)(b);
    console.log(result);
    return result;
  };   //Debug/validation use-----------------


const isPrimitive = val => (val !== Object(val));

const toObj = p => !isPrimitive(p)
  ? p //object return
  : (typeof (p) === "boolean")
    ? new Boolean(p)
    : (typeof (p) === "number")
      ? new Number(p)
      : (typeof (p) === "string")
        ? new String(p)
        : p; //Symbol()


const selfAware = i => i[i] = i;
const isAware = i => (i[i] === i);

const I = i => (i === I) || (i == null)
  ? i
  : selfAware(toObj(i));

const amI = i => (i === I)
  ? true
  : (i == null)
    ? false
    : isAware(i);







const flatArray = (arr1) => arr1
  .reduce((acc, val) => Array.isArray(val)
    ? [...acc, ...flatArray(val)]
    : [...acc, val], []);

const flatList = ls => ls.map(l => amI(l)
  ? flatList(l(EVAL)) : l);

//evaluation to be associative operation: flatten list

const evaluation = list => associative(list);
const associative = list => flatArray(flatList(list));

const identityType = f => { //left&right identity
  const T = x => (x === T)
    ? T //left identity
    : f(x);
  return I(T); //right identity
};


const EVAL = Symbol();
const M = identityType( //Monoid type constructer
  a => { // list accumulation recursion
    const m = list => x => (x === EVAL)
      ? evaluation(list) // list() triggered to eval
      : I(m([...list, x])); // data x joint
    return m([])(a); //initial empty [] list and data a
  }
);

//Validation================

console.log(
  (M) //[Function: M]
);
console.log(
  (M)(M)
);
console.log(
  (M)(M)(M)
);
console.log(
  (M)(M)(M)(M)
);
logEq(
  (M)(M)
)(
  (M)
); //true

logEq(
  (M)(M)(M)
)(
  (M)
); //true

logEq(
  (M)(M)(M)(M)
)(
  (M)
); //true


console.log(
  (M)(EVAL) // []
);
console.log(
  (M)(M)(EVAL) //[]
);
console.log(
  (M)(M)(M)(EVAL) //[]
);
console.log(
  (M)(M)(M)(M)(EVAL) //[]
);
const m = M(5);

//left identity
logEq(
  (M)(m)
)(
  (m)
); //true

//right identity
logEq(
  (m)
)(
  (m)(M)
); //true


console.log(
  (M)(1)(2)(3) //{ [Function: n] isList: true }
);

logEq(
  (M)(1)(2)(3)
)(
  (M)(99)
); //true without evaluation

logEq(
  (M)(1)(2)(3)(EVAL)
)(
  (M)(99)(EVAL)
); //false with evaluation

console.log(
  (M)(1)(2)(3)(EVAL) //[1, 2, 3]
);
console.log(
  (M)(1)(M)(2)(3)(M)(EVAL) //[1, 2, 3]
);

logEq(
  (M)(1)(2)(3)(EVAL) //[1,2,3]
)(
  (M)(1)(M)(2)(3)(M)(EVAL) //[1,2,3]
); //true

console.log("associative----------------");
const a = (M)(1)(2)(3);
const b = (M)(4)(5)(6);
const c = (M)(99);

const ab = (a)(b);
const bc = (b)(c);
const abc1 = (ab)(c);
const abc2 = (a)(bc);
console.log("no eval yet----------------");
console.log(
  (ab)(EVAL) //[1, 2, 3, 4, 5, 6]
);
console.log(
  (bc)(EVAL) //[4, 5, 6, 99]
);
console.log(
  (abc1)(EVAL) //[1, 2, 3, 4, 5, 6, 99]
);
console.log(
  (abc2)(EVAL) //[1, 2, 3, 4, 5, 6, 99]
);
logEq(
  (abc1)(EVAL)
)(
  (abc2)(EVAL)
); // true for Associative law

这篇关于如何存储Monoidal List功能链的数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆