我对Haskell相对较新,并尝试使用monadic组合移植在Kernighan和Ritchie中演示的UNIX wc程序,如Jeremy Gibbons和Bruno C.的The Essence of the Iterator Pattern所示。 S. Oliveira,并且在编译时遇到了一些麻烦。这是我的代码:
import Control.Monad.Writer
import Control.Monad.State
import Data.Char
test :: Bool -> Integer
test b = if b then 1 else 0
ccmBody :: Char -> Writer Integer Char
ccmBody c = do
tell 1
return c
ccm :: String -> Writer Integer String
ccm = mapM ccmBody
lcmBody :: Char -> Writer Integer Char
lcmBody c = do
tell(test(c == '\n'))
return c
lcm' :: String -> Writer Integer String
lcm' = mapM lcmBody
wcmBody :: Char -> State (Integer, Bool) Char
wcmBody c = let s = not (isSpace c) in do
(n,w) <- get
put (n + test(not (w || s)), s)
return c
wcm :: String -> State (Integer, Bool) String
wcm = mapM wcmBody
clwcm = ccm >=> lcm' >=> wcm
编译错误:
wordcount.hs:10:3: error: …
• No instance for (Monoid Integer) arising from a do statement
• In a stmt of a 'do' block: tell 1
In the expression:
do { tell 1;
return c }
In an equation for ‘ccmBody’:
ccmBody c
= do { tell 1;
return c }
wordcount.hs:33:26: error: …
• Couldn't match type ‘StateT
(Integer, Bool) Data.Functor.Identity.Identity’
with ‘WriterT Integer Data.Functor.Identity.Identity’
Expected type: String
-> WriterT Integer Data.Functor.Identity.Identity String
Actual type: String -> State (Integer, Bool) String
• In the second argument of ‘(>=>)’, namely ‘wcm’
In the second argument of ‘(>=>)’, namely ‘lcm' >=> wcm’
In the expression: ccm >=> lcm' >=> wcm
Compilation failed.
在任何一种情况下,我都无法理解我在做什么。任何帮助将不胜感激。谢谢!
答案 0 :(得分:3)
要使Writer
monad工作,您正在编写的对象必须是Monoid
的实例。 tell
使用mappend
将其参数添加到正在运行的日志中。
但是对于整数,Monoid
实例至少有两个不错的选择。其中一个是加法,以0为单位元素:
instance Monoid Int where
mempty = 0
mappend = (+)
,另一个是乘以1:
instance Monoid Int where
mempty = 1
mappend = (*)
Haskell设计师应如何在这两种选择之间做出选择?它们同样有效,并且在不同情况下都有用。最后,他们决定不发表意见,让Int
没有自己的Monoid
个实例,而是提供两个newtype
,以便您选择所需的实例。
newtype Sum n = Sum { getSum :: n }
instance Num n => Monoid (Sum n) where
mempty = Sum 0
Sum x `mappend` Sum y = Sum (x + y)
newtype Product n = Product { getProduct :: n }
instance Num n => Monoid (Product n) where
mempty = Product 1
Product x `mappend` Product y = Product (x * y)
找到in the Data.Monoid
module这两个newtype
。我猜你想要在Writer
monad中添加数字,所以你需要做的就是将所有类型的签名从Writer Integer
更改为Writer (Sum Integer)
另一种类型错误是GHC告诉您,您无法使用Writer
操作撰写State
操作。您有wcm :: State (Integer, Bool) String
和ccm :: Writer Integer String
。浏览您的代码,看起来您只是使用州的Integer
组件来添加内容(我猜测它是否意味着参与运行总计)以及Writer
位?),所以我会考虑使用State
的 monad transformer 版本:
wcm :: StateT Bool (Writer Integer) String
然后使用lift
将普通的旧Writer Integer
monad引入StateT
- 丰富的上下文。
如果您还不习惯使用monad变换器,另一种选择是在State (Integer, Bool)
monad中写下所有内容。