如何存储功能链的数据?
How to store data of a functional chain?
下面是一个简单的函数:
const L = a => L;
表格
L
L(1)
L(1)(2)
...
这看起来是一个列表,但实际上根本没有存储数据,所以如果需要存储数据,例如[1,2]
,最聪明的做法是什么?
const L = (a) => {
// do somthing
return L;
};
我更喜欢这种简洁的箭头函数风格,尽量不破坏外部结构。当然,我知道需要对外部结构进行一些修改,但我很好奇有什么可能,尤其是在函数式风格而不是 OO 中。
规范只是为了存放函数链的数据
有什么想法吗?谢谢。
最初最简单的方法是:
const L = (a) => {
L.val = a;
return L;
};
L.val = L;
可以做一些,但是没有数据积累。
{ [Function: L] val: [Circular] }
{ [Function: L] val: 1 }
{ [Function: L] val: 2 }
通知:
每个列表都应该独立进行累加。
L(3)(4)
将 return [3,4]
不会 [2,3,3,4]
预先积累另一个列表。
进阶话题!
How to store data of a functional chain of Monoidal List?
感谢@Adelin 的善良和技巧,我想出了理想的方法。
const L = (a) => {
const m = a => (m.list ? m.list : m.list = [])
.push(a) && m; //use `concat` and refactor needed instead of `push` that is not immutable
return m(a); // Object construction!
};
console.log(L);
console.log(L(2));
console.log(L(1)(2)(3))
一些输出:
{ [Function: m] list: [ 2 ] }
{ [Function: m] list: [ 1, 2, 3 ] }
这是多么优雅啊。
再次将 95% 的贡献归功于@Adelin。
我的感谢。
这是我能达到的最接近的结果。
const L = a => b => {
if (!Array.isArray(a)) a = [a];
a.push(b);
return a;
}
x = L(L(L(3)(5))(5))(3)
console.log(x); // [3, 5, 5, 3]
希望你喜欢方括号!
函数柯里化和可变参数实际上不能一起工作。一旦您意识到以下两个表达式不兼容,这个限制就会变得很明显
L (1) -> [ 1 ]
L (1) (2) -> [ 1, 2 ]
L (1)
returns 上面的一个列表,但是在第二个表达式中我们期望 L (1)
是一个我们可以应用于 2
的函数。 L (1)
可以是一个列表 或者 它可以是一个生成列表的函数;两者不能同时存在。
这就是为什么其他人提出 .list
之类的东西来获取实际值的原因。您可以这样做,但要知道没有必要使用对象属性或依赖突变。您可以使用您选择的任何信号
const L = (x, acc = []) =>
x === undefined
? acc
: y => L (y, [...acc, x])
console.log
( L () // []
, L (1) () // [ 1 ]
, L (1) (2) () // [ 1, 2 ]
, L (1) (2) (3) () // [ 1, 2, 3 ]
)
我们可以使用辅助辅助函数抽象出可选参数。这种技术类似于您找到的解决方案,但在这里我们避免了笨拙的函数属性赋值,而是使用简单的变量和非变异操作
const L = init =>
{ const loop = (acc, x) =>
x === undefined
? acc
: y => loop ([...acc, x], y)
return loop ([], init)
}
console.log
( L () // []
, L (1) () // [ 1 ]
, L (1) (2) () // [ 1, 2 ]
, L (1) (2) (3) () // [ 1, 2, 3 ]
)
或者看你的要求有点灵活,用更灵活的编码来发挥创意
const List = x =>
k => k (x)
const append = x => xs =>
List ([ ...xs, x ])
const prepend = x => xs =>
List ([ x, ...xs ])
List ([]) (append (1)) (console.log)
// [ 1 ]
List ([ 2, 3 ]) (append (4)) (append (5)) (prepend (1)) (console.log)
// [ 1, 2, 3, 4, 5 ]
将 JavaScript 的宽松语法推向极限很有趣,但最好使用扩展参数定义可变参数函数
const L = (...values) =>
values
console.log
( L () // []
, L (1) // [ 1 ]
, L (1, 2) // [ 1, 2 ]
, L (1, 2, 3) // [ 1, 2, 3 ]
)
一个不那么做作的例子演示了一个更好的用例
const max = (x, ...ys) =>
ys.length === 0
? x
: max2 (x, max (...ys))
const max2 = (x, y) =>
x > y ? x : y
console.log
( max (1, 5, 3) // 5
, max (5, 2, 9, 7) // 9
, max (4) // 4
, max () // undefined
)
可能以下方法有点疯狂,但它有效:
const L = x => {
const L_ = xs => x => typeof x == 'undefined' ? xs : L_ ([...xs, x])
return L_ ([]) (x)
}
const l1 = L (0) (2) (55) (383) (91) (6) ()
const l2 = L (22) (985) (82) (12) (1034) ()
console.log(l1)
console.log(l2)
基本上,外部 L
接收要添加到 列表 中的第一个元素。随后的调用将递归内部 L_
连接先前的 xs
加上新的 x
直到 x
evals falsy * undefined
请注意内部 L_
是如何部分应用的,因此下一次调用只需要一个新的 x
!
另一种方法:Writer monad
还有另一种可能的方法使用 Writer monad。请注意,为了示例的缘故,此示例实现已被简化:
/////
const Writer = acc => {
return { acc }
}
const of = x => Writer ([x])
const map = f => m => Writer ([...m.acc, f (m.acc)])
const read = m => m.acc
/////
const pipe = xs => x => xs.reduce ((o, f) => f (o), x)
const K = x => () => x
const list = pipe ([
of,
map (K (1)),
map (K (38)),
map (K (1781)),
read
]) (123)
const list2 = pipe ([
of,
map (x => x * 2),
map (x => x + 4),
map (x => x * 10),
read
]) (123)
console.log ('#1 list:')
console.log (list)
console.log ('#2 list:')
console.log (list2)
* 它不应该是 falsy 因为 0
评估为 false
所以 L
不支持它作为可能的值。
下面是一个简单的函数:
const L = a => L;
表格
L
L(1)
L(1)(2)
...
这看起来是一个列表,但实际上根本没有存储数据,所以如果需要存储数据,例如[1,2]
,最聪明的做法是什么?
const L = (a) => {
// do somthing
return L;
};
我更喜欢这种简洁的箭头函数风格,尽量不破坏外部结构。当然,我知道需要对外部结构进行一些修改,但我很好奇有什么可能,尤其是在函数式风格而不是 OO 中。
规范只是为了存放函数链的数据
有什么想法吗?谢谢。
最初最简单的方法是:
const L = (a) => {
L.val = a;
return L;
};
L.val = L;
可以做一些,但是没有数据积累。
{ [Function: L] val: [Circular] }
{ [Function: L] val: 1 }
{ [Function: L] val: 2 }
通知:
每个列表都应该独立进行累加。
L(3)(4)
将 return [3,4]
不会 [2,3,3,4]
预先积累另一个列表。
进阶话题!
How to store data of a functional chain of Monoidal List?
感谢@Adelin 的善良和技巧,我想出了理想的方法。
const L = (a) => {
const m = a => (m.list ? m.list : m.list = [])
.push(a) && m; //use `concat` and refactor needed instead of `push` that is not immutable
return m(a); // Object construction!
};
console.log(L);
console.log(L(2));
console.log(L(1)(2)(3))
一些输出:
{ [Function: m] list: [ 2 ] }
{ [Function: m] list: [ 1, 2, 3 ] }
这是多么优雅啊。
再次将 95% 的贡献归功于@Adelin。 我的感谢。
这是我能达到的最接近的结果。
const L = a => b => {
if (!Array.isArray(a)) a = [a];
a.push(b);
return a;
}
x = L(L(L(3)(5))(5))(3)
console.log(x); // [3, 5, 5, 3]
希望你喜欢方括号!
函数柯里化和可变参数实际上不能一起工作。一旦您意识到以下两个表达式不兼容,这个限制就会变得很明显
L (1) -> [ 1 ]
L (1) (2) -> [ 1, 2 ]
L (1)
returns 上面的一个列表,但是在第二个表达式中我们期望 L (1)
是一个我们可以应用于 2
的函数。 L (1)
可以是一个列表 或者 它可以是一个生成列表的函数;两者不能同时存在。
这就是为什么其他人提出 .list
之类的东西来获取实际值的原因。您可以这样做,但要知道没有必要使用对象属性或依赖突变。您可以使用您选择的任何信号
const L = (x, acc = []) =>
x === undefined
? acc
: y => L (y, [...acc, x])
console.log
( L () // []
, L (1) () // [ 1 ]
, L (1) (2) () // [ 1, 2 ]
, L (1) (2) (3) () // [ 1, 2, 3 ]
)
我们可以使用辅助辅助函数抽象出可选参数。这种技术类似于您找到的解决方案,但在这里我们避免了笨拙的函数属性赋值,而是使用简单的变量和非变异操作
const L = init =>
{ const loop = (acc, x) =>
x === undefined
? acc
: y => loop ([...acc, x], y)
return loop ([], init)
}
console.log
( L () // []
, L (1) () // [ 1 ]
, L (1) (2) () // [ 1, 2 ]
, L (1) (2) (3) () // [ 1, 2, 3 ]
)
或者看你的要求有点灵活,用更灵活的编码来发挥创意
const List = x =>
k => k (x)
const append = x => xs =>
List ([ ...xs, x ])
const prepend = x => xs =>
List ([ x, ...xs ])
List ([]) (append (1)) (console.log)
// [ 1 ]
List ([ 2, 3 ]) (append (4)) (append (5)) (prepend (1)) (console.log)
// [ 1, 2, 3, 4, 5 ]
将 JavaScript 的宽松语法推向极限很有趣,但最好使用扩展参数定义可变参数函数
const L = (...values) =>
values
console.log
( L () // []
, L (1) // [ 1 ]
, L (1, 2) // [ 1, 2 ]
, L (1, 2, 3) // [ 1, 2, 3 ]
)
一个不那么做作的例子演示了一个更好的用例
const max = (x, ...ys) =>
ys.length === 0
? x
: max2 (x, max (...ys))
const max2 = (x, y) =>
x > y ? x : y
console.log
( max (1, 5, 3) // 5
, max (5, 2, 9, 7) // 9
, max (4) // 4
, max () // undefined
)
可能以下方法有点疯狂,但它有效:
const L = x => {
const L_ = xs => x => typeof x == 'undefined' ? xs : L_ ([...xs, x])
return L_ ([]) (x)
}
const l1 = L (0) (2) (55) (383) (91) (6) ()
const l2 = L (22) (985) (82) (12) (1034) ()
console.log(l1)
console.log(l2)
基本上,外部 L
接收要添加到 列表 中的第一个元素。随后的调用将递归内部 L_
连接先前的 xs
加上新的 x
直到 x
evals falsy * undefined
请注意内部 L_
是如何部分应用的,因此下一次调用只需要一个新的 x
!
另一种方法:Writer monad
还有另一种可能的方法使用 Writer monad。请注意,为了示例的缘故,此示例实现已被简化:
/////
const Writer = acc => {
return { acc }
}
const of = x => Writer ([x])
const map = f => m => Writer ([...m.acc, f (m.acc)])
const read = m => m.acc
/////
const pipe = xs => x => xs.reduce ((o, f) => f (o), x)
const K = x => () => x
const list = pipe ([
of,
map (K (1)),
map (K (38)),
map (K (1781)),
read
]) (123)
const list2 = pipe ([
of,
map (x => x * 2),
map (x => x + 4),
map (x => x * 10),
read
]) (123)
console.log ('#1 list:')
console.log (list)
console.log ('#2 list:')
console.log (list2)
* 它不应该是 falsy 因为 0
评估为 false
所以 L
不支持它作为可能的值。