5

我是这个社区的新人。我学习 Haskell,但在使用 Haskell 编码时遇到了困难。我希望你能帮助我。

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

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

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"]
4

3 回答 3

9

的类型filter

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

因此,如果您想String根据谓词过滤 s 列表,则需要一个 function String -> Bool,但您编写的内容(`elem` ['u',U'])具有 type Char -> Bool

所以你需要一个函数

beginsWithU :: String -> Bool

定义它的最简单方法是

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

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

但是,正如7stud 指出的那样,您实际上并不想更改要从原始列表中保留的元素,什么

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

或者,无点:

myStringListFilter = filter (not . beginsWithU) . map tail

会实现。因此,您也需要将 thetail合并到谓词中,并且不需要 no map,这将产生

myStringListFilter = filter (not . beginsWithU . tail)

String或者,如果应该善意地处理输入列表中出现空的可能性,

myStringListFilter = filter (not . beginsWith . drop 1)

因为tail ""会产生一个*** Exception: Prelude.tail: empty listwhiledrop 1 ""产生"".

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

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

myStringListFilter = filter (not . secondCharIsU)
于 2013-05-05T23:35:58.613 回答
5

建议的解决方案:

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 会更改原始字符串,因此过滤已映射字符串的列表不会生成包含任何原始字符串的列表。op 需要使用自定义过滤器过滤原始列表

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”是一样的。

于 2013-05-06T06:03:01.537 回答
1

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

“。”有什么意义?意思是什么,它叫什么?例如在这一行:

filterBy notAllowedChars = 不。( elemnotAllowedChars)。头 。尾巴

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

(f1 . f2) xs 

定义为:

f1 (f2 xs) 

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

(f2 xs)

然后 haskell 将 f2 的返回值应用到 f​​1:

f1 retValFromf2

这是一个使用函数组合的简单示例:

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

dostuff x = (func1 . func2) x

ghci> dostuff 0
20

过滤器在这里是如何工作的?我在这一行中看不到任何过滤器功能:

filterBy notAllowedChars = 不。( elemnotAllowedChars)。头 。尾巴

该函数创建一个过滤器。该函数替代了我首先提供的非点自由函数:

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。not 将 Bool 作为参数,例如 True,并返回 Bool,例如 False。请注意,当您将函数与点链接在一起时,您必须确保点右侧的函数返回的任何内容都是点左侧的函数接受的参数。

  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)

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

myfunc xs = (tail . head) xs

…然后你可以再一次从两边取消 xs:

myfunc = tail . head

这又是无点风格。至于为什么您会费心以无点样式重写函数,我不确定。现在,我认为这是我可以做的。你会发现,当你学习一门计算机编程语言时,你会学到很多技巧。有时,当你学习一个技巧时,你不确定为什么它是有用的。你只需要接受这样一个事实,作为初学者,你并不总是能理解为什么一个技巧是有用的。直到你变得更有经验,某个技巧的用处才会变得明显。

无论如何,以无点风格编写函数不会改变函数的工作方式,所以如果您不理解它,请不要担心。随着你更多地学习 Haskell,你可以做一些更高级的事情。

我的目的是理解 Haskell

您应该意识到 1) 在我看来,Haskell 是一种极其困难的语言,2) 您永远无法“了解”一门计算机编程语言。理解的层次是无限的。因此,您学习和使用语言的次数越多,您对它的了解就越多。这意味着无论您在语言方面有多专家,您仍然会遇到难以理解或无法理解的代码。

@7螺柱

...不产生正确的输出。

正如我在上面写的,Daniel Fischer 的代码和你的一样工作得很好。你能告诉我你的意思吗?

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

于 2013-05-07T03:33:27.220 回答