2010-12-03 134 views
4

我有一個函數:do while循環在Haskell

isItSimple :: Int -> Bool 

它得到詮釋,並返回布爾。

我需要找到第一個在[x | x < - [n ..],isItSimple x]。

這裏是我的解決方案:

findIt :: Int -> Int 
findIt num 
     | isItSimple num = num 
     | otherwise = findIt (num + 1) 

是否有哈斯克爾任何更好的解決方案?

回答

6

在大多數情況下,尤其是當您的問題是解決問題的特定情況時,顯式拒絕是不好的。一個不使用明確的遞歸您的問題可能的解決方案是:

import Data.List (find) 
import Data.Maybe (fromJust) 

findIt :: Int -> Int 
findIt n = fromJust $ find isItSimple [n..] 
+0

這不是取決於問題和解決方案的複雜性嗎?如果顯式遞歸比知道find和fromJust簡單,那麼不應該使用顯式遞歸嗎? – Jaywalker 2010-12-03 10:29:04

+0

@Jaywalker:完全一樣,更優雅。 – 2010-12-03 10:30:39

+0

任何人都可以詳細說明「顯式遞歸是不好的」的意思。表現不佳? Uglyness? – 2012-12-10 00:37:49

1
findIt :: Int -> Int 
findIt num = head $ dropWhile (not isItSimple) [num..] 

我不知道是否更好。它出現在我的腦海裏。

+0

應該是`(不是isItSimple)`,用點(函數組合)。 – 2014-05-08 07:52:48

20

我需要找到[X 第一號| x < - [n ..],isItSimple x]。

就像你說的那樣。

findIt n = head [ x | x <- [n..], isItSimple x ] 
13

雖然其他答案的工作,他們可以說是不是在哈斯克爾解決這個問題最常用的方式。你並不需要任何額外的輸入: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風格,這可以得到令人費解的一個例子,但在這種情況下,很優雅,在我看來。 )

1

另一種方法是使用最少的定點組合器(在Data中修復。功能)

findIt = fix (\f x -> if isItSimple x then x else f (x + 1)) 

在這種情況下,它看起來有點過度設計,但如果「搜索空間」遵循一個更復雜的規則比x + 1這個技術是非常有用的。