首页 > 解决方案 > 有什么办法可以缩短这些线

问题描述

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

parseChar :: Char -> Parser Char
parseChar _ "" = Nothing
parseChar ch (x:xs) | x == ch = Just (ch, xs)
                    | otherwise = Nothing

parseAnyChar :: String -> Parser Char
parseAnyChar "" _ = Nothing
parseAnyChar _ "" = Nothing
parseAnyChar (x:xs) str | isJust res = res
                        | otherwise = parseAnyChar xs str
                        where res = parseChar x str

我是haskell的初学者,我想知道如何以比递归循环更“haskell方式”的方式在parseAnyChar中使用parseChar。例如使用地图或其他任何东西,但我找不到。

标签: haskell

解决方案


是的。一方面,您可以只使用标准函数而不是手动递归来尝试parseChar所有指定的替代方案:

import Data.List (find)

parseAnyChar cs str = case find isJust ress of
    Just res -> res
    Nothing  -> Nothing
 where ress = [parseChar c str | c<-cs]

...或更短

import Data.Maybe (listToMaybe)
import Control.Monad (join)

parseAnyChar cs str = join . listToMaybe $ (`parseChar`str)<$>cs

一个更有效的解决方案是首先不尝试所有选项,而是使用一个Set选项:

import qualified Data.Set as Set

parseOneCharOf :: Set.Set Char -> Parser Char
parseOneCharOf _ "" = Nothing
parseOneCharOf cs (x:xs)
   | x`Set.member`cs  = Just x
   | otherwise        = Nothing

...或更短

import Control.Monad (guard)
parseOneCharOf cs (x:xs) = guard (x`Set.member`cs) >> Just x

推荐阅读