如果我使用"[xs]"而不是"xs",为什么这个功能不起作用?

pee*_*ngh 2 haskell

split :: [a] -> Int -> ([a], [a])
split [xs] n = 
    (take n [xs], drop n [xs])
Run Code Online (Sandbox Code Playgroud)

如果我将变量xs改为代替,则相同的代码可以工作[xs],签名在两种情况下都相同.使用[xs]给出了模式非穷举的错误.我理解这说明我提供的输入不在我的代码中,但不清楚幕后发生了什么.

测试输入:[1,2,3] 2.

Wil*_*sem 11

不知何故,很多人都认为[xs]模式意味着你统一了一个列表xs.但这是不正确的,因为函数签名(隐式派生或明确声明)已经阻止您编写使用非列表项调用函数的代码.

列表有两个构造函数:

  • 空列表[]; 和
  • 的"缺点" (h : t)h所述头部(第一元件),并且t所述尾部(与其余元素的列表).

然而,Haskell也引入了一些语法糖.例如[1],简称(1:[])[1, 4, 2]for (1:(4:(2:[]))).

因此,这意味着,如果你写的[xs],窗帘后面你定义的模式(xs: [])这从而意味着你匹配所有名单正好一个元素,而单元素(而不是整个列表)然后xs.

无论如何,解决方案是使用:

split xs n = (take n xs, drop n xs)
Run Code Online (Sandbox Code Playgroud)

由于这两个take :: Int -> [a] -> [a]drop :: Int -> [a] -> [a]在该签名有xs应该是一个列表,哈斯克尔会自动推导n应该是一个Int,和xs一个[a].

请注意,您也可以使用splitAt :: Int -> [a] -> ([a], [a]).我们可以使签名等同于您所定位的签名:

split = flip splitAt
Run Code Online (Sandbox Code Playgroud)

  • 我实际上更喜欢你的评论,因为它非常清楚地向我解释了(或我的)问题。认为这是一个典型的初学者问题,部分原因是在函数签名中 [a] 表示一个列表,而代码中的相同 ([a]) 表示一个包含单个值的列表! (2认同)