Haskell函数定义不如预期地工作。

3

我是一名新手,正在学习函数式编程和Haskell。以下定义有何问题还不确定:

在test.h中的函数定义

drop5 [a]  = drop 5 [a] 

尝试使用这个函数时,我遇到了程序错误。
$:load test.h
$drop5 [2,3,4,5,6,7,8]
Program error: pattern match failure: drop5 [2,3,4,5,6,7,8]
$:t drop5
drop5 :: [a] -> [a]

当我将定义更改为以下内容时,它可以正常工作;意思是它接受一个列表,并丢弃列表的前五个元素。
drop5 ns = drop 5 ns

在这种情况下,当我查看打印类型时,我看到:

$:t drop5
drop5 :: [a] -> [a]

我不确定为什么第一个定义和第二个不同?而“程序错误:模式匹配失败”错误的含义是什么?

3个回答

5
在第一个定义中,[a]是只匹配一个元素的列表模式,这个元素在规则的右侧被称为a
因此,您定义的函数只接受单元素列表。
此外,从仅有一个元素的列表中删除5个元素显然会导致空列表(任何正数的元素删除都会导致空列表)。

有道理。谢谢你!! 我尝试了drop5 [2],没有返回任何错误。 - patronus

4

你的函数定义:

drop5 [a] = drop 5 [a]

指定该从句仅适用于恰好具有 一个 元素的列表。实际上,在函数定义中,[a] 不是参数的类型,它是 模式。模式 [a] 意味着我们正在处理仅包含一个元素的列表。

如果您使用 -Wall 编译,则会得到:

<interactive>:1:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘drop5’:
        Patterns not matched:
            []
            (_:_:_)

编译器/解释器因此产生了一个警告,即两个模式没有被覆盖:一个是针对列表的模式,另一个是针对两个或更多元素的列表的模式。

有趣。编译器如何知道这是模式还是参数?此外,我正在使用hugs98开始(这是edx函数式编程课程上推荐的)。我不确定如何在这里编译文件。 - patronus
1
@patronus:参数就是一个模式。但是,您可以在头部使用模式。在这种情况下,如果匹配模式,则触发该行。模式匹配是几乎所有函数式编程语言共享的一个方面。 - Willem Van Onsem

2

[a] 告诉 Haskell 列表中只有一个元素,而 ns 告诉 Haskell 在完成函数并确定输出和输入类型之前,它可以是任何东西(甚至是布尔值)。您还可以通过在该行上方添加以下内容明确告译 Haskell 输入和输出类型:

drop5 :: [Integer] -> [Integer]

你可以在GHCI中通过执行:t drop5来查找它。

另外,顺带一提,这段代码可以被简化。只需将其改为:

drop5 = drop 5

现在这句话可能对你来说没有意义,但是随着你学习的深入,你应该会发现Haskell中所有的函数都只有一个参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接