- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是之后的顺序问题
How to store data of a functional chain of Monoidal List?
和
Extracting data from a function chain without arrays
在这里,我要表达我对我的问题的贡献者的敬意和赞赏,尤其是@Aadit M Shah和@ user633183的贡献
现在,打开这个问题来阐明Difference list和Church list之间的异同或关系
。
差异表
https://stackoverflow.com/a/51320041/6440264
difference list是获取列表并在其前面添加另一个列表的函数。例如:
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.
const id = x => x; // The identity element is just the id function.
const compose = (f, g) => x => f(g(x)); // The binary operation is composition.
compose(id, f) = f = compose(f, id); // identity law
compose(compose(f, g), h) = compose(f, compose(g, h)); // associativity law
class DList {
constructor(f) {
this.f = f;
this.id = this;
}
cons(x) {
return new DList(ys => this.f([x].concat(ys)));
}
concat(xs) {
return new DList(ys => this.f(xs.concat(ys)));
}
apply(xs) {
return this.f(xs);
}
}
const id = new DList(x => x);
const cons = x => new DList(ys => [x].concat(ys)); // Construct DList from value.
const concat = xs => new DList(ys => xs.concat(ys)); // Construct DList from array.
id . concat([1, 2, 3]) = concat([1, 2, 3]) = concat([1, 2, 3]) . id // identity law
concat([1, 2]) . cons(3) = cons(1) . concat([2, 3]) // associativity law
apply
方法来检索
DList
的值,如下所示:
class DList {
constructor(f) {
this.f = f;
this.id = this;
}
cons(x) {
return new DList(ys => this.f([x].concat(ys)));
}
concat(xs) {
return new DList(ys => this.f(xs.concat(ys)));
}
apply(xs) {
return this.f(xs);
}
}
const id = new DList(x => x);
const cons = x => new DList(ys => [x].concat(ys));
const concat = xs => new DList(ys => xs.concat(ys));
const identityLeft = id . concat([1, 2, 3]);
const identityRight = concat([1, 2, 3]) . id;
const associativityLeft = concat([1, 2]) . cons(3);
const associativityRight = cons(1) . concat([2, 3]);
console.log(identityLeft.apply([])); // [1,2,3]
console.log(identityRight.apply([])); // [1,2,3]
console.log(associativityLeft.apply([])); // [1,2,3]
console.log(associativityRight.apply([])); // [1,2,3]
foldr
看起来像
foldl
:
const L = g => function (x, a) {
switch (arguments.length) {
case 1: return L((f, a) => f(g(f, a), x));
case 2: return g(x, a);
}
};
const A = L((f, a) => a);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y, 0)); // 15
console.log(xs((x, y) => x * y, 1)); // 120
console.log(xs((a, x) => a.concat(x), [])); // [1,2,3,4,5]
g
是到目前为止累积的教会编码列表。最初,它是空列表。调用
g
会将其从右侧折叠。但是,我们也从右侧构建列表。因此,由于我们编写列表的方式,似乎我们正在构建列表并将其从左侧折叠。
const L = g => function (x, a) {
switch (arguments.length) {
case 1: return L([x].concat(g));
case 2: return g.reduceRight(x, a);
}
};
const A = L([]);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y, 0)); // 15
console.log(xs((x, y) => x * y, 1)); // 120
console.log(xs((a, x) => a.concat(x), [])); // [1,2,3,4,5]
reduceRight
向后折叠向后列表。因此,您似乎正在构建并向前折叠列表。
最佳答案
问题的根源
问题系列的根本原因是您坚持使用L(1)(2)(3)
语法构造列表。这种语法没有任何意义,人们已经一次又一次告诉您放弃使用这种语法:
user633183's answer您的第一个问题:
函数currying和可变参数不能真正一起使用。一旦意识到以下两个表达式不兼容,就会很明显地体现出这一限制
L (1) -> [ 1 ]
L (1) (2) -> [ 1, 2 ]
L (1)
上面返回一个列表,但是在第二个表达式中,我们希望
L (1)
是可以应用于
2
的函数。
L (1)
可以是列表,也可以是产生列表的函数;它不能同时存在。
autoCons
的类型–
autoCons (1) // "lambda (x,n) => isFunction (x) ...
autoCons (1) (2) // "lambda (x,n) => isFunction (x) ...
autoCons (1) (2) (3) // "lambda (x,n) => isFunction (x) ...
autoCons (1) (2) (3) (add, 0) // 6
autoCons
总是返回一个lambda,但是该lambda具有我们无法确定的类型-有时它返回另一个相同类型的lambda,有时返回一个完全不同的结果。在这种情况下,
6
autoCons
表达式与程序的其他部分混合和组合。如果删除此错误驱动器以创建可变参数的咖喱界面,则可以使
autoCons
可输入类型
L(1)(2)(3)
时,我认为没有任何理由使用
toList([1,2,3])
语法:
// null :: List a
// cons :: (a, List a) -> List a
const cons = (head, tail) => ({ head, tail });
// xs :: List Number
const xs = cons(1, cons(2, cons(3, null))); // You can either construct a list manually,
// toList :: Array a -> List a
const toList = array => array.length ? cons(array[0], toList(array.slice(1))) : null;
// ys :: List Number
const ys = toList([1,2,3]); // or you can construct a list from an array.
console.log(xs);
console.log(ys);
L(1)(2)(3)
语法的唯一原因是“有效地”将元素推到列表的末尾,那么您也可以使用普通列表来这样做。只需向后构建列表,然后使用
cons
在列表的开头放置一个新元素。
┌──────────────────────────── A List of a
│ ┌──────────────────────── is
| | ┌──────────────────── either null
| | | ┌───────────────── or
| | | | ┌───────────── cons of
| | | | | ┌───────── an a and
│ | | | | | ┌─── another List of a.
┌──┴─┐ │ ┌─┴┐ | ┌─┴┐ | ┌──┴─┐
List a = null | cons (a, List a)
null
表示。通过使用
cons
将新元素放在另一个(可能为空)元素列表之前,可以形成非空列表。我们将新元素放在原始列表的前面而不是它的后面,因为它更自然:
cons(1, cons(2, cons(3, null))); // This is easier to read and write.
snoc(snoc(snoc(null, 1), 2), 3); // This is more difficult to read and write.
snoc
并没有本质上的错误。我们可以将
List
定义为
List a = null | snoc (List a, a)
。但是,使用
cons
更自然。现在,根据是否使用
cons
或
snoc
定义
List
数据类型,将新元素放在列表前面或将新元素放在列表后面变得很昂贵:
in front of behind
┌─────────────┬─────────────┐
cons │ Inexpensive │ Expensive │
├─────────────┼─────────────┤
snoc │ Expensive │ Inexpensive │
└─────────────┴─────────────┘
as ++ bs ++ cs ++ ds
,在其中连接了四个列表。如果我们使用
cons
的
List
实现,则串联的最有效顺序是
as ++ (bs ++ (cs ++ ds))
,这就是Haskell中
(++)
运算符正确关联的原因。另一方面,如果我们使用
snoc
的
List
实现,则串联的最有效顺序是
((as ++ bs) ++ cs) ++ ds
。
cons
的
List
实现时,差异列表的形式为
(xs ++)
,其中
xs
是常规列表。我们可以使用常规函数组合(即
(as ++) . (bs ++) . (cs ++) . (ds ++)
)将它们向前组合。使用
snoc
的
List
实现时,差异列表的形式为
(++ xs)
,其中
xs
是常规列表。我们可以使用常规函数组合(即
(++ ds) . (++ cs) . (++ bs) . (++ as)
)向后组合它们。这是为什么更优选使用
cons
的
List
实现的另一个原因。
cons
的
List
实现还是
snoc
的
List
实现),术语
head
,
tail
,
init
和
head tail
│ ┌──────────┴─────────┐
cons(1, cons(2, cons(3, null)));
└──────┬─────┘ │
init last
init last
┌──────────┴─────────┐ │
snoc(snoc(snoc(null, 1), 2), 3);
│ └─┬─┘
head tail
last
是列表的第一个元素。
head
是列表的第一个元素以外的所有内容。
tail
是列表的最后一个元素以外的所有内容。
init
是列表的最后一个元素。
last
还是
cons
定义
snoc
数据类型,
List
和
head
或
tail
和
init
变得昂贵:
head / tail init / last
┌─────────────┬─────────────┐
cons │ Inexpensive │ Expensive │
├─────────────┼─────────────┤
snoc │ Expensive │ Inexpensive │
└─────────────┴─────────────┘
last
还是
cons
定义
snoc
数据类型,
List
或
foldl
都将成为尾递归:
foldl foldr
┌──────────────────────┬──────────────────────┐
cons │ Tail Recursion │ Structural Recursion │
├──────────────────────┼──────────────────────┤
snoc │ Structural Recursion │ Tail Recursion │
└──────────────────────┴──────────────────────┘
foldr
实现无限向前扩展(即
cons
),而
cons(1, cons(2, cons(3, ....)))
实现无限向前扩展(即
snoc
)。与
snoc(snoc(snoc(...., 1), 2), 3)
相比更喜欢
cons
的另一个原因。
snoc
,并使用
xs = cons(1, cons(2, cons(3, null)))
折叠它:
cons func
/ \ / \
1 cons 1 func
/ \ -> foldr(func, init, xs) -> / \
2 cons 2 func
/ \ / \
3 null 3 init
foldr
减少列表时,实际上是用
foldr
替换每个
cons
,并且用
func
替换
null
。这样,您可以通过折叠第一个列表,将
init
替换为
cons
,用第二个列表
cons
替换
null
来追加两个列表:
cons cons
/ \ / \
1 cons 1 cons
/ \ -> foldr(cons, ys, xs) -> / \
2 cons 2 cons
/ \ / \
3 null 3 cons
/ \
4 cons
/ \
5 cons
/ \
6 null
cons func
/ \ / \
1 cons 1 func
/ \ -> foldr1(func, xs) -> / \
2 cons 2 func
/ \ /
3 null 3
ys = cons(4, cons(5, cons(6, null)))
可以找到列表的总和而不提供初始值(即
foldr1
),但是如何在不借助
witchcraft的情况下重建相同的列表呢?如果您愿意提供初始值,则可以优雅地编写
foldr1(plus, xs)
。否则,除非您违反了函数式编程的原理,并使用副作用从
foldr(cons, null, xs)
自身内部人为地提供初始值,否则不可能这样做。无论哪种方式,无论是通过显式指定初始值还是通过将列表的最后一个元素作为
func
中的特例处理,您都将提供初始值。
func
包中的
foldr
函数。
Data.DList
语法不正确,因此只能向后构建列表(即
L(1)(2)(3)
)。因此,如果要“向前”折叠列表,则必须使用
L(1)(2)(3) = cons(3, cons(2, cons(1, null)))
而不是
foldr
。请注意,如果我们使用
foldl
而不是
snoc
,那么它实际上是转发的(即
cons
)。这是因为
L(1)(2)(3) = snoc(snoc(snoc(null, 1), 2), 3)
只是
snoc
且参数已翻转。因此,
cons
的
foldr
等同于
cons
的
foldl
,反之亦然,这是user633183注意到的。
snoc
用于
foldl
,但是为此,由于列表是向后构建的,因此我不得不以某种方式反转该列表。这就是延续的目的,以反转列表。直到后来我才意识到我根本不需要撤消这份清单。我可以简单地使用
cons
而不是
foldr
。
foldl
,二进制运算为
null
。请注意
append = (xs, ys) => foldr(cons, ys, xs)
(左标识)和
foldr(cons, null, xs) = xs
(右标识)。此外,
foldr(cons, ys, null) = ys
等效于
foldr(cons, zs, foldr(cons, ys, xs))
(关联性)。
foldr(cons, foldr(cons, zs, ys), xs)
数据类型被实现为差异列表,则nil是标识函数。否则,那是另一回事。尽管如此,nil始终是列表的标识元素。
List
。您必须提供初始值以追加两个列表。您可以通过显式地提供列表的第一个元素(使用
append
时)或最后一个元素(使用
foldl
时)来人工提供初始值(从而打破了功能编程)。
关于javascript - 使用右折和差异列表对列表进行教堂编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51485931/
如标题所示,ans_list是一个答案列表,ans_index是一个数字(答案在词汇表中的索引,但与atm无关) 这里生成的 tree.anslist 是什么? (例如,仅针对第一个),忽略迭代。 f
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。 这与 How do I “flatte
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将带有一个元素的东西拿走。 这与 How do I “flatte
这个问题已经有答案了: Convert nested list to 2d array (3 个回答) 已关闭 7 年前。 java中有没有快捷方式可以转换 List> 到 String[][] ?
我在排序时遇到问题 List> 。我创建了一个自定义比较器,在其中编写了对数据进行排序的代码。 public class CustomComparator implements Comparator
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Java Generics: Cannot cast List to List? 我只是想知道为什么下面的java代
试图想出一个 LINQy 方法来做到这一点,但我什么也没想到。 我有一个对象列表<>,其中包含一个属性,该属性是逗号分隔的字母代码列表: lst[0].codes = "AA,BB,DD" lst[1
假设我有这些任务: points = [] point = (1, 2) 我怎么会这样做: points += point 它工作得很好,并且给了我点 = [1, 2]。但是,如果我这样做: poin
如何在 scala 中将 List[Task[List[Header]]] 类型转换为 Task[List[Header]]。 我有一个方法返回 Task[List[Header]] 并多次调用 do
如何在 Java 中查找二维列表的元素? 我有一个参数为 List> 的函数我想知道如何找到这个列表的行和列。 最佳答案 如果你喜欢 List> obj 然后你就可以像这样访问 obj.get(cur
分配 List到 List工作正常。 分配 List>到 List>不编译。 代码 public class Main { public static void main(String[] a
我正在用 Java 编写一个方法,该方法必须接收并迭代 Serializable 的 List。 有什么区别: public void myMethod(List list) { } 和 public
我看到很多人想用 mvvm 更新网格/列表/树的一部分,但他们不想刷新整个列表。 对于所有遇到此问题的人,我做了以下示例。 希望这对你有用。 最佳答案 这是一个简单的例子。整个代码中最重要的是: Bi
我正在为现有的 C++ 库编写包装器,该库使用列表,其中 T 是自定义结构。我被建议使用 vector 而不是列表,但我试图避免修改库。 为了更好地理解这个场景,我做了一个简单的应用程序,使用一个列表
List list List list 这两种声明有什么区别吗? 谢谢, 最佳答案 是的。 List可以包含所有派生自 Base 的不同事物的混合物. List包含同质项(从某种意义上说,它们必须全部
有人可以尽可能详细地解释以下类型之间的区别吗? List List List 让我更具体一点。我什么时候想使用 // 1 public void CanYouGiveMeAnAnswer(List l
我有一个元组列表,每个元组都是一对列表。所以我的数据看起来像: mylist = [(['foo', 'bar'], ['bar', 'bar']),(['bar', 'bar'],['bar', '
也许是一个时髦的标题,但我遇到了以下问题: 给定一个类型为 (a * b) list 的列表,我想创建一个类型为 (a * b list) list 的新列表。一个例子: 给定列表 let testL
我是一名优秀的程序员,十分优秀!