Haskell:有条件地打破循环 [英] Haskell: Break a loop conditionally

查看:158
本文介绍了Haskell:有条件地打破循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆