我正在阅读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
但是linter说它有多余的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&#39;的等式有两个参数,但它的类型L8.ByteString -> StateT L8.ByteString Maybe ()
只有一个
Isn&#t; t L8.ByteString -> Maybe((), L8.ByteString)
和StateT L8.ByteString Maybe ()
同样的事情?
答案 0 :(得分:7)
StateT s m a
不是s -> m (a, s)
的类型别名,而是newtype
包装器,由类型检查器计为单独的类型,因此您必须使用{{包装lambda 1}}构造函数。
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
<{1}} Monad
实例编写不带lambda的匹配器
StateT
这使用matchHeader prefix = do
str <- get
if prefix `L8.isPrefixOf` str
then return ()
else lift Nothing
来获取当前状态,然后返回get
或“提升”()
转换器到内部StateT
monad。
上面的示例使用与原始代码相同的逻辑,但您可能还希望从状态中删除前缀。您也可以使用来自Maybe
的{{1}},因为Ørjan已经证明可以缩短if子句。
guard