繁体   English   中英

如何在haskell的函数参数中传递列表?

[英]How do you pass list in a function parameter in haskell?

我知道这个问题以前已经被问过很多次了,我已经仔细阅读了,但并不能帮助我回答这类问题。 我是Haskell的新手,

假设我们有以下内容:

filter p [] = []
filter p (h:l) = if (p h) then (h:(filter p l)) else (filter p l)

我有两个问题

  1. 如何调用过滤器? 我所知道的是,您通过了p ,这是一个列表

  2. 老实说,我一般不知道什么是多态类型,而且我无法弄清楚过滤器函数的多态类型。

我不了解if语句中函数过滤器的作用。

如果您能在这两个问题上协助我,我将不胜感激。

有很多资源可以解释多态性,但是我不理解它们。

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]

在学习新概念时,SO并不是一个很好的起点。 你真的应该抓一本好书。

在深入了解实现之前,我们应该确定filter的类型。 实际上,您通常应该设计函数的类型签名,而无需编写任何实际代码……但是损坏已经在这里完成了。 (谨此陈辞,您现在可以实际询问GHCi 您的实现类型是什么……但是同样,这是倒退的,所以我不会深入研究它。)

那么,您希望filter完成什么工作? 确实应该列出一个清单。 您想根据每个元素可能具有的某些属性来提取该列表中的某些元素。 但是filter不应该有任何难以理解的假设,即要使用什么条件,即应该是任何元素类型的列表的类型 在Haskell中,我们将其写为[a] (实际上是∀ a . [a]简写,请读成“对于您可能考虑的所有元素类型-例如A –这是[A]类型的列表”)。

然后,应通过一个额外的参数确定实际标准是什么: 过滤谓词 例如,您可能要从整数列表中过滤所有小于5数字–您可以使用谓词(<5) :: Int -> Bool 通常,对于您的[a]列表,您需要使用a- a -> Bool类型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 ,但是人们会怀疑:发生了什么 鼠标 p ?)

    如果列表不为空,则可以从其中直接弹出一个元素:

     filter p (h:l) = … 

    在这里, h是头元素, l是列表的其余部分。 太好了,我们现在有了一个类型a的元素,让我们看看谓词告诉我们的内容!

     filter p (h:l) = if ph then … else … 

    因此,如果谓词得到满足,我们希望在最终结果中再次看到h ,不是吗? 实际上,最终结果应以h 开头

     filter p (h:l) = if ph then h : … else … 

    最终结果的其余部分应与输入列表的其余部分有关。 我们可以照原样传递then h : l else … ,但这意味着我们只能控制head元素的条件。 不,我们仍然必须过滤列表的其余部分:

     filter p (h:l) = if ph then h : filter pl else … 

    实际上,即使谓词没有满足h ,我们也想这样做,除非我们不添加它:

     filter p (h:l) = if ph then h : filter pl else filter pl 

然后你去了:

filter _ [] = []
filter p (h:l) = if p h then h : filter p l else filter p l

if看起来有些笨拙,则首选语法实际上是警卫 (它们执行相同的操作)

filter _ [] = []
filter p (h:l)
 | p h        = h : filter p l
 | otherwise  = filter p l

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM