雖然Willem Van Onsem和The Orgazoid的答案都很好(upvoted),但您也可以採用更通用的方式處理部分問題,而不僅僅是列表。
對於下面,你會需要這些進口:
import Control.Monad (MonadPlus, mfilter)
import Data.Maybe (fromMaybe, listToMaybe)
如果我理解正確的問題,你想嘗試的as
,bs
,並cs
所有組合。通常可以實現組合樣行爲與Applicative
類型類:
combinations = (,,) <$> as <*> bs <*> cs
(,,)
是創建三個單獨的值三元組(三元素的元組)的功能。
這適用於列表,因爲列表應用性:
*Prelude> (,,) <$> [1,2] <*> ["foo", "bar"] <*> [True, False]
[(1,"foo",True),(1,"foo",False),(1,"bar",True),(1,"bar",False),(2,"foo",True),(2,"foo",False),(2,"bar",True),(2,"bar",False)]
,但它也適用於例如Maybe
S:
*Prelude> (,,) <$> Just 1 <*> Just "foo" <*> Just False
Just (1,"foo",False)
有了這一點,你現在可以定義你的函數的核心:
try' :: MonadPlus m => ((a, a, a) -> Bool) -> m a -> m a -> m a -> m [a]
try' predicate as bs cs =
tripleToList <$> mfilter predicate combinations
where
combinations = (,,) <$> as <*> bs <*> cs
tripleToList (a, b, c) = [a, b, c]
你會發現,這個輔助功能是完全通用的。它適用於任何包含元素a
的任何MonadPlus
實例。
下面是一些例子:
*Answer> try' (const True) ["foo", "bar", "baz"] ["qux", "quux", "quuz", "corge"] ["grault", "garply"]
[["foo","qux","grault"],["foo","qux","garply"],["foo","quux","grault"],["foo","quux","garply"],["foo","quuz","grault"],["foo","quuz","garply"],["foo","corge","grault"],["foo","corge","garply"],["bar","qux","grault"],["bar","qux","garply"],["bar","quux","grault"],["bar","quux","garply"],["bar","quuz","grault"],["bar","quuz","garply"],["bar","corge","grault"],["bar","corge","garply"],["baz","qux","grault"],["baz","qux","garply"],["baz","quux","grault"],["baz","quux","garply"],["baz","quuz","grault"],["baz","quuz","garply"],["baz","corge","grault"],["baz","corge","garply"]]
*Answer> try' (const False) ["foo", "bar", "baz"] ["qux", "quux", "quuz", "corge"] ["grault", "garply"]
[]
*Answer> try' (const True) (Just "foo") (Just "bar") (Just "baz")
Just ["foo","bar","baz"]
*Answer> try' (const False) (Just "foo") (Just "bar") (Just "baz")
Nothing
你應該注意到,如果predicate
總是返回False
,你會得到任何回報。對於列表,你會得到空的列表;對於Maybe
,您從字面上得到Nothing
。
到目前爲止它都是通用的,但是checkIfCorrect
不是。它也看起來像你只想得到匹配的第一個元素。你可以做到這一點通過checkIfCorrect
組成try'
:
try :: [String] -> [String] -> [String] -> [String]
try as bs cs = fromMaybe [] $ listToMaybe $ try' isCorrect as bs cs
where isCorrect (a, b, c) = checkIfCorrect a b c
這裏,我以uncurry的checkIfCorrect
函數創建一個私有isCorrect
功能。然後,我使用listToMaybe
和fromMaybe
的組合返回結果列表的第一個元素。這裏的其他答案使用head
,但如果列表爲空,那麼將會拋出異常,所以我使用了這種組合,因爲它很安全。
您可能需要更改'try',以便返回類型是3值的元組而不是列表。通過這種方式很顯然,您期望列表中只有3個值。 – 4castle