1. # A Sequence represents anything that can lazily produce a sequence of values.
  2. # There are various concrete implementations of Sequence, the most common
  3. # being Seq, which represents a sequentially produced sequence.
  4. #
  5. # Sequences are born in a state where iterating them will consume the values.
  6. # However, calling .cache will return a List that will lazily reify to the
  7. # values in the Sequence. The List is memoized, so that subsequent calls to
  8. # .cache will always return the same List (safe as List is immutable). More
  9. # than one call to .iterator throws an exception (and calling .cache calls the
  10. # .iterator method the first time also). The memoization can be avoided by
  11. # asking very specifically for the Seq to be coerced to a List (using .List
  12. # or .list), a Slip (.Slip) or an Array (.Array).
  13. #
  14. # The actual memoization functionality is factored out into a role,
  15. # PositionalBindFailover, which is used by the binder to identify types that,
  16. # on failure to bind to an @-sigilled thing, can have .cache called on them
  17. # and get memoization semantics. This decouples this functionality from the
  18. # Sequence role, so other user-defined types can get access to this
  19. # functionality.
  20. my role PositionalBindFailover {
  21. has $!list;
  22. method cache() {
  23. $!list.DEFINITE
  24. ?? $!list
  25. !! ($!list := List.from-iterator(self.iterator))
  26. }
  27. multi method list(::?CLASS:D:) {
  28. List.from-iterator(self.iterator)
  29. }
  30. method iterator() { ... }
  31. }
  32. nqp::p6configposbindfailover(Positional, PositionalBindFailover); # Binder
  33. Routine.'!configure_positional_bind_failover'(Positional, PositionalBindFailover); # Multi-dispatch
  34. my role Sequence does PositionalBindFailover {
  35. multi method Array(::?CLASS:D:) { Array.from-iterator(self.iterator) }
  36. multi method List(::?CLASS:D:) { List.from-iterator(self.iterator) }
  37. multi method Slip(::?CLASS:D:) { Slip.from-iterator(self.iterator) }
  38. multi method Str(::?CLASS:D:) {
  39. self.cache.Str
  40. }
  41. multi method Stringy(::?CLASS:D:) {
  42. self.cache.Stringy
  43. }
  44. method Numeric(::?CLASS:D:) { self.cache.elems }
  45. multi method AT-POS(::?CLASS:D: Int:D $idx) is raw {
  46. self.cache.AT-POS($idx)
  47. }
  48. multi method AT-POS(::?CLASS:D: int $idx) is raw {
  49. self.cache.AT-POS($idx)
  50. }
  51. multi method EXISTS-POS(::?CLASS:D: Int:D $idx) {
  52. self.cache.EXISTS-POS($idx)
  53. }
  54. multi method EXISTS-POS(::?CLASS:D: int $idx) {
  55. self.cache.EXISTS-POS($idx)
  56. }
  57. multi method eager(::?CLASS:D:) { List.from-iterator(self.iterator).eager }
  58. method fmt(|c) {
  59. self.cache.fmt(|c)
  60. }
  61. multi method gist(::?CLASS:D:) {
  62. self.cache.gist
  63. }
  64. }