从自定义类型列表中过滤和提取的最佳方法?

时间:2019-06-21 04:27:32

标签: haskell

我有一个表示命令行选项的数据类型:

data Flag = Verbose | Help | Buffer Int deriving (Show, Eq)

程序运行时,我得到Flag的列表,与用户指定的选项相对应。例如,[Buffer 10, Verbose]

我的问题是,从Int中的Buffer提取[Flag]值的最佳方法是什么?
该列表甚至可能没有Buffer
我要提出的只是某种复杂的遍历/折叠,它使用case语句从其他Buffer中过滤出Flag

2 个答案:

答案 0 :(得分:9)

首先,请考虑以下功能:

buffers :: [Flag] -> [Int]
buffers xs = [b | Buffer b <- xs]

它从Int内部返回仅Buffer的列表。对于[Verbose, Help],它将返回[]。对于[Buffer 10, Verbose],它将返回[10]。对于[Buffer 123, Buffer 456],它将返回[123, 456]

现在您有一个[Flag] -> [Int]。如果您还提出了[Int] -> Int,则可以将它们组成以获得您最初要求的[Flag] -> Int,因此现在由您决定如何从列表中得到一个整数。

listToMaybe是一种方法。如果列表为空,它将返回Nothing,否则返回Just第一个元素。如果没有提供缓冲区,请与fromMaybe组合以设置默认缓冲区大小。

或者,您可以以某种方式组合多个缓冲区参数。 max (0:buffers xs)将返回指定的最大缓冲区大小,如果没有,则返回0。 (没有0:,如果未指定缓冲区大小,则程序将崩溃。)sum (buffers xs)将返回指定的所有缓冲区大小的总和(如果没有,则自动返回0,因为空总和为0)。

答案 1 :(得分:0)

对此有一个非常简单的解决方案。

首先,实现一种类型来表示程序行为的 complete 描述:

data Mode = NormalMode { verbose :: Bool, buffer :: Int } | HelpMode

然后,实现更新功能,以基于 one 标志和默认参数数组更新参数:

defaults :: Mode
defaults = NormalMode { verbose = False, buffer = defaultBuffer }
 -- assuming defaultBuffer is defined somewhere

update :: Flag -> Mode -> Mode
update Help _ = HelpMode
update _ HelpMode = HelpMode
update Verbose NormalMode { buffer = b } = NormalMode { verbose = True, buffer = b }
update (Buffer n) NormalMode { verbose = v } = NormalMode { verbose = v, buffer = n }

然后,要解析Flag的列表,只需使用foldrfoldl

parseFlagsR :: [Flag] -> Mode
parseFlagsR = foldr update defaults
 -- This prioritizes the leftmost Buffer flag

parseFlagsL :: [Flag] -> Mode
parseFlagsL = foldl (flip update) defaults
 -- This prioritizes the rightmost Buffer flag

您可以通过以下任意一种方式获取缓冲区,尽管我建议使用最后一种:

safeGetBuffer :: Mode -> Maybe Int
safeGetBuffer NormalMode { buffer = b } = Just b
safeGetBuffer _ = Nothing

getBufferWith :: Int -> Mode -> Int
getBufferWith _ NormalMode { buffer = b } = b
getBufferWith n _ = n

getBuffer :: Mode -> Int
getBuffer = getBufferWith defaultBuffer
 -- defaultBuffer from earlier, again, assuming it's defined.

此解决方案比Joseph Sible的回答更为笼统,在提取详细程度值时可能很有用。这也明确表示了标志的优先级,并方便地将所有更新操作捆绑为一个。

此外,如果您想了解更多有关此功能的一般实现方法,建议您熟悉镜头和其他光学器件。