我有一个表示命令行选项的数据类型:
data Flag = Verbose | Help | Buffer Int deriving (Show, Eq)
程序运行时,我得到Flag
的列表,与用户指定的选项相对应。例如,[Buffer 10, Verbose]
。
我的问题是,从Int
中的Buffer
提取[Flag]
值的最佳方法是什么?
该列表甚至可能没有Buffer
。
我要提出的只是某种复杂的遍历/折叠,它使用case
语句从其他Buffer
中过滤出Flag
。
答案 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
的列表,只需使用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的回答更为笼统,在提取详细程度值时可能很有用。这也明确表示了标志的优先级,并方便地将所有更新操作捆绑为一个。
此外,如果您想了解更多有关此功能的一般实现方法,建议您熟悉镜头和其他光学器件。