Skip to content

oshmkufa2010/ruby-monad

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

在Ruby里模拟Scala的for comprehension

Haskell的do-notation是个好东西,类似于JavaScript的async-await语法(实际上do-notation比async-await强大很多),可以帮助我们从>>=运算符的层层嵌套中解脱出来,其实质是编译器帮助我们做了一次CPS变换

In Haskell

f :: Monad m => m a
f = do
  x1 <- m1
  x2 <- m2
  ...
  return xn

Scala的for-comprehension也是类似的:

val f[M[_]: Monad, A]: M[A] = for {
  x1 <- m1
  x2 <- m2
  ...
} yield xn

但如果是Ruby呢?

对不起,Ruby没有

为此我模仿Scala的for-comprehension给Ruby订制了一套DSL,与Scala的Monad一样,只需给需要成为Monad的类定义一个unit类方法和flat_map实例方法即可,比如我们要将Ruby内置类型Array变成一个Monad,只需

class Array
  include Monad

  def self.unit(x)
    [x]
  end
end

因为Array已经实现了flat_map,所以只需实现unit 效果如下:

Array.for {
  let(:x) { [1, 2, 3] }
  let(:y) { (0..x).to_a }
}.yield { x + y } # => [1, 2, 2, 3, 4, 3, 4, 5, 6]

let函数实在是丑陋,所以我又实现了以下语法:

Array.for {
  x <= proc { [1, 2, 3] }
  y <= proc { (0..x).to_a }
}.yield { x + y }

About

An implementation of for-comprehension(do notation) in Ruby:)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages