我有一个功能:
isItSimple :: Int -> Bool
它获得了Int并返回Bool。
我需要在[x |中找到第一个数字x< - [ n .. ],isItSimple x]。
这是我的解决方案:
findIt :: Int -> Int
findIt num
| isItSimple num = num
| otherwise = findIt (num + 1)
Haskell有没有更好的解决方案?
答案 0 :(得分:21)
我需要在[x |中找到第一个数字x< - [n ..],isItSimple x]。
就像你说的那样。
findIt n = head [ x | x <- [n..], isItSimple x ]
答案 1 :(得分:14)
虽然其他答案有效,但它们可能不是在Haskell中解决这个问题的最常用方法。你真的不需要任何额外的导入:Prelude中的一些函数可以解决这个问题。
首先创建一个大于或等于n
的所有简单数字的列表。函数filter :: (a -> Bool) -> [a] -> [a]
使这很容易:
filter isItSimple [n..]
与[n..]
类似,这是一个无限列表,但这不是问题,因为Haskell很懒,在需要之前不会评估任何内容。
为了得到你想要的东西,你可以把这个无限列表的头脑:
findIt :: Int -> Int
findIt n = head $ filter isItSimple [n..]
有些人不喜欢head
,因为它是部分功能,并且在给出空列表时会引发异常。我个人不会在此担心,因为我们知道永远不会在空列表中调用它。它让我比fromJust
更不舒服,这也是一个部分功能(当给出Nothing
时会引发异常)并且在我看来总是一个坏主意。
(谈到个人品味,我写的如下:
findIt = head . filter isItSimple . enumFrom
这是pointfree风格的一个例子,在我看来这可能会令人费解,但在这种情况下非常优雅。)
答案 2 :(得分:6)
在大多数情况下,特别是当您的问题是解决问题的特定情况时,明确的重新解决是不好的。不使用显式递归的问题的可能解决方案之一是:
import Data.List (find)
import Data.Maybe (fromJust)
findIt :: Int -> Int
findIt n = fromJust $ find isItSimple [n..]
答案 3 :(得分:1)
findIt :: Int -> Int
findIt num = head $ dropWhile (not isItSimple) [num..]
我不知道它是否更好。它刚刚出现在我的脑海里。
答案 4 :(得分:1)
另一种方法是使用最小定点组合器(在Data.Function中修复)
findIt = fix (\f x -> if isItSimple x then x else f (x + 1))
在这种情况下,它看起来有点过度设计,但如果“搜索空间”遵循比x + 1
更复杂的规则,这种技术可能非常有用。