代码之家  ›  专栏  ›  技术社区  ›  Sophia Gold

GHC 8.0.1编写器和状态单子的错误

  •  2
  • Sophia Gold  · 技术社区  · 7 年前

    The Essence of the Iterator Pattern 由杰里米·吉本斯和布鲁诺·C·d·S·奥利维拉编写,在编译时遇到了一些麻烦。这是我的代码:

    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.
    

    不管是哪种情况,我都不明白我做错了什么。任何帮助都将不胜感激。谢谢

    1 回复  |  直到 7 年前
        1
  •  3
  •   Benjamin Hodgson    7 年前

    对于 Writer Monoid . tell 使用 mappend 将其参数添加到运行日志。

    然而,对于整数,对于 幺半群 例子其中之一是加法,单位元素为0:

    instance Monoid Int where
        mempty = 0
        mappend = (+)
    

    另一个是与1:

    instance Monoid Int where
        mempty = 1
        mappend = (*)
    

    Haskell设计师应该如何在这两个选项之间进行选择?它们都同样有效,在不同的情况下都很有用。最后,他们决定不发表意见,离开了 Int 没有 幺半群 实例,而不是提供两个 newtype s允许您选择所需的实例。

    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 作家 monad,所以您需要做的就是将所有类型签名从 Writer Integer Writer (Sum Integer) .


    另一种类型的错误是GHC,它告诉您不能编写 作家 行动 State 行动你有 wcm :: State (Integer, Bool) String ccm :: Writer Integer String Integer 您的状态的组件来添加内容(我猜这意味着与 作家 单子转换器 版本 状态 :

    wcm :: StateT Bool (Writer Integer) String
    

    然后使用 lift 带着朴素的老人 写入整数 单子进入 StateT -这丰富了上下文。

    如果您还不习惯monad transformers,另一种选择是在 State (Integer, Bool) 单子。