2016-09-01 80 views
6

有一件事我一直在Perl 6的失蹤,是intersperse功能like Haskell has如何在Perl寫的`intersperse`功能6

的點綴功能需要的元素與列表和'點綴列表元素之間的元素。

例如,這樣的:

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

...應該返回序列:

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

所以我一直在試圖實現它自己作爲一個自定義的功能。 爲了獲得最大的可重用性,它應:

  1. 支持任何類型的對象(包括列表和無)作爲要素。
  2. 不以任何方式改變元素的集裝箱化。
  3. 不以任何方式展平或以其他方式影響元素的內部結構。
  4. 如果輸入列表是作爲惰性序列給出的,則返回一個惰性序列,以便它可以在無限序列上使用,如intersperse 42, 1..Inf中所述。

我想出到目前爲止,是這樣的:

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

即:無限重複的元素穿插,與列表拉鍊,然後使用mapslip每個元組以便除去由zip添加的嵌套層而不壓扁原始元素,然後使用數組下標來消除散佈元素的前導重複。

它滿足要求1-3,但不是4,因爲數組下標急於操作(即完全迭代輸入序列,然後返回一個非惰性列表)因此導致此函數在給定無限序列。

什麼是一個很好的方式來實現這個功能,以滿足所有4個要求?

+2

Inter esting。有點像'join'的List列表版本。 –

回答

9

我不是特別滿意,我已經想出瞭解決方案,但在這裏,他們去:

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; 
     } 
    } 
} 

也許它會成爲爲別人提供更好的靈感......

+0

哎喲,那第一個把它從'O(n)'變成'O(n²)',不是嗎? – smls

+0

雖然'聚攏'/'採取似乎是一個好方法,我沒有想到這一點。 我不認爲逗號運算符可以保證像C中那樣是一個序列點,所以我可能會寫這條代碼,比如'FIRST {take $ _;下一步}。 – smls

+0

好吧,我不會推薦第一種方法:這正是我想出來讓你的原創想法工作;我懷疑可能有更好的方法來做到這一點,但對我來說並不明顯;關於逗號操作符,它應該是安全的,因爲它從左到右進行評估;我不認爲這是實際記錄的任何地方 - 如果不是有人應該這樣做,並添加相應的spectest – Christoph