Raku是否具备可将副作用编码为纯值的数据类型?
关于Raku中类似Cats Effect IO的纯副作用编码类型的疑问
我正在做《Grokking Functional Programming》一书的练习题,需要把原Scala示例代码转写成Raku。Scala的Cats Effect库中有个IO数据类型,它能将副作用编码为纯值,支持表达同步和异步计算——IO[A]是一个代表潜在带有副作用的IO操作(或其他不安全操作)的值,执行成功后会生成A类型的结果。
原Scala示例代码会打印两次"hey!":
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() }
我目前能想到的Raku对应类型是Promise,或是Lazy类型,但不确定Raku是否有专门用来将副作用编码为纯值的数据类型?
Raku标准库中没有像Cats Effect IO那样专门的内置IO类型,但可以通过几种方式实现类似的“将副作用封装为纯值”的效果:
用代码块(Callable)封装:这是最直接的方式,把副作用逻辑放在代码块里,代码块本身是一个纯值,只有显式调用时才会触发副作用。
# 封装单个副作用操作 my $print-hey = { say "hey!" }; # 此时无任何输出,直到调用 $print-hey(); $print-hey(); # 组合多个操作,模拟Scala的for推导式 sub combine-io(&op1, &op2) { { op1(); op2() } } my $program = combine-io({ say "hey!" }, { say "hey!" }); $program(); # 手动触发,执行两次打印Promise的灵活使用:Promise主要用于异步任务,但也能用来封装副作用并延迟执行。不过要注意,
Promise.start会立即启动任务,所以如果要完全手动触发,需要把Promise的创建也封装起来:my $program = { await Promise.start({ say "hey!" }); await Promise.start({ say "hey!" }); }; $program(); # 此时才执行两次打印Lazy类型的局限性:Lazy标量可以延迟计算,但它会缓存结果,第一次执行副作用后,后续访问不会再触发,所以只适合纯计算场景,不适合需要重复执行的副作用:
lazy $print-once = do { say "hey!"; Nil }; $print-once; # 第一次打印 $print-once; # 无输出,因为缓存了Nil结果
如果需要更贴近IO类型的函数式特性,也可以看看Raku社区的函数式编程模块,但用标准库的话,代码块是最简便的模拟方案。
内容的提问来源于stack exchange,提问作者ohmycloudy
相关产品推荐
相关产品推荐

