如果没有收益定义,Haskell表示法如何知道要采用哪个值?

时间:2018-11-08 05:32:07

标签: haskell

我有这个单子对象。

data Parser a = Parser (String -> Maybe (a, String))

instance Functor Parser where
  -- fmap :: (a -> b) -> Parser a -> Parser b
  fmap f (Parser pa) =  Parser $ \input -> case pa input of
                                             Nothing -> Nothing
                                             Just (a, rest) -> Just (f a, rest)

instance Applicative Parser where
  pure = return
  (<*>) = ap

instance Monad Parser where
  --return :: a -> Parser a
  return a =  Parser $ \input -> Just (a, input)

  --(>>=) :: Parser a -> (a -> Parser b) -> Parser b
  (Parser pa) >>= f  = Parser $ \input -> case pa input of
                                            Nothing -> Nothing
                                            Just (a,rest) -> parse (f a) rest

我对item的定义是这样的,我被告知“读入一个字符”,但我没有真正看到任何读物。

item :: Parser Char
item = Parser $ \ input -> case input of ""    -> Nothing
                                         (h:t) -> Just (h, t)

但是,好的,也许我应该放松一下如何将“ read”和jibe一词带入其中。继续,我有

failParse :: Parser a
failParse = Parser $ \ input -> Nothing

sat :: (Char -> Bool) -> Parser Char
sat p = do c <- item
           if p c
           then return c
           else failParse

这就是我很困惑的地方。变量c中存储了什么?由于item是带有参数Parser的{​​{1}},因此我的第一个猜测是Char正在存储这样的对象。但是,经过一秒钟的思考,我知道do表示法现在不起作用了,您没有得到monad,而是得到了monad的内容。很好,但这告诉我c是函数

c

但是显然,这是错误的,因为\ input -> case input of "" -> Nothing (h:t) -> Just (h, t) 定义的下一行将sat视为字符。这不仅不是我所期望的,而且还比我期望的低了三个层次!它不是函数,不是Maybe对象,也不是元组,而是埋在函数内部的Just元组的左坐标!这个小人物在外面如何一直工作?指示c提取Monad的这一部分的内容是什么?

2 个答案:

答案 0 :(得分:3)

如评论所述,<-只是do notation语法糖,等效于:

item >>= (\c->if p c 
              then return c 
              else failParse)

好的,让我们看看c是什么?考虑(>>=)

的定义
(>>=) :: Parser a -> (a -> Parser b) -> Parser b

或更可读的方式:

Parser a >>= (a -> Parser b)

现在,将其与上面的表达式item >>= (\c->if p c then return c else failParse)匹配:

Parer a = item

(a->Parser b) = (\c->if p c then return c else failParse) 

item的类型为:

item :: Parser Char

因此,我们现在可以将a中的(>>=)替换为Char,给出

Parser Char >>= (Char -> Parser b)

现在\c->if p c then return c else failParse的类型也为:(Char -> Parser b)

所以c是一个Char,整个表达式可以扩展为:

sat p =
item >>= (\c->...) = 
Parser pa >= (\c->...) = Parser $ \input -> case pa input of
                                            Nothing -> Nothing
                                            Just (a,rest) -> parse (f a) rest
                         where f c =  if p c
                                      then return c
                                      else failParse
                               pa input = case input of ""   -> Nothing
                                                       (h:t) -> Just (h, t)

答案 1 :(得分:1)

TL; DR:通常,根据Monad法,

do { item }

相同
do { c <- item
   ; return c
   }

从某种意义上说,它是由return定义的。详细信息如下。


它确实从正在被“ read” 的输入字符串中取出一个字符,因此从这个意义上来说,它会“ reads” 该字符:

item :: Parser                                   Char
item = Parser $ \ input ->   -- input :: [Char]   
             case input of { ""    -> Nothing
                           ; (h:t) -> Just (h, t)  -- (h:t) :: [Char]
                           }             -- h :: Char    t :: [Char]

我敢肯定有一个定义

parse (Parser pa) input = pa input

在某处定义;所以

parse item input = case input of { "" -> Nothing ; (h:t) -> Just (h, t) }

接下来,(>>=)是什么意思?这意味着

parse (Parser pa >>= f) input = case (parse (Parser pa) input) of
                     Nothing -> Nothing
                     Just (a, leftovers) -> parse (f a) leftovers

parse (item      >>= f) input = case (parse  item  input) of
                     Nothing -> Nothing
                     Just (a, leftovers) -> parse (f a) leftovers
      = case (case input of { "" -> Nothing ; (h:t) -> Just (h, t) }) of
                     Nothing -> Nothing
                     Just (a, leftovers) -> parse (f a) leftovers
      = case input of 
           ""    -> Nothing 
           (h:t) -> case Just (h, t) of {
                         Just (a, leftovers) -> parse (f a) leftovers }
      = case input of 
           ""    -> Nothing 
           (h:t) -> parse (f h) t

现在

-- sat p: a "satisfies `p`" parser 
sat :: (Char -> Bool) -> Parser Char
sat p = do { c <- item           -- sat p :: Parser Char
           ; if p c              -- item :: Parser Char,   c :: Char
                then return c    -- return c :: Parser Char
                else failParse   -- failParse :: Parser Char
           }
      = item >>= (\ c ->
                    if p c then return c else failParse)

(通过展开do语法),等等

parse (sat p) input 
 = parse (item >>= (\ c ->
                    if p c then return c else failParse)) input
   -- parse (item >>= f) input
   --  = case input of { "" -> Nothing ; (h:t) -> parse (f h) t }
 = case input of 
       "" -> Nothing 
       (h:t) -> parse ((\ c -> if p c then (return c)
                                       else failParse) h) t
 = case input of 
       "" -> Nothing 
       (c:t) -> parse (if p c then (return c) 
                               else failParse) t
 = case input of 
       "" -> Nothing 
       (c:t) -> if p c then parse (return c) t
                               else parse failParse t
 = case input of 
       "" -> Nothing 
       (c:t) -> if p c then Just (c, t)
                               else Nothing

现在sat p的含义应该很清楚:对于c产生的item(如果输入为非空,则是输入中的第一个字符),如果{{ 1}}成立,p c被接受并且解析成功,否则解析失败:

c