代码之家  ›  专栏  ›  技术社区  ›  Dulguun Otgon

Linter说lambda是多余的,但如果按照建议进行替换,则会产生不同的错误

  •  2
  • Dulguun Otgon  · 技术社区  · 10 年前

    我在看书 Real World Haskell - Chapter 10 .

    所有函数都具有通用类型 L.ByteString -> Maybe (a, L.ByteString) 然后我研究了StateT的定义 s -> m (a, s) 如果是写的,则与上面的完全匹配 StateT L.ByteString Maybe a 。所以我决定使用monad变形金刚重写第一个示例。希望如此

    parseP5 :: StateT L.ByteString Maybe Greymap
    parseP5 = do
       matchHeader (L8.pack "P5")
       skipSpace
       width <- getNat
       skipSpace
       height <- getNat
       skipSpace
       maxGrey <- getNat
       skipSpace
       _ <- getBytes 1
       bitmap <- getBytes (width*height)
       return (Greymap width height maxGrey bitmap)
    

    就会奏效。

    例如 matchHeader 函数将变为

    matchHeader :: L.ByteString -> StateT L.ByteString Maybe ()
    matchHeader prefix = \str ->
          if prefix `L8.isPrefixOf` str
             then Just ((), str)
             else Nothing
    

    但林特表示,它有多余的lambda。但我不知道如何在没有lambda的情况下编写它。你能帮我做这个吗?

    更新:

    更换时,如:

    matchHeader prefix str=
          if prefix `L8.isPrefixOf` str
             then Just ((), str)
             else Nothing
    

    它给出了另一个错误

    无法匹配期望的类型 L8.ByteString -> Maybe ((), L8.ByteString) 带实际类型 StateT L8.ByteString Maybe () matchHeader的公式有两个参数,但其类型 L8.ByteString -> StateT L8.ByteString Maybe () 只有一个

    不是 L8.ByteString -> Maybe((), L8.ByteString) StateT L8.ByteString可能() 同样的事情?

    1 回复  |  直到 4 年前
        1
  •  7
  •   shang    10 年前

    StateT s m a 不是的类型别名 s -> m (a, s) 但是 newtype 包装器,该包装器被类型检查器计数为单独的类型,因此您必须使用 StateT 构造函数。

    import Control.Monad.State
    import qualified Data.ByteString.Lazy as L
    import qualified Data.ByteString.Lazy.Char8 as L8
    
    matchHeader :: L.ByteString -> StateT L.ByteString Maybe ()
    matchHeader prefix = StateT $ \str ->
          if prefix `L8.isPrefixOf` str
             then Just ((), str)
             else Nothing
    

    还可以使用 Monad 的实例 状态T

    matchHeader prefix = do
          str <- get
          if prefix `L8.isPrefixOf` str
             then return ()
             else lift Nothing
    

    这使用 get 获取当前状态,然后返回 () 或“提升” 状态T 变压器内部 Maybe 莫纳德。

    上面的示例使用与原始代码相同的逻辑,但您可能也希望从状态中去掉前缀。您也可以使用 guard 从…起 MonadPlus 正如rjan所展示的那样,它缩短了if条款。

    matchHeader :: L.ByteString -> StateT L.ByteString Maybe ()
    matchHeader prefix = do
        str <- get
        guard (prefix `L8.isPrefixOf` str)
        put $ L8.drop (L8.length prefix) str