split :: [a] -> Int -> ([a], [a])
split [xs] n =
(take n [xs], drop n [xs])
如果我将变量设为xs
而不是[xs]
,则相同的代码有效,两种情况下的签名都相同。使用[xs]
会产生错误,即模式并非详尽无遗。我理解它告诉我,我提供的输入不在我的代码中,但不清楚幕后发生了什么。
测试输入:[1,2,3] 2
。
答案 0 :(得分:10)
不知何故,很多人认为[xs]
作为模式意味着您统一列表xs
。但这是不正确的,因为函数签名(隐式派生或明确说明)已经阻止您编写使用非列表项调用函数的代码。
列表中有两个构造函数:
[]
;和(h : t)
h
head (第一个元素),t
tail (包含其余元素的列表)。< / LI>
[1]
是(1:[])
的缩写,[1, 4, 2]
是(1:(4:(2:[])))
的缩写。
这意味着如果你写下[xs]
,在窗帘后面你定义了一个模式(xs: [])
,这意味着你匹配所有列表完全一个元素,那个单一元素(不是整个列表)是xs
。
无论如何,解决方案是使用:
split xs n = (take n xs, drop n xs)
由于take :: Int -> [a] -> [a]
和drop :: Int -> [a] -> [a]
都在签名中xs
应该是一个列表,Haskell会自动导出n
应该是Int
1}},xs
和[a]
。
请注意,您也可以使用splitAt :: Int -> [a] -> ([a], [a])
。我们可以使签名等同于您目标的签名:
split = flip splitAt