6

Recently, I have been learning Swift's Combine framework.

In Apple's words:

The Combine framework provides a declarative approach for how your app processes events. Rather than potentially implementing multiple delegate callbacks or completion handler closures, you can create a single processing chain for a given event source. Each part of the chain is a Combine operator that performs a distinct action on the elements received from the previous step.

In Combine, There is a function called compactMap, which can filter nil values:

import Combine

let strings = ["a", "1.24", "3", "def", "45", "0.23"].publisher

strings
  .compactMap { Float($0) }
  .sink(receiveValue: {
    print($0)
  })
  .store(in: &subscriptions)
)

compactMap in Swift

I rewrite the above code in Raku as the following:

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];
my Supply $supply = Supply.from-list(@strings);
my Supply $compact = $supply.map(-> $value {
  try { Num($value) }
  if $! { Empty } else { Num($value) }
 }); # .grep(Num);

$compact.tap(
    &say,
    done => { say 'finished' },
    quit => { say 'done'     }
);

# ()   <--
# 1.24
# 3
# ()   <--
# 45
# 0.23

But it also output two empty parentheses. When use map on plain Array instead of on a Supply, the map with Empty value got filtered:

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];

my @compacted = @strings.map(-> $value {
    try { Num($value) }
    if $! { Empty } else { Num($value) }
});

.say for @compacted;

# 1.24
# 3
# 45
# 0.23

Is the behavior of map function with Empty value in Supply and plain Array inconsistent?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
chenyf
  • 5,048
  • 1
  • 12
  • 35
  • 1
    I am confused - is this a question about Combine or Raku? You start with "I have been learning Swift's Combine framework" and also tagged "swift" and "combine", but the body of your question asks about something completely irrelevant to Swift or Combine (?). – Sweeper Sep 01 '22 at 06:20
  • 1
    @Sweeper Sorry for confusion, My question is about Raku. I use Raku's `Supply` to implement the same logic of Combine's `compactMap` operator, but found the Raku version is less elegant than Swift's Combine – chenyf Sep 01 '22 at 07:32
  • 2
    I think it is worth making an issue about the inconsistency in handling `Empty` between `Supply` and `Array`. – Elizabeth Mattijsen Sep 02 '22 at 08:34
  • 2
    @ElizabethMattijsen thanks for your attention, I will making an issue. – chenyf Sep 02 '22 at 09:24

1 Answers1

7

Why not do it like this...

my @strings = ["a", "1.24", "3", "def", "45", "0.23"];

my $supply = Supply.from-list(@strings);
my $compact = $supply.grep(*.Num.so);
$compact.tap(&say);

# 1.24
# 3
# 45
# 0.23

I agree that there seems to be a small divergence (related to Failure handling) vs. regular grep (no .so needed)...

say @strings.grep(*.Num);
#(1.24 3 45 0.23)
librasteve
  • 6,832
  • 8
  • 30