Haskell - 根据某些条件过滤字符串列表

时间:2013-05-05 23:27:41

标签: string list haskell filter

我是这个社区的新手。我学习Haskell并且遇到Haskell编码问题。 我希望你能帮助我。

我在这里和谷歌搜索过,没有任何成功。

我的问题是fowllows: 我想编写一个函数,它将列表作为参数,如下所示:

myStringListFilter :: [String] -> [String]

处理以下步骤:

  1. 删除第一个字母

    myStringListFilter myList = map tail strListe myList
    
  2. 过滤列表中以“u”或“U”开头的每个元素。

    myStringListFilter myList = filter (´elem´ ['u', 'U']) (map tail strListe myList)
    
  3. 第二步不起作用。我收到错误。

    如果我需要以下内容,如何实现解决方案:

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

3 个答案:

答案 0 :(得分:8)

filter的类型是

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

因此,如果您想根据谓词过滤String列表,则需要一个函数String -> Bool,但您所写的内容(`elem` ['u',U'])的类型为Char -> Bool

所以你需要一个功能

beginsWithU :: String -> Bool

最简单的定义方法是

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

然后你误解了filter如何工作,保持满足谓词的元素,你想要删除它们,所以你需要用not来构造谓词(或直接定义为doesn'tbeginWithU。)

但是,作为7stud points 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 list,而drop 1 ""会产生""

但是,由于您希望保留原始列表元素,您还可以定义谓词以直接查看第二个字符,

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

myStringListFilter = filter (not . secondCharIsU)

答案 1 :(得分: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会更改原始字符串,因此过滤map'ed字符串列表将不会生成包含任何原始字符串的列表。操作系统需要使用自定义过滤器过滤原始列表

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'],与字符串“uU”相同。

答案 2 :(得分:1)

我也是初学者,所以也许我的解释会有所帮助。

  

重点是什么“。”意思是什么?例如,在这一行:

     

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

点做“功能组合”,其中:

(f1 . f2) xs 

定义为:

f1 (f2 xs) 

这意味着haskell在点的右侧获取函数f2,并将xs应用于它:

(f2 xs)

然后haskell获取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。 head将列表作为参数并返回列表的单个元素。部分功能:

(`elem` notAllowedChars) 

将左侧的一个元素作为参数,这正是head返回的内容,elem返回Bool。不要将Bool作为论据,例如是的,并返回Bool,例如假。请注意,当您将函数与点链接在一起时,必须确保点右侧的函数返回的任何内容都是点左侧函数接受的参数。

  
      
  1. 什么是“无点”?
  2.   

我认为这意味着在函数定义中没有指定参数。我喜欢把它想象为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)

但是tail将列表作为参数 - 而不是函数,因此会产生错误。但是,如果使用函数组合重写myfunc的右侧:

myfunc xs = (tail . head) xs

...然后再次取消双方的xs:

myfunc = tail . head

这又是点自由的风格。至于为什么你会用点自由风格来重写函数,我不确定。就目前而言,我认为这是我能欺骗的原因。你会发现,当你学习计算机编程语言时,你会学到很多技巧。有时候,当你学习它时,你不确定为什么一个技巧是有用的。你必须接受这样一个事实:作为一个初学者,你并不总是理解为什么一个技巧是有用的。直到你变得更有经验,某种技巧的有用性才会变得明显。

在任何情况下,以无点样式编写函数都不会改变函数的工作方式,因此如果您不理解它,请不要担心它。当你更多地研究Haskell时,你可以做一些更高级的事情。

  

我的目的是理解Haskell

你应该意识到1)在我看来,Haskell是一种极其困难的语言,2)你永远不会“知道”计算机编程语言。理解水平是无限的。因此,学习和使用语言的次数越多,学到的就越多。这意味着无论您使用何种语言,您仍然会遇到难以理解或无法理解的代码。

  

@ 7Stud

     

...没有产生正确的输出。

     

正如我上面所写,Daniel Fischer的代码与你的一样好。   你能告诉我你的意思吗?

我发布了Daniel Fischer的例子以及它产生的输出。如果将该输出与您在op中发布的输出进行比较,则它们不匹配。