scala - 在 Scala 中编写状态 monad

标签 scala monads

状态 monad 的理论是我从 Philip Wadler 的《函数式编程 Monads》借来的:

type M a = State → (a, State) 
type State = Int
unit :: a → M a
unit a = λx. (a, x)
(*) :: M a → (a → M b) → M b
m * k = λx. 
         let (a, y) = m x in 
         let (b, z) = k a y in 
         (b, z)

我想使用状态单子(monad)的方式如下:

Given a list L I want different parts of my code to get this list and update this list by adding new elements at its end.

我想上面的内容应该修改为:

type M = State → (List[Data], State) 
type State = List[Data]
def unit(a: List[Data]) = (x: State) => (a,x)
def star(m: M, k: List[Data] => M): M = {
 (x: M) => 
   val (a,y) = m(x)
   val (b,z) = k(a)(y)
   (b,z)
} 
def get = ???
def update = ???

如何填写详细信息?

  1. 如何实例化我的层次结构以处理具体列表?
  2. 如何根据上述内容实现获取和更新?

最后,我该如何使用 Scala 的语法以及 flatMap 和 unit 来做到这一点?

最佳答案

您的M定义不正确。它应该采用 a/A 作为参数,如下所示:

type M[A] = State => (A, State)

您还在其他地方错过了该类型参数。

unit 应该有这样的签名:

def unit[A](a: A): M[A]

star 应该有这样的签名:

def star[A, B](m: M[A], k: A => M[B]): M[B]

希望这能让功能更加清晰。

您的 unit 实现几乎相同:

def unit[A](a: A): M[A] = x => (a, x)

但是,在 star 中,您的 lambda (x) 参数的类型为 State,而不是 M >,因为 M[B] 基本上是 State => (A, State)。其余的你都答对了:

def star[A, B](m: M[A])(k: A => M[B]): M[B] = 
  (x: State) => {
    val (a, y) = m(x)
    val (b, z) = k(a)(y)
    (b, z)
  }

编辑:根据 @Luis Miguel Mejia Suarez 的说法:

It would probably be easier to implement if you make your State a class and define flatMap inside it. And you can define unit in the companion object.

他建议final class State[S, A](val run: S => (A, S)),这也允许您使用中缀函数,例如>>= .

另一种方法是将 State 定义为函数 S => (A, S) 的类型别名,并使用隐式类对其进行扩展。

type State[S, A] = S => (A, S)
object State {
  //This is basically "return"
  def unit[S, A](a: A): State[S, A] = s => (a, s)
}

implicit class StateOps[S, A](private runState: S => (A, S)) {
  //You can rename this to ">>=" or "flatMap"
  def *[B](k: A => State[S, B]): State[S, B] = s => {
    val (a, s2) = runState(s)
    k(a)(s2)
  }
}

如果您对 get 的定义是

set the result value to the state and leave the state unchanged (borrowed from Haskell Wiki), then you can implement it like this:

def get[S]: State[S, S] = s => (s, s)

如果您的意思是要提取状态(在本例中为 List[Data]),则可以使用 execState (在 StateOps 中定义它) ):

def execState(s: S): S = runState(s)._2

这是一个糟糕的示例,说明如何向 List 添加元素。

def addToList(n: Int)(list: List[Int]): ((), List[Int]) = ((), n :: list)

def fillList(n: Int): State[List[Int], ()] =
  n match {
    case 0 => s => ((), s)
    case n => fillList(n - 1) * (_ => addToList(n))
  }

println(fillList(10)(List.empty)) 给我们这个(可以使用 execState 提取第二个元素):

((),List(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))

关于scala - 在 Scala 中编写状态 monad,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62849571/

相关文章:

haskell - 临时类型变量的作用域

haskell - Monadic 管道图分割流

Haskell - 在 Monad 中提取 Maybe

haskell - 如何使用replicateM解决八皇后问题?

Scala 映射 -> 运算符

haskell - MonadIO 到 Maybe

eclipse - 使用Eclipse在Scala中创建单文件可运行Jar

scala - Scala 的特征如何不是真正的特征?

scala - 使用 Guice 和 MockitoSugar 模拟返回 Cats EitherT 的服务

scala - List 是怎样的一个单子(monad)?