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

问题描述 投票:0回答:2

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

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

当程序运行时,我会得到一个

Flag
列表,对应于用户指定的选项。例如,
[Buffer 10, Verbose]

我的问题是,从

Int
中的
Buffer
中提取
[Flag]
值的最佳方法是什么?
该列表甚至可能没有
Buffer

我想出的只是某种复杂的遍历/折叠,它使用
case
语句从其他
Buffer
中过滤掉
Flag

haskell
2个回答
8
投票

作为起点,考虑这个函数:

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
组合以设置默认缓冲区大小。

或者,您可以以某种方式组合多个缓冲区参数。

maximum (0:buffers xs)
将返回指定的最大缓冲区大小,如果没有则返回 0。 (如果没有
0:
,如果没有指定缓冲区大小,程序将会崩溃。)
sum (buffers xs)
将返回所有指定缓冲区大小的总和(如果没有指定缓冲区大小,则自动返回 0,因为空总和为 0 ).


0
投票

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

首先,实现一个类型来表示程序行为的完整描述:

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
列表,只需使用
foldr
foldl
:

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 的答案更通用,并且在提取详细值时可能很有用。这也明确地制定了标志的优先级,并方便地将所有更新操作捆绑在一起。

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

© www.soinside.com 2019 - 2024. All rights reserved.