【问题标题】:How to specify the return type of a function to be a (arbitrary) monad?如何将函数的返回类型指定为(任意)monad?
【发布时间】:2012-08-09 12:34:09
【问题描述】:

简而言之,我想声明一个这样的特征:

trait Test {
    def test(amount: Int): A[Int] // where A must be a Monad
}

这样我就可以在不知道A 是什么单子的情况下使用它,例如:

class Usecase {
    def someFun(t: Test) = for { i <- t.test(3) } yield i+1
}

更多细节...

基本上,我想做这样的事情:

class MonadResultA extends SomeUnknownType {
    // the base function
    def test(s: String): Option[Int] = Some(3)
}

class MonadResultB(a: MonadResultA) extends SomeUnknownType {
    // added a layer of Writer on top of base function
    def test(s: String): WriterT[Option, String, Int] = WriterT.put(a.test(s))("the log")
}

class Process {
    def work(x: SomeUnknownType) {
        for {
            i <- x.test("key")
        } yield i+1
    }
}

我希望能够传递MonadResultA 或 MonadResultB 的任何实例,而无需对函数work 进行任何更改。
缺少的部分是SomeUnknowType,我猜它应该有一个test 像下面这样使work 函数编译。

trait SomeUnknowType {
    def test(s: String): T[Int] // where T must be some Monad
}

正如我所说,我还在学习这个 monad 的东西...如果你发现我的代码不是 正确的方法,那么非常欢迎你指出它出来~

非常感谢~~

【问题讨论】:

    标签: scala monads scalaz monad-transformers


    【解决方案1】:

    假设您有一个名为 Monad 的类型类,您可以编写

    def test[A:Monad](amount: Int): A[Int]
    

    当调用 test 时,编译器将要求在作用域中存在 Monad[A] 类型的隐式。

    编辑: 我仍然不确定您在寻找什么,但是您可以将 monad 值与其对应的类型类打包成这样的特征:

    //trait that holds value and monad
    trait ValueWithMonad[E] {
      type A[+E]
      type M <: Monad[A]
      val v:A[E]
      val m:M
    }
    
    object M {
    
      //example implementation of test method
      def test(amount:Int):ValueWithMonad[Int] = new ValueWithMonad[Int] {
        type A[+E] = Option[E]
        type M = Monad[Option]
        override val v = Option(amount)
        override val m = OptionMonad
      }
    
      //test can now be used like this
      def t {
        val vwm = test(1)
        vwm.m.bind(vwm.v, (x:Int) => {
          println(x)
          vwm.m.ret(x)
        })
      }
    }
    
    trait Monad[A[_]] {
      def bind[E,E2](m:A[E], f:E=>A[E2]):A[E2]
      def ret[E](e:E):A[E]
    }
    
    object OptionMonad extends Monad[Option] {
      override def bind[E,E2](m:Option[E], f:E=>Option[E2]) = m.flatMap(f)
      override def ret[E](e:E) = Some(e)
    }
    

    【讨论】:

    • 但是调用代码必须确切知道A是什么,更重要的是,返回类型必须取决于调用函数时提供的A,这无法实现我想要做的......如果你有时间,请看一下我的问题的详细描述~谢谢~
    • 我建议你简化你的代码,这样它就减少了问题,并且不包含任何与你的项目无关的东西。 tl;博士
    • @Chris 当然,调用代码必须知道它将返回什么类型。 Scala 是静态类型的。它不知道运行时类,但它知道要编译的类型。如果您只知道要返回某种 Monad[Int],则返回类型必须是 Monad[Int]。
    • 我已经尝试简化我的代码,希望能让问题更清晰~
    • 我还在消化你写的东西,看来可以解决问题。随着方法测试为每个实现返回一个ValueWithMonad,t 方法可以用它来定义。我可以看到你对 Monad 的定义与 scalaz 的定义有点不同,比如 bind 方法它需要一个 f:A=>M[B],是不是拼写错误?
    猜你喜欢
    • 1970-01-01
    • 2022-06-15
    • 2020-05-15
    • 2020-09-10
    • 2017-11-12
    • 2022-01-22
    • 1970-01-01
    • 2015-03-23
    • 1970-01-01
    相关资源
    最近更新 更多