用于在Scala中组合不同monad的惯用方法

时间:2014-09-19 19:57:00

标签: scala

假设我们有两个值包含在不同的monad中(例如Try和Option):

val x: Option[Int] = Some(10)
val y: Try[Int] = Success(4)

我们希望得到值的总和。一个人会写

val z = for {
  xval <- x
  yval <- y
} yield xval + yval

但由于类型错误,它不会被编译。有没有惯用的Scala方法来解决这个问题?

3 个答案:

答案 0 :(得分:3)

Scala标准库缺少一些有用的函数/抽象,但幸运的是有一个名为Scalaz的补充库,它提供了你需要的大部分内容。

特别是,正如所建议的那样,您正在寻找Monad变压器。请参阅以下这两篇文章:

http://eed3si9n.com/learning-scalaz/Monad+transformers.html

http://underscoreconsulting.com/blog/posts/2013/12/20/scalaz-monad-transformers.html

答案 1 :(得分:1)

使用Cats monad转换器OptionT:

import { Component } from '@angular/core';
import { of, from } from 'rxjs';
import { map, catchError, tap, retry} from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'Angular 6';

  constructor() {
    of('a', 'b', 'c', 'd')
      .pipe(
       map(x => {
        if (x === 'c') {
          throw 'An error has occurred';
        }
        return x;
       }),
       tap(x => console.log('In tap: ', x)),
       retry(3),
       catchError(() => of('caught error!'))
      )
      .subscribe(x => console.log(x));
  }
}

但是,返回类型为val z = (for { xval <- OptionT.fromOption(x): OptionT[Try, Int] yval <- OptionT.liftF(y) } yield xval + yval).value

答案 2 :(得分:0)

Daniel Spiewak的Emm库能够合并多个monad,但由于它不遵守所有monadic法律,因此该库仅用于教学目的。

Emm Github:https://github.com/djspiewak/emm

Daniel在Emm上做了一个演讲:https://www.youtube.com/watch?v=E5Tri3Yow0U

我还遇到了FreeK,这是一个用于编写多个Free monad的库:https://github.com/ProjectSeptemberInc/freek