在Scala中将任意类作为monad实例 [英] Make an arbitrary class in Scala as a monad instance

查看:88
本文介绍了在Scala中将任意类作为monad实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了使任何东西都可以在monad上下文中操作,如果使用Haskell-我只是在任何地方为给定类型添加Monad类的实现.因此,我完全不涉及数据类型定义的来源.像(人造的)

In order to make anything operable in monad context, if using Haskell - I just add implementation of class Monad for given type anywhere. So I don't touch a source of the data type definition at all. Like (something artificial)

data Z a = MyZLeft a | MyZRight a

swap (MyZLeft x) = MyZRight x
swap (MyZRight x) = MyZLeft x

instance Monad Z where
  return a = MyZRight a
  (>>=) x f = case x of
                MyZLeft s -> swap (f s)
                MyZRight s -> swap (f s)

所以我没有触及Z的定义,而是将其作为单子.

so I'm not touching definition of Z, but make it as a monad

我如何在Scala中做到这一点?似乎除了混合一些特征并定义方法map/flatMap/filter/withFilter之外,别无选择.

How do I do this in Scala? It seems that there's no way besides of mixing some traits in and defining methods map/flatMap/filter/withFilter ?

推荐答案

看看 scalaz :

// You could use implementation in the end of this answer instead of this import
import scalaz._, Scalaz._

sealed trait Z[T]
case class MyZLeft[T](t: T) extends Z[T]
case class MyZRight[T](t: T) extends Z[T]

def swap[T](z: Z[T]) = z match {
  case MyZLeft(t) => MyZRight(t)
  case MyZRight(t) => MyZLeft(t)
}

implicit object ZIsMonad extends Monad[Z] {
  def point[A](a: => A): Z[A] = MyZRight(a)
  def bind[A, B](fa: Z[A])(f: A => Z[B]): Z[B] = fa match {
    case MyZLeft(t) => swap(f(t))
    case MyZRight(t) => swap(f(t))
  }
}

用法:

val z = 1.point[Z]
// Z[Int] = MyZRight(1)

z map { _ + 2 }
// Z[Int] = MyZLeft(3)

z >>= { i => MyZLeft(i + "abc") }
// Z[String] = MyZRight(1abc)

z >>= { i => (i + "abc").point[Z] }
// Z[String] = MyZLeft(1abc)

for-comprehensions(类似于do-notation ):

for {
  i <- z
  j <- (i + 1).point[Z]
  k = i + j
} yield i * j * k
// Z[Int] = MyZRight(6)

另请参见 Scalaz速查表 scalaz中没有魔术-您可以在没有scalaz的情况下实现.

There is no magic in scalaz - you could implement this without scalaz.

相关: Scala和amp;中的Typeclases Haskell .

Monad的最简单实现,带有语法,以防您不想使用scalaz:

Simplest implementation of Monad with syntax in case you don't want to use scalaz:

import scala.language.higherKinds

trait Monad[M[_]] {
  def point[A](a: => A): M[A]
  def bind[A, B](fa: M[A])(f: A => M[B]): M[B]
}

implicit class MonadPointer[A](a: A) {
  def point[M[_]: Monad] = implicitly[Monad[M]].point(a)
}

implicit class MonadWrapper[M[_]: Monad, A](t: M[A]) {
  private def m = implicitly[Monad[M]]
  def flatMap[B](f: A => M[B]): M[B] = m.bind(t)(f)
  def >>=[B](f: A => M[B]): M[B] = flatMap(f)
  def map[B](f: A => B): M[B] = m.bind(t)(a => m.point(f(a)))
  def flatten[B](implicit f: A => M[B]) = m.bind(t)(f)
}

这篇关于在Scala中将任意类作为monad实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆