如何在 Perl 6 中编写“intersperse”函数

How to write an `intersperse` function in Perl 6

我在 Perl 6 中遗漏的一件事是 intersperse 函数 like Haskell has:

The intersperse function takes an element and a list and `intersperses' that element between the elements of the list.

例如这个:

intersperse <X Y>, (<a b>, <c d>, <e f>);

...应该 return 这个序列:

<a b>, <X Y>, <c d>, <X Y>, <e f>

所以我一直在尝试自己将其实现为自定义函数。 为了获得最大的可重用性,它应该:

  1. 支持任何类型的对象(包括List和Nil)作为元素。
  2. 不以任何方式改变元素的容器化。
  3. 不会展平或以其他方式影响元素的内部结构。
  4. Return 如果输入列表作为惰性序列给出,则为惰性序列,以便它可以用于无限序列,如 intersperse 42, 1..Inf.

到目前为止我想出的是:

sub intersperse (\element, +list) {
    ((element xx *) Z list).map(|*)[1..*]
}

即:无限重复要穿插的元素,用list压缩,然后用mapslip每个元组,去掉zip加的嵌套层,不用将原来的元素压平,然后用一个数组下标去掉中间穿插元素的前导重复。

满足要求1-3,但不满足要求4,因为数组下标是eagerly操作(即完全迭代输入序列然后return是一个非惰性List) 并因此导致此函数在给定无限序列时挂起。

实现此功能以满足所有 4 个要求的好方法是什么?

我对我提出的解决方案不是特别满意,但他们走了:

sub intersperse (\element, +list) {
    map { ((element xx *) Z list).map(|*)[$_] },
        1..(list.is-lazy ?? Inf !! list.elems * 2 - 1);
}

sub intersperse (\element, +list) {
    gather for list {
        FIRST .take, next;
        take slip element, $_;
    }
}

sub intersperse (\element, +list) {
    list.map({ slip element, $_ }) does role {
        method iterator {
            my \it = callsame;
            it.pull-one;
            it;
        }
    }
}

也许它会成为其他人想出更好的东西的灵感...