Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
219 views
in Technique[技术] by (71.8m points)

javascript - How to store data of a functional chain of Monoidal List?

This is an advanced topic of my prior question here:

How to store data of a functional chain?

The brief idea is

A simple function below:

const L = a => L;

forms

L
L(1)
L(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?

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 .

So here goes:

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())  
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your data type is inconsistent!

So, you want to create a monoid. Consider the structure of a monoid:

class Monoid m where
    empty :: m           -- identity element
    (<*>) :: m -> m -> m -- binary operation

-- It satisfies the following laws:

empty <*> x = x = x <*> empty     -- identity law
(x <*> y) <*> z = x <*> (y <*> z) -- associativity law

Now, consider the structure of your data type:

(L)(a) = (a) = (a)(L)     // identity law
((a)(b))(c) = (a)((b)(c)) // associativity law

Hence, according to you the identity element is L and the binary operation is function application. However:

(L)(1)                  // This is supposed to be a valid expression.
(L)(1) != (1) != (1)(L) // But it breaks the identity law.

// (1)(L) is not even a valid expression. It throws an error. Therefore:

((L)(1))(L)                // This is supposed to be a valid expression.
((L)(1))(L) != (L)((1)(L)) // But it breaks the associativity law.

The problem is that you are conflating the binary operation with the reverse list constructor:

// First, you're using function application as a reverse cons (a.k.a. snoc):

// cons :: a -> [a] -> [a]
// snoc :: [a] -> a -> [a] -- arguments flipped

const xs = (L)(1)(2); // [1,2]
const ys = (L)(3)(4); // [3,4]

// Later, you're using function application as the binary operator (a.k.a. append):

// append :: [a] -> [a] -> [a]

const zs = (xs)(ys); // [1,2,3,4]

If you're using function application as snoc then you can't use it for append as well:

snoc   :: [a] ->  a  -> [a]
append :: [a] -> [a] -> [a]

Notice that the types don't match, but even if they did you still don't want one operation to do two things.

What you want are difference lists.

A difference list is a function that takes a list and prepends another list to it. For example:

const concat = xs => ys => xs.concat(ys); // This creates a difference list.

const f = concat([1,2,3]); // This is a difference list.

console.log(f([])); // You can get its value by applying it to the empty array.

console.log(f([4,5,6])); // You can also apply it to any other array.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...