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

时间:2014-11-11 10:26:52

标签: haskell

我有这个解析器定义:

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

我也有这个功能:

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

如何使下面的函数从(Char,String Char)返回中间元素

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

示例:

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

我想提取x和y。

谢谢!

2 个答案:

答案 0 :(得分:4)

这将是:

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

但我建议您声明Parser a一个仿函数:

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

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

这当然不是Parser (a,b,c) -> (b, String),但你需要看看你是否真的需要unJust结果。例如:

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

正如评论中正确指出的那样,类型与请求的类型不同。如果没有Parser (a,b,c) -> (b, String)提供要解析的functionCons,则无法获得确切的签名String

答案 1 :(得分:2)

这里有两个问题:

Applicatives

我认为你没有在haskell允许的范围内使用applicatives。 functionMatching返回分隔符,只是稍后将它们丢弃。要丢弃Parser匹配项,请使用*><*

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

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

<*>*><*如何工作很容易记住,他们只返回><指向的内容:

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

解析器

有一种更惯用的方式来使用解析器。请勿提取未解析的String Maybe (a,String)解析!这是对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是一个类似于您想要导出的runState, evalState, execState的有用功能。

解析器的想法是不要过早地离开解析器。如果没有匹配,上面的代码将遇到错误(fromJust执行此操作)。 haskell为此使用了Maybe,并且已经在解析器中内置了Maybe。我不知道你想用(String,String)做什么,但你可能想把它传递给函数f :: String -> String -> b

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

会更好地处理不匹配问题。