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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…