2013-05-05 35 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中发布的输出进行比较,则它们不匹配。