【发布时间】:2016-09-03 10:39:46
【问题描述】:
我已经定义了一个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 的 lift 方法。在Scalaz 中使用ReaderWriterState,我在几个小时内无法弄清楚如何使用local 方法。而这仅仅是开始......
这个 Haskell 解决方案如何以简单而优雅的方式翻译? (在语言允许的范围内)。
旁注:
我仍在试图弄清楚为什么我需要花这么多时间将简单的解决方案从 Haskell 转换为 Scala + FP 库(Cats、Scalaz)。在 Haskell 中,查找每个类型类的实例和可用函数是一件轻而易举的事,在使用 IntelliJ、GitHub 和 StackOverflow 的 Scala 中,这需要我几天的时间。所以我想知道我做错了什么,我该如何改善这种情况。
【问题讨论】:
-
关于您的旁注:您认为 scala 文档对探索 API 没有帮助?
-
目前还没有。我看到一个定义为类私有的方法的问题(例如上面的
local),这意味着您不能直接使用它,而是通过这个私有类的多个实例之一。我认为您不能仅从 Scala 文档中做到这一点。 -
关于您的旁注,Scala 标准库没有配备诸如 Monad 之类的代数。如果您想访问这些设施,那么您必须自己手动编写代码,或者像使用 Scalaz 或 Cats 一样。然而,由于语言的冗长和它的类型系统,在 Scala 中在 Haskell 中完成相同的工作相对而言需要更多的工作。正如 Edward Kmett 所说,Haskell 为他提供了更高的功率重量比。你的挫败感证明了这一点。
-
@Samar,我想说最大的障碍是他们无法将任何 OOP 知识转移到 FP 范式中。如果我们甚至采用 FP 中最基本的引用透明性的基本概念,命令式程序员就会立即被难住。首先,他们必须明白 FP 中函数的概念是数学函数,而不是命令式意义上的函数/过程(有时包含隐含的环境)。
-
如果我们去掉了 OOP 程序员的基本工具,比如继承,那么你几乎已经瘫痪了他。而且我们甚至还没有开始讨论 FP 中的其他 FP 基本概念,例如 HOF、lambda 演算、ADT、代数和余代数等......
标签: scala haskell functional-programming scalaz scala-cats