我是这个社区的新手。我学习Haskell并且遇到Haskell编码问题。 我希望你能帮助我。
我在这里和谷歌搜索过,没有任何成功。
我的问题是fowllows: 我想编写一个函数,它将列表作为参数,如下所示:
myStringListFilter :: [String] -> [String]
处理以下步骤:
删除第一个字母
myStringListFilter myList = map tail strListe myList
过滤列表中以“u”或“U”开头的每个元素。
myStringListFilter myList = filter (´elem´ ['u', 'U']) (map tail strListe myList)
第二步不起作用。我收到错误。
如果我需要以下内容,如何实现解决方案:
Input: ["butter", "chees", "aUbergine", "egg", "milk", "bUbble", "curry"]
Output: ["chees", "egg", "milk"]
答案 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,例如假。请注意,当您将函数与点链接在一起时,必须确保点右侧的函数返回的任何内容都是点左侧函数接受的参数。
- 什么是“无点”?
醇>
我认为这意味着在函数定义中没有指定参数。我喜欢把它想象为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中发布的输出进行比较,则它们不匹配。