我是 Haskell 的初学者,我正在尝试在列表的末尾添加一个元素。
我输入一个列表,如 [1,2,3,4] 和一个数字 10。我想要这样的输出 [1,2,3,4,10]。
我的代码:
func a [] = a
func a (x:xs) = x : func a (x:xs)
Run Code Online (Sandbox Code Playgroud)
但我收到了那个错误:
Non type-variable argument in the constraint: Num [a]
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a. (Num a, Num [a]) => [a]
Run Code Online (Sandbox Code Playgroud)
谁能帮忙解释一下?
小智 11
一个简单的非递归方法怎么样:
func num xs = xs ++ [num]
Run Code Online (Sandbox Code Playgroud)
或者如果你坚持递归:
func num [] = [num]
func num (x:xs) = x : func num xs
Run Code Online (Sandbox Code Playgroud)
您需要了解等号左侧的函数定义发生了什么是“模式匹配”。
通过以下声明,您基本上是在说
func a [] = a
...
Run Code Online (Sandbox Code Playgroud)
我想首先接受任何类型的元素,即a, 作为第一个参数,以及一个空列表作为第二个参数,即[]. 如果是这种情况,您想返回a. 问题是,您想返回一个列表[a](稍后您将在本答案中看到原因)。
对于函数定义的第二部分(这意味着第一个“模式”与您的输入不匹配),您是在说:我接受任何类型的元素,即a,以及一个非空列表,即(x:xs)。(x:xs)是一种说法:好的,我有一个列表并且x是该列表的第一个元素。我调用的列表的其余部分xs可能是空的;在这种情况下,您的原始列表将是大小为 1 的列表,即[x].
...
func a (x:xs) = x : func a (x:xs)
Run Code Online (Sandbox Code Playgroud)
如果模式匹配,您返回的内容是
... = x : func a (x:xs)
Run Code Online (Sandbox Code Playgroud)
这意味着您将列表的第一个元素作为第二个参数(即x)传递,并将其添加到func a (x:xs).
鉴于您的问题的这种描述,这里有一个可能的解决方案:
func a [] = [a]
func a (x:xs) = x : func a xs
Run Code Online (Sandbox Code Playgroud)
我想在这里说明两件事。在第一个模式中,即func a [] = [a],我返回一个列表,即[a]。在第二种模式中,我传递xs给func,即func a xs。在这两种情况下,我都会返回一个列表!
为什么这样做?让我们看一个例子。假设您调用funclike func 3 [1, 2]。那么这就是会发生的事情。
由于[1, 2]不是空列表,您不匹配第一个模式,所以让我们看看第二个;是的,我们与第二个比赛。现在我们有了a = 3, x = 1(列表的开头)和xs = [2]。所以我们有1 : func 3 [2]. 所以我们递归!我们现在有a = 3(和以前一样),x = 2和xs = [](即一个空列表)。所以我们继续处理函数体,我们这样做2 : func 3 []。最后,func 3 []匹配第一个模式,然后返回[3]。但是为了什么?那么,to 2 : [3],返回到什么?到1 : 2 : [3].