2013-05-05 76 views
2

我是這個社區中的新人。我學習Haskell並且在Haskell編碼方面遇到困難。 我希望你能幫助我。哈斯克爾 - 根據一些條件篩選字符串列表

我在這裏和谷歌搜索,沒有任何成功。

我的問題IST爲fowllows: 我想編寫一個函數,它接受一個列表作爲參數是這樣的:

myStringListFilter :: [String] -> [String] 

過程中的以下步驟:

  1. 刪除第一個字母

    myStringListFilter myList = map tail strListe myList 
    
  2. 過濾列表中的每個元素以「u」或「U」開頭。

    myStringListFilter myList = filter (´elem´ ['u', 'U']) (map tail strListe myList) 
    

第二步不起作用。我得到錯誤。

如何實現的解決方案,如果我想以下幾點:

Input: ["butter", "chees", "aUbergine", "egg", "milk", "bUbble", "curry"] 

Output: ["chees", "egg", "milk"] 

回答

8

類型的filter

filter :: (a -> Bool) -> [a] -> [a] 

,所以如果你想要過濾的根據String s到一個列表謂詞,你需要一個函數String -> Bool,但是你寫的是(`elem` ['u',U'])Char -> Bool

所以你需要一個功能

beginsWithU :: String -> Bool 

界定它是

beginsWithU (c:_) = c == 'u' || c == 'U' 
beginsWithU _ = False      -- empty list 

然後你誤會filter是如何工作的,它保持滿足謂詞的元素,你想要的最簡單的方法刪除它們,所以你需要用not(或者直接定義爲doesn'tbeginWithU)組成謂詞。

然而,隨着7studpoints out,你實際上並不想改變你希望從原始列表保持的元素,什麼

myStringListFilter myList = filter (not . beginsWithU) (map tail myList) 

,或者點免費電話:

myStringListFilter = filter (not . beginsWithU) . map tail 

會實現。所以,你需要納入tail到謂語過了,不需要map,這將產生

myStringListFilter = filter (not . beginsWithU . tail) 

,或者,如果一個空String發生在輸入列表中的可能性,應親切地予以處理,

myStringListFilter = filter (not . beginsWith . drop 1) 

因爲tail ""會產生一個*** Exception: Prelude.tail: empty listdrop 1 ""產生""

但是,只要你想保持原來的列表元素,你也可以定義謂詞直接看第二個字符,

secondCharIsU :: String -> Bool 
secondCharIsU (_:c:_) = c == 'u' || c == 'U' 
secondCharIsU _  = False 

myStringListFilter = filter (not . secondCharIsU) 
+0

你應該寫'startsWithU(h:c:_)= c =='u'|| c =='U'代替'startsWithU(c:_)= c =='u'|| c =='U'',然後以'myStringListFilter = filter(not。beginsWithU)結束''或者我沒有達到你的答案的目的。 – zurgl 2013-05-06 12:32:47

+2

@zurgl然後我不會稱之爲'startsWithU',我在問題中被引用爲'map tail',並且沒有仔細觀察所需的輸出。 – 2013-05-06 12:38:47

3

提出的解決方案:

beginsWithU (c:_) = c == 'u' || c == 'U' 
beginsWithU _ = False  

myStringListFilter myList = filter (not . beginsWithU) (map tail myList) 


ghci>myStringListFilter ["butter", "cheese", "aUbergine", "egg", "milk", "bUbble", "curry"] 
["heese","gg","ilk"] 

.. 。不會產生正確的輸出。

map更改原始字符串,因此,過濾映射字符串列表不會生成包含任何原始字符串的列表。該運算需要與自定義過濾器來過濾原始列表

myFilter :: String -> String -> Bool 
myFilter notAllowedChars str = 
    if head (tail str) `elem` notAllowedChars 
    then False --if match, reject this string 
    else True  --if no match, include this string in result list 


ghci>filter (myFilter "uU") ["butter", "cheese", "aUbergine", "egg", "milk", "bUbble", "curry"] 
["cheese","egg","milk"] 

點免費:

filterBy :: String -> String -> Bool 
filterBy notAllowedChars = 
    not . (`elem` notAllowedChars) . head . tail 

記住,字符,例如[「U」,「U」的陣列]與String「uU」是一樣的。

+0

你的權利,這更專門化的一行'過濾器((/ =)'你')。請注意,尾部不安全,那麼如果遇到空字符串,它將失敗'***例外:Prelude.tail:空列表'。像這樣管理它'過濾(\ x - >(null $ x)||((/ =)'u'。(toLower.head。tail)$ x))''''或者你可以在調用它之前過濾列表使用'filer(非null)'。我是你知道的,但是OP可能不是。 – zurgl 2013-05-06 12:24:35

+0

看上去很好,我沒有仔細觀察期望的輸出。 – 2013-05-06 12:29:07

1

我也是初學者,所以也許我的解釋會有所幫助。

點「。」是什麼意思?是什麼意思?例如,在此行中:

filterBy notAllowedChars = not。 (elem notAllowedChars)。頭。尾

的點做「功能成分」,其中:

(f1 . f2) xs 

被定義爲:

f1 (f2 xs) 

這也就意味着,Haskell中呈現的右手側的功能點f2,並將xs應用於它:

(f2 xs) 

然後哈斯克爾需要的F2的返回值,並將其應用於F1:

f1 retValFromf2 

下面是使用功能組成一個簡單的例子:

func1 x = x * 2 
func2 x = x + 10 

dostuff x = (func1 . func2) x 

ghci> dostuff 0 
20 

又如何過濾器在這裏工作?我沒有在這一行看到任何過濾功能:

filterBy notAllowedChars = not。 (elem notAllowedChars)。頭。尾部

該函數創建一個過濾器。這個函數是我第一次提供的非點免費功能的替代品:

myFilter :: String -> String -> Bool 
myFilter notAllowedChars str = 
    if head (tail str) `elem` notAllowedChars 
    then False --if match, reject this string 
    else True  --if no match, include this string in result list 

所以我應該有一個名爲點免費功能較好:

createFilter notAllowedChars = not . (`elem` notAllowedChars) . head . tail 

你所看到的右邊是一個鏈的函數組合,最右邊的函數tail,首先執行。 tail將一個列表作爲參數並返回一個列表。返回的列表然後應用於頭部。 head將列表作爲參數並返回列表中的單個元素。部分函數:

(`elem` notAllowedChars) 

將左邊的單個元素作爲參數,這正是頭部返回值,elem返回Bool。不需要Bool作爲參數,例如真,並返回一個Bool,例如假。請注意,當您將函數與點鏈接在一起時,您必須確保點的右側的函數返回的任何內容都是點左側的函數接受的參數。

  1. 什麼是實際上「無點」?

我認爲這意味着在函數定義中沒有指定參數。我喜歡將它看作xs是點的列表,並且當xs項沒有出現在函數定義的任何位置時,那麼您已經用點自由樣式編寫了該函數。點不是 '點'。如果點是'一個點',那麼類似這樣的東西:

not . (`elem` notAllowedChars) . head . tail 

......很難被稱爲'免費點'。

在Haskell,如果你有這樣定義一個函數:

myfunc xs = head xs 

其中XS在右邊出現在平等的雙方簽訂,然後就像一個公式,你可以取消出來生產:

myfunc = head 

然後,如果你撥打:

myfunc xs 

你得到的結果是相同的與原始的myfunc定義。

現在看這個函數定義:

myfunc xs = tail (head xs) 

在這種情況下,如果您從兩側XS你:

myfunc = tail (head) 

但尾取一個列表作爲argument--不是一個函數,所以會產生一個錯誤。但是,如果您使用改寫函數組合MYFUNC的右邊:

myfunc xs = (tail . head) xs 

...然後再次你可以從兩側取消XS:

myfunc = tail . head 

這是再次指向自由的風格。至於你爲什麼會用點自由風格重寫一個函數,我不確定。現在,我認爲這是我可以做的。你會發現,當你學習計算機編程語言時,你會學到一些技巧。有時候,你不確定爲什麼一個技巧在你學習時有用。你只需要接受這樣一個事實:作爲初學者,你並不總是理解爲什麼一個技巧是有用的。直到你變得更有經驗,某種把戲的有用性纔會變得明顯。

在任何情況下,使用免費樣式編寫函數都不會改變函數的工作方式,所以如果您不理解它,請不要擔心。當你更多地學習Haskell時,你可以做一些更高級的事情。

我的目的是comprehens哈斯克爾

你應該認識到:1)在我看來,Haskell是一個非常難學的語言,2)你永遠無法「知道」的計算機編程語言。理解水平是無限的。所以你學習和使用語言越多,你對它的瞭解就越多。這意味着無論您的語言多麼專業,您仍然會遇到難以理解或無法理解的代碼。

@ 7Stud

...不會產生正確的輸出。

正如我上面所寫,Daniel Fischer的代碼與您的代碼一樣正常工作。 你能告訴我你的意思嗎?

我發佈了Daniel Fischer的例子和它產生的輸出。如果您將該輸出與您在op中發佈的輸出進行比較,則它們不匹配。