Does Raku has a data type for encoding side effects as pure values?

193 Views Asked by At

I am doing some exercise from the book Grokking Functional Programming, the origin code examples are written in Scala, and I want to rewrite it with Raku.

In Scala's cats effect library, there is a type call IO, which is a data type for encoding side effects as pure values, capable of expressing both synchronous and asynchronous computations.IO[A] is a value that represents a potentially side-effectful IO action (or another unsafe operation) that, if successful, produces a value of type A.

The following code print "hey!" twice:

import cats.effect.IO
import cats.effect.unsafe.implicits.global

object TestApp extends App {
  val program: IO[Unit] = for {
    _ <- IO.println("hey!")
    _ <- IO.println("hey!")
  } yield ()
  program.unsafeRunSync()
}

The code can be run in Scala playground.

The corresponding data type in Raku I can think of is Promise, or some other Lazy data type I dont't know yet.

So, does Raku has a data type for encoding side effects as pure values?

3

There are 3 best solutions below

5
Rawley Fowler On BEST ANSWER

Using Raku's type-system it's fairly simple to implement monadic types like IO. Something like:

role IO[$t] does Callable { 
    has $.type = $t;
    has &.cb;

    method map(&f) {
        return IO[$!type].new(cb => &f(&!cb));
    }

    method bind(&f) {
        return &f(&!cb);
    }

    submethod CALL-ME(*@t) {
        &!cb();
    }
}

sub sayIO($s --> IO[Nil]) {
    # Use Nil in place of unit.
    return IO[Nil].new(cb => sub { say $s });
}

sub execAllSync(@ios --> Any) {
    $_() for @ios;
}

sub execAllAsync(@ios --> Promise) {
    my Promise @promises;
    for @ios -> $a {
        push @promises, start { $a(); }
    }
    Promise.allof(|@promises);
}

execAllSync [sayIO("foo"), sayIO("bar"), sayIO("baz")];
await execAllAsync([sayIO("foo"), sayIO("bar"), sayIO("baz")]);

There may also be some type-fu you can do using given to create a more monadic interface, similar to what is in Monad-Result. But I'm not 100% sure that it is super useful. The side-effect is just the execution of the code, so all you really need is a wrapper around a function.

1
wamba On

Not sure what exactly you need, but probably you could use Supply.

So FizzBuzz example in Raku could look like:

my Supply $s .=interval: 1;

$s              .tap( -> $x { say $x     });
$s.grep( * %% 3).tap( -> $  { say 'fizz' });
$s.grep( * %% 5).tap( -> $  { say 'buzz' });

sleep 16;

or with react-whenever block

my Supply $s .=interval: 1;

react {
    whenever $s               { say $_ }
    whenever $s.grep( * %% 3) { say 'fizz' }
    whenever $s.grep( * %% 5) { say 'buzz' }
}
1
raiph On

Does Raku has a data type for encoding side effects as pure values?

What do you mean?

Raku's Block data type can encode side effects as pure values:

my &pure-value = { say 'something'; 42 }

capable of expressing both synchronous and asynchronous computations.

Sure:

my &synchronous-computation  = {       say 42 }
my &asynchronous-computation = { start say 42 }

asynchronous-computation; # displays `42` asynchronously
synchronous-computation;  # displays `42` synchronously
...

The corresponding data type in Raku I can think of is Promise, or some other data type I don't know yet.

I don't know Scala, but I don't understand why you're suggesting the following Scala code is asynchronous. It, and other similar examples, look synchronous to me:

import cats.effect.IO
import cats.effect.unsafe.implicits.global

object TestApp extends App {
  val program: IO[Unit] = for {
    _ <- IO.println("hey!")
    _ <- IO.println("hey!")
  } yield ()
  program.unsafeRunSync()
}

I tried to explore your question more fully but some things got in the way:

  • The book you linked can't be read for free in a reasonable way.

  • I infer from your question, and the verbiage in the cats-effects doc, that vanilla (impure) Scala doesn't have a data type for encoding side effects as pure values. Raku makes it as easy as {...}. So there's little motivation to dig in to understand all that machinery.

  • cats and cats-effects are libraries, not part of Scala. Also, the cats links you've provided are to its 2.x version, which I think tracks its Scala 2.x library. I tried but gave up finding 3.x equivalents of the 2.x doc you linked. I'm loathe to invest further effort into the older library (2.x, whose last major updates were several years ago I think?) and older Scala (2.x, even more out-of-date with respect to Scala 3.x I think?).

  • I'm unsure what you're trying to achieve. Given that the Scala code is old-trending-obsolete, it seems unlikely that gaining more detailed insight into Raku analogs to that Scala code will get you or anyone else very far. What are you trying to achieve overall? Where do you hope to be in your Scala vs Raku explorations related to this a year from now?