简体   繁体   English

Haskell类型展开,然后折叠为另一种类型

[英]Haskell type unfold then fold to another type

I have this parser definition: 我有这个解析器定义:

newtype Parser a = P { getParser :: String -> Maybe (a, String) }

I also have this function: 我也有这个功能:

functionMatching :: Parser (Char, String, Char)
functionMatching = (,,) <$> spot (`elem` "\\") <*> getWord <*> spot (`elem` ".")

How can I make the below function returning the middle element from (Char, String Char) 我怎样才能使下面的函数从(Char,String Char)返回中间元素

functionCons:: Parser (Char, String, Char) -> (String, String)
functionCons = undefined

Example: 例:

getParser functionMatching "\\x.y"
Just (('\\',"x",'.'),"y")

I want to extract x and y. 我想提取x和y。

Thanks! 谢谢!

It will be something like: 它将类似于:

functionCons (P p) = P $ fmap (\((_,x,_), s) -> (x,s)) . p

But I suggest that you declare Parser a a functor: 但我建议您声明Parser a为函子:

newtype Parser a = P { getParser :: String -> Maybe (a, String) } 
                   deriving (Functor)

functionCons :: Parser (a,b,c) -> Parser b
functionCons = fmap (\(_,x,_) -> x)

This of course isn't quite Parser (a,b,c) -> (b, String) , but you need to see if you really need to unJust the result. 当然,这不是完全Parser (a,b,c) -> (b, String) ,但是您需要查看是否确实需要unJust结果。 For example: 例如:

functionCons :: Parser (a,b,c) -> String -> (b,String)
functionCons = unJust . fmap (\(_,x,_) -> x) where
  unJust (P p) s = case p s of
    Just x -> x
    -- if Nothing happens, it will throw a unmatched pattern

As has been correctly noted in the comments, the type is not the same as requested. 正如注释中正确指出的那样,类型与请求的类型不同。 It is not possible to get the exact signature Parser (a,b,c) -> (b, String) without functionCons providing the String to be parsed. 没有functionCons提供要解析的String ,就不可能获得准确的签名Parser (a,b,c) -> (b, String)

There are two issues here: 这里有两个问题:

Applicatives 应用程式

I think you are not using applicatives to the extent haskell allows. 我认为您没有在haskell允许的范围内使用应用性应用。 functionMatching returns the delimiting characters, only to have them discarded later. functionMatching返回定界字符,只是稍后将其丢弃。 To discard Parser matches, use *> and <* : 要放弃解析器匹配,请使用*><*

functionMatching''' :: Parser String
functionMatching''' = spot (`elem` "\\") *> getWord <* spot (`elem` ".")

functionCons''' :: String -> (String, String)
functionCons''' = fromJust . getParser functionMatching'''

How <*> , *> and <* work is easily memorized, they only return what > and < point to: <*>*><*工作方式很容易记住,它们仅返回><指向:

  • f <*> x: fx
  • x *> y: y
  • x <* y: x

Parsers 解析器

There is a way more idiomatic way to use parsers. 有一种更惯用的方式来使用解析器。 Don't extract the unparsed String of Maybe (a,String) , parse it instead! 不要提取Maybe (a,String)的未解析String ,而是解析它! That is one more call to getWord . 那是对getWord另一个调用。

functionMatching' :: Parser (String, String)
functionMatching' = (,) <$> (spot (=='\\') *> getWord <* spot (=='.')) <*> getWord

functionCons' :: String -> (String, String)
functionCons' = fromJust . evalParser functionMatching'

-- evalParser discards the unparsed String
evalParser :: Parser a -> String -> Maybe a
evalParser p s = fst <$> getParser p s

evalParser is a useful function analogous to runState, evalState, execState you will want to export. evalParser是一个有用的函数,类似于您要导出的runState,evalState和execState

The idea of parsers is to not leave the parser prematurely. 解析器的想法是不要过早地离开解析器。 The code above will encounter an error ( fromJust does this) if there is no match. 如果没有匹配项,上面的代码将遇到错误( fromJust这样做)。 haskell uses Maybe s for that, and a Maybe already is built into the parser. haskell为此使用Maybe ,并且解析器中已经内置了Maybe I do not know what you want to do with that (String,String) , but you probably want to pass it to a function f :: String -> String -> b . 我不知道您想使用那个(String,String)做什么,但是您可能想将其传递给函数f :: String -> String -> b Then a 然后一个

functionMatching'' :: Parser b
functionMatching'' = f <$> (spot (=='\\') *> getWord <* spot (=='.')) <*> getWord

will handle mismatches better. 将更好地处理不匹配问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM