Icon语言中如何实现ZipWith等价操作?关于流与标量的疑问
Icon流操作:单值本质与非平凡流交错方法
嘿,关于你在Icon里遇到的流相关疑问,我来帮你拆解清楚:
1. 单值(比如2)的本质:单元素流 + 运算符的分布特性
在Icon里,所有值都是单元素流——没有所谓的“特殊标量”,单值只是只产生一次结果的流而已。而像*这类运算符天生就有流分布的特性:当运算符两边有流时,它会自动将流的每个元素与另一边的元素(如果是流的话,会遍历所有组合;如果是单元素流,就逐个结合)生成新的流。
比如你给出的代码:
procedure main() every write((1 | 2 | 3) * 2) end
它等价于手动展开流的组合:
procedure main() every write(1*2 | 2*2 | 3*2) end
这里的2作为单元素流,会被自动和左边流的每个元素配对运算,最终输出2、4、6。
2. 交错两个非平凡流的实现方法
要交错两个流的元素(比如把流A: 1|3|5和流B:2|4|6变成1|2|3|4|5|6),你可以通过自定义递归生成器来实现,利用Icon的惰性流特性按需生成元素:
# 自定义交错生成器:交替从两个流中取元素 procedure interleave(stream1, stream2) # 先尝试从第一个流取元素 if elem := !stream1 then { suspend elem # 挂起输出当前元素 # 递归调用时交换两个流的位置,实现交替 suspend interleave(stream2, stream1) } else { # 如果第一个流耗尽,输出第二个流剩下的所有元素 suspend !stream2 } end # 测试示例 procedure main() # 定义两个非平凡流 even := 2 | 4 | 6 odd := 1 | 3 | 5 # 交错输出两个流的元素 every write(interleave(odd, even)) end
运行这段代码会依次输出1、2、3、4、5、6。如果其中一个流是无限流(比如1 to *),这个生成器也能持续交替输出元素,完全适配Icon的惰性流模型。
另外,如果你需要的是“全交错”(即每个流的元素两两组合,而不是交替取单个元素),那直接用|和运算符结合即可,比如(1|2) * (3|4)会生成3|4|6|8,这是Icon默认的流笛卡尔积行为。
内容的提问来源于stack exchange,提问作者Greg Nisbet
相关产品推荐
相关产品推荐

