Haskell:有条件地打破循环 [英] Haskell: Break a loop conditionally
问题描述
import Data.Maybe(fromJust,isJust,Maybe( Just))
tryCombination :: Int - > Int - >可能是String
tryCombination x y
| x * y == 20 =只需好
|否则= Nothing
结果:: [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 和加入
和加入
看起来您正在寻找 Data.List.find
。 find
具有类型签名
find ::(a - >布尔) - > [a] - >也许是
所以你可以做一些像
result :: Maybe(Maybe String)
result = find isJust [tryCombination xy | x < - [1..5],y < - [1..5]]
或者,如果你不想要 Maybe(Maybe String)
(你为什么?),你可以用 Control.Monad.join
,它有签名
join :: Maybe(也许a) - >也许是
,这样您就有了
result :: Maybe String
result = join $ find isJust [tryCombination xy | x < - [1..5],y < - [1..5]]
更高级的解决方案: asum
更高级的解决方案,您可以使用 Data.Foldable.asum
,它有签名
asum :: [也许a] - >可能是
它所做的是挑出第一个 Just
来自许多列表的值。它通过使用 Alternative 可能
的实例来实现。
Alternative > Maybe >可能是这样的:(import
Control.Applicative
来访问< |>
运算符)
λ> Nothing< |> Nothing
Nothing
λ> Nothing< |>只是世界
只是世界
λ>只是你好< |>只是世界
只是你好
换句话说, code>只有两个选项的值。想象一下,将< |>
放在列表的每一个元素之间,这样
$ 变成
Nothing< |> Nothing< |>只需好< |> Nothing< |> Nothing< |> Nothing< |>只要好
这正是 asum
功能呢!由于< |>
是短路,因此它只会评估第一个 Just
值。有了这个,你的函数就会像
result :: Maybe String
result = asum [tryCombination x y | x < - [1..5],y < - [1..5]]
为什么你想要这个更高级的解决方案?它不仅更短;一旦你知道了这个习惯用语(即当你熟悉 Alternative
和 asum
时),它更清楚地说明了这个功能通过阅读代码的前几个字符。
I want to break a loop in a situation like this:
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
Imagine, that "tryCombination" is a lot more complicated like in this example. And it's consuming a lot of cpu power. And it's not a evalutation of 25 possibilities, but 26^3.
So when "tryCombination" finds a solution for a given combination, it returns a Just, otherwise a Nothing. How can I break the loop instantly on the first found solution?
解决方案 Simple solution: find
and join
It looks like you're looking for Data.List.find
. find
has the type signature
find :: (a -> Bool) -> [a] -> Maybe a
So you'd do something like
result :: Maybe (Maybe String)
result = find isJust [tryCombination x y | x <- [1..5], y <- [1..5]]
Or, if you don't want a Maybe (Maybe String)
(why would you?), you can fold them together with Control.Monad.join
, which has the signature
join :: Maybe (Maybe a) -> Maybe a
so that you have
result :: Maybe String
result = join $ find isJust [tryCombination x y | x <- [1..5], y <- [1..5]]
More advanced solution: asum
If you wanted a slightly more advanced solution, you could use Data.Foldable.asum
, which has the signature
asum :: [Maybe a] -> Maybe a
What it does is pick out the first Just
value from a list of many. It does this by using the Alternative
instance of Maybe
. The Alternative
instance of Maybe
works like this: (import Control.Applicative
to get access to the <|>
operator)
λ> Nothing <|> Nothing
Nothing
λ> Nothing <|> Just "world"
Just "world"
λ> Just "hello" <|> Just "world"
Just "hello"
In other words, it picks the first Just
value from two alternatives. Imagine putting <|>
between every element of your list, so that
[Nothing, Nothing, Just "okay", Nothing, Nothing, Nothing, Just "okay"]
gets turned to
Nothing <|> Nothing <|> Just "okay" <|> Nothing <|> Nothing <|> Nothing <|> Just "okay"
This is exactly what the asum
function does! Since <|>
is short-circuiting, it will only evaluate up to the first Just
value. With that, your function would be as simple as
result :: Maybe String
result = asum [tryCombination x y | x <- [1..5], y <- [1..5]]
Why would you want this more advanced solution? Not only is it shorter; once you know the idiom (i.e. when you are familiar with Alternative
and asum
) it is much more clear what the function does, just by reading the first few characters of the code.
这篇关于Haskell:有条件地打破循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!