我想在这样的情况下打破一个循环:
import Data.Maybe (fromJust, isJust, Maybe(Just))
tryCombination :: Int -> Int -> Maybe String
tryCombination x y
| x * y == 20 = Just "Okay"
| otherwise = Nothing
result :: [String]
result = map (fromJust) $
filter (isJust) [tryCombination x y | x <- [1..5], y <- [1..5]]
main = putStrLn $ unlines $result
想象一下,“tryCombination”比这个例子复杂得多。而且它消耗了大量的CPU功率。这不是对 25 种可能性的评估,而是 26^3。
因此,当“tryCombination”找到给定组合的解决方案时,它返回一个 Just,否则返回一个 Nothing。如何在第一个找到的解决方案上立即打破循环?
最佳答案
简单的解决方案:find
和 join
看起来您正在寻找 Data.List.find
. find
有类型签名
find :: (a -> Bool) -> [a] -> Maybe a
所以你会做类似的事情
result :: Maybe (Maybe String)
result = find isJust [tryCombination x y | x <- [1..5], y <- [1..5]]
或者,如果您不想要
Maybe (Maybe String)
(你为什么要这样做?),你可以用 Control.Monad.join
把它们折叠起来。 , 有签名join :: Maybe (Maybe a) -> Maybe a
所以你有
result :: Maybe String
result = join $ find isJust [tryCombination x y | x <- [1..5], y <- [1..5]]
更高级的解决方案:
asum
如果您想要更高级的解决方案,可以使用
Data.Foldable.asum
, 有签名asum :: [Maybe a] -> Maybe a
它的作用是挑出第一个
Just
值来自许多列表。它通过使用 Alternative
来做到这一点。 Maybe
的实例. Alternative
Maybe
的实例工作方式如下:(导入 Control.Applicative
以访问 <|>
运算符)λ> Nothing <|> Nothing
Nothing
λ> Nothing <|> Just "world"
Just "world"
λ> Just "hello" <|> Just "world"
Just "hello"
换句话说,它选择第一个
Just
两种选择的值(value)。想象把<|>
在列表的每个元素之间,以便[Nothing, Nothing, Just "okay", Nothing, Nothing, Nothing, Just "okay"]
被转向
Nothing <|> Nothing <|> Just "okay" <|> Nothing <|> Nothing <|> Nothing <|> Just "okay"
这正是
asum
功能呢!自 <|>
短路,它只会评估第一个 Just
值(value)。有了这个,你的功能就会很简单result :: Maybe String
result = asum [tryCombination x y | x <- [1..5], y <- [1..5]]
你为什么想要这个更高级的解决方案?它不仅更短;一旦你知道了这个习惯用法(即当你熟悉
Alternative
和 asum
时),只需阅读代码的前几个字符,就可以更清楚地了解函数的作用。
关于loops - Haskell:有条件地中断循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29648319/