我知道这个问题以前已被问过很多次了,我已经仔细阅读了它们,但它并没有帮助我回答我的问题。我对Haskell很新,
假设我们有以下内容:
filter p [] = []
filter p (h:l) = if (p h) then (h:(filter p l)) else (filter p l)
如何调用过滤器?我所知道的是你通过了p
列表
老实说,我一般都不知道什么是多态类型,我无法弄清楚过滤函数的多态类型。
我没有事件理解函数过滤器在if语句中的作用。
如果你能帮我解决这两个问题,我将非常感激。
有足够的资源来解释多态性,但我不了解它们。
答案 0 :(得分:6)
p
不是列表。 p
是谓词的缩写 - 通常用于获取值并返回Bool
的函数的术语。列表是filter
的第二个参数。
你怎么称呼过滤器?你需要阅读那里的许多haskell书籍之一。马上。一些例子:
filter (> 5) [1, 6, 2, 8, 9, 3] -- [6, 8, 9]
filter (== 'z') "bazzz" -- "zzz" (String === [Char])
此处(> 5) :: Int -> Bool
和(== 'z') :: Char -> Bool
是谓词。
多态非常松散意味着它具有不同类型的相同形式:
filter :: (a -> Bool) -> [a] -> [a]
filter
必须适用于任何类型a
。因此,实现者不知道特定的a
,并且函数不能假设a
。 a
由呼叫站点的功能用户选择。
顺便说一下。这是一个有趣的小练习,可以确定允许执行以下功能:
:: a -> a
(提示:它只能做一件事,名字就把它拿走了,所以我把它留了出来)
您还可以将filter
视为一系列功能完全相同且仅在a
中有所不同。其中一些可能是:
:: (Int -> Bool) -> [Int] -> [Int]
:: (Char -> Bool) -> [Char] -> [Char]
:: (Foo -> Bool) -> [Foo] -> [Foo]
在学习新概念时,开始并不是一个好的开始。你应该抓一本好书。
答案 1 :(得分:4)
在了解有关实施的任何细节之前,我们应该确定filter
应该是什么类型。实际上,您通常应该设计函数的类型签名,而不必编写任何实际代码......但损坏已在此处完成。 (正如Chi所言,你可以在这一点上实际问GHCi 你的实现类型是什么......但是,这又是向后的,所以我不会深入研究它。 )
那么你想要filter
完成什么?确实应该列出一个清单。您希望根据每个元素可能具有的某些属性来提取该列表的某些元素;但是filter
不应该有任何难以理解的假设,使用什么标准,即它应该是任何类型的元素列表的类型。在Haskell中,我们写了[a]
(这实际上是∀ a . [a]
的简写,将其读作“对于您可能考虑的所有元素类型 - 例如,A
- 它是一个列表类型[A]
“)。
然后应该通过一个额外的参数来确定实际标准:过滤谓词。例如,您可能希望从整数列表中筛选小于5
的所有数字 - 您使用谓词(<5) :: Int -> Bool
。通常,对于[a]
列表,您需要一个类型为a -> Bool
的谓词。最终结果将与您传入的列表元素相同,因此filter
将具有签名
filter :: [a] -> (a -> Bool) -> [a]
...除了惯例之外,我们首先把谓词,即
filter :: (a -> Bool) -> [a] -> [a]
让我们检查一下是否有意义......例如,我们想要
> filter ((<5) :: Int -> Bool) ([4,9,3] :: [Int])
在这种情况下a ~ Int
如此
filter :: (Int -> Bool) -> [Int] -> [Int]
...是的,这很有意义。
现在你开始真的担心实施。有两种通用方法:
解构列表。基本上,列表只有两种方式:它可以包含某些内容,也可以为空。空是很容易的,因为在这种情况下你不可能再返回一个空列表。您甚至无法使用谓词,因为 没有您可以检查的元素,因此只需通过匹配_
将其丢弃:
filter _ [] = []
(或者你也可以这样,你也可以将谓词与p
匹配,但人们会想知道: the mouse p
发生了什么? )
如果列表不为空,我们可以直接弹出一个元素:
filter p (h:l) = …
此处,h
是头元素,l
是列表的其余部分。太棒了,我们现在有一个a
类型的元素,让我们看看谓词告诉我们的内容!
filter p (h:l) = if p h then … else …
因此,如果谓词已经完成,我们希望在最终结果中再次看到h
,我们不会?实际上,最终结果应该以h
开始,因此
filter p (h:l) = if p h then h : … else …
最终结果的其余部分应该与输入列表的其余部分有关。我们可以传递then h : l else …
,但这意味着我们只能控制头元素的条件。不,我们仍然需要过滤列表的其余部分:
filter p (h:l) = if p h then h : filter p l else …
事实上,即使h
没有达到谓词,我们也希望这样做,除非我们不加前缀:
filter p (h:l) = if p h then h : filter p l else filter p l
然后你去了:
filter _ [] = []
filter p (h:l) = if p h then h : filter p l else filter p l
这个if
看起来有点笨拙,首选的语法实际上是 guards (它做同样的事情)
filter _ [] = []
filter p (h:l)
| p h = h : filter p l
| otherwise = filter p l