加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

如何使自己的for-comprehension兼容scala monad?

发布时间:2020-12-16 08:49:49 所属栏目:安全 来源:网络整理
导读:我想在 Scala中实现我自己的for-comprehension兼容的monad和functor. 我们以两个愚蠢的monad为例.一个monad是一个状态monad,包含一个可以映射或平面映射的“Int”. val maybe = IntMonad(5)maybe flatMap( a = 3 * ( a map ( () = 2 * a ) ) )// returns Int
我想在 Scala中实现我自己的for-comprehension兼容的monad和functor.

我们以两个愚蠢的monad为例.一个monad是一个状态monad,包含一个可以映射或平面映射的“Int”.

val maybe = IntMonad(5)
maybe flatMap( a => 3 * ( a map ( () => 2 * a ) ) )
// returns IntMonad(30)

另一个monad采取像这样的功能组合……

val func = FunctionMonad( () => println("foo") )
val fooBar = func map ( () => println("bar") )
fooBar()
// foo
// bar
// returns Unit

这个例子可能有一些错误,但你明白了.

我希望能够在Scala中使用这两种不同类型的Monad组成的for-understanding.像这样:

val myMonad = IntMonad(5)
for {
    a <- myMonad
    b <- a*2
    c <- IntMonad(b*2)
} yield c    
// returns IntMonad(20)

我不是斯卡拉大师,但你明白了

解决方法

对于在for-comprehension中使用的类型,您实际上只需要为它返回返回相同类型实例的map和flatMap方法.从语法上讲,for-comprehension由编译器转换为一系列flatMaps,后跟yield的最终映射.只要这些方法具有适当的签名,它就可以工作.

我不确定你的例子是什么,但这里有一个简单的例子,相当于Option:

sealed trait MaybeInt {
    def map(f: Int => Int): MaybeInt
    def flatMap(f: Int => MaybeInt): MaybeInt
}

case class SomeInt(i: Int) extends MaybeInt {
    def map(f: Int => Int): MaybeInt = SomeInt(f(i))
    def flatMap(f: Int => MaybeInt): MaybeInt = f(i)
}

case object NoInt extends MaybeInt {
    def map(f: Int => Int): MaybeInt = NoInt
    def flatMap(f: Int => MaybeInt): MaybeInt = NoInt
}

我有两个子类型的共同特征(尽管我可以拥有尽可能多的子类型).常见特征MaybeInt强制每个子类型符合map / flatMap接口.

scala> val maybe = SomeInt(1)
maybe: SomeInt = SomeInt(1)

scala> val no = NoInt
no: NoInt.type = NoInt

for {
  a <- maybe
  b <- no
} yield a + b

res10: MaybeInt = NoInt

for {
  a <- maybe
  b <- maybe
} yield a + b

res12: MaybeInt = SomeInt(2)

此外,您还可以添加foreach和过滤器.如果你想处理这个(没有收益):

for(a <- maybe) println(a)

你会添加foreach.如果你想使用if guard:

for(a <- maybe if a > 2) yield a

你需要filter或withFilter.

一个完整的例子:

sealed trait MaybeInt { self =>
    def map(f: Int => Int): MaybeInt
    def flatMap(f: Int => MaybeInt): MaybeInt
    def filter(f: Int => Boolean): MaybeInt
    def foreach[U](f: Int => U): Unit
    def withFilter(p: Int => Boolean): WithFilter = new WithFilter(p)

    // Based on Option#withFilter
    class WithFilter(p: Int => Boolean) {
        def map(f: Int => Int): MaybeInt = self filter p map f
        def flatMap(f: Int => MaybeInt): MaybeInt = self filter p flatMap f
        def foreach[U](f: Int => U): Unit = self filter p foreach f
        def withFilter(q: Int => Boolean): WithFilter = new WithFilter(x => p(x) && q(x))
    }
}

case class SomeInt(i: Int) extends MaybeInt {
    def map(f: Int => Int): MaybeInt = SomeInt(f(i))
    def flatMap(f: Int => MaybeInt): MaybeInt = f(i)
    def filter(f: Int => Boolean): MaybeInt = if(f(i)) this else NoInt
    def foreach[U](f: Int => U): Unit = f(i)
}

case object NoInt extends MaybeInt {
    def map(f: Int => Int): MaybeInt = NoInt
    def flatMap(f: Int => MaybeInt): MaybeInt = NoInt
    def filter(f: Int => Boolean): MaybeInt = NoInt
    def foreach[U](f: Int => U): Unit = ()
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读