将这个monadic计数器从Haskell翻译成Scala

我已经定义了一个
monadic counter in Haskell,我试图将其转换为Scala,到目前为止失败了.简而言之,问题是将计数器实现为状态monad,它从环境中读取计数器增量常量,并记录计数器的历史记录(其值序列).

我的一个朋友改进了我的解决方案,并提出了这个简单的解决方案:

newtype Counter = Counter Int deriving (Eq)

instance Show Counter where
  show (Counter i) = show i

incWith :: MonadState Counter m => Int -> m ()
incWith n = let incCounter n' (Counter i) = Counter $i + n'
            in modify (incCounter n)

inc :: (MonadReader Int m, MonadState Counter m, MonadWriter [Counter] m) => m ()
inc = ask >>= incWith >> get >>= tell . (:[])

compute :: (MonadReader Int m, MonadState Counter m, MonadWriter [Counter] m) => m ()
compute =
  local (const 3) $do
    inc
    inc
    inc
    local (const 5) $do
      inc
      inc

我已经尝试过without success将其编码为Scala(Cats | ScalaZ).最新稳定版的Cats缺乏WriterT的升力方法.使用Scalaz中的ReaderWriterState,我无法在几个小时内弄清楚如何使用本地方法.那只是开始……

如何以简单而优雅的方式翻译这个Haskell解决方案? (在语言允许的范围内).

边注:

我还在试图找出为什么我需要花费这么多时间将简单的解决方案从Haskell转换为Scala FP库(Cats,Scalaz).在Haskell中查找每个类型类的实例和可用函数是轻而易举的,在Scala中使用IntelliJ,GitHub和StackOverflow这需要几天时间.所以我想知道我做错了什么,我怎么能改善这种情况呢.

最佳答案 如果我理解你的意图是正确的,那么这就转化为非常简单易懂的代码:

  import scalaz._
  import Scalaz._
  val SM = ReaderWriterState.rwstMonad[Id, Int, List[String], Counter]

  case class Counter(value: Int)

  def incWith(n: Int): State[Counter, Unit] = for {
    v ← get[Counter]
    _ ← put(Counter(v.value + n))
  } yield ()

  def inc: IRWS[Int, List[String], Counter, Counter, Unit] = for {
    v ← SM.ask
    c ← SM.get
    _ ← SM.tell(List(s"Incrementing $c by $v "))
    _ ← SM.modify(counter ⇒ Counter(counter.value + v))
  } yield ()

  def compute: IRWS[Int, List[String], Counter, Counter, Unit] = {
    for {
      _ <- SM.local[Unit](i ⇒ 3)(for {
        _ ← inc
        _ ← inc
        _ ← inc
      } yield ())
      _ <- SM.local[Unit](i ⇒ 5)(for {
        _ ← inc
        _ ← inc
        _ ← inc
      } yield ())
    } yield ()
  }

  println(incWith(5)(Counter(0)))
  println(inc.run(4, Counter(0)))
  println(compute.run(0, Counter(0)))
点赞