Haskell 调用多个参数时的列表理解非穷举模式
Haskell List Comprehension Non-exhaustive pattern when calling more than one parameter
首先,我创建了一个 StudentMark 类型,它是一个元组,首先是一个字符串,其次是一个整数。
type StudentMark = (String, Int)
这是我的 capMarks 函数:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
这是我的 capMark 函数:
capMark :: StudentMark -> StudentMark
capMark (st, mk)
| mk > 39 = (st, 40)
| mk < 40 = (st, mk)
应该是return:
[("Jo", 37), ("Sam", 40)]
来自:
capMarks [("Jo", 37), ("Sam", 76)]
但是当我只向函数输入 1 个参数时,只会 return 正确和预期的响应,例如:
capMarks [("Jake", 50)]
或
capMarks [("Jake"), 30]
但是按预期使用两个(或更多)只会告诉我 capMarks 函数中有一个非详尽模式。
您应该检查 Haskell 中模式匹配的工作原理。
capMarks [x]
只会匹配一个包含一个元素的列表。您可能想要的是 capMarks myList = [ ... | ... <- f myList]
或以递归方式定义其余情况。
例如
capMarks [] = []
capMarks x:xs = capMark x : capMarks xs
这个简化的 "version" 在拥抱中有效
capMarks :: [Integer] -> [Integer]
capMarks xs = [(*) 2 x | x <- xs]
让我们分析一下您的 capMarks
函数:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
首先capMarks [cMarks] = ...
是模式匹配。这匹配包含单个元素的列表。我假设您想对整个列表执行某些操作,因此将其更改为 capMarks cMarks = ...
下一步 ... [(st, mk) | (st, mk) <- [capMark cMarks]]
将把 capMark
函数应用于原始模式匹配方案中的唯一元素,然后将结果作为列表的唯一元素。您似乎想要将 capMark
应用于列表的每个元素。所以如果我们按照前面的建议,你需要做类似 ... [capMark mark | mark <- cMarks]
的事情。这完全如前所述:将 capMark
应用于 cMarks
列表的每个元素。
最终版本:
capMarks :: [StudentMark] -> [StudentMark]
capMarks cMarks = [capMark mark | mark <- cMarks]
或者,您也可以使用模式匹配和显式递归:
capMarks [] = []
capMarks (x:xs) = capMark x : capMarks xs
第一行说capMarks
应用于空列表是一个空列表。第二行说 capMarks
应用于至少有一个元素的列表,将 capMark
应用于第一个元素,然后递归地将 capMarks
应用于列表的其余部分。
这是 Haskell 中的一种常见模式,因此有一个名为 map
的函数对其进行了概括。使用 map
非常简单:
capMarks cMarks = map capMark cMarks
map
有类型 (a -> b) -> [a] -> [b]
这意味着它接受一个函数和一个列表, returns 一个列表。 (a
和 b
只是告诉编译器哪些类型必须相同。)map
然后将函数应用于输入列表中的每个元素。
最终您将了解偏函数应用和 point-free 风格。有了这两个概念,使用map
的版本可以稍微简化一下:
capMarks = map capMark
暂时不要太担心这个。为了完整起见,我将其添加到此处。
首先,我创建了一个 StudentMark 类型,它是一个元组,首先是一个字符串,其次是一个整数。
type StudentMark = (String, Int)
这是我的 capMarks 函数:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
这是我的 capMark 函数:
capMark :: StudentMark -> StudentMark
capMark (st, mk)
| mk > 39 = (st, 40)
| mk < 40 = (st, mk)
应该是return:
[("Jo", 37), ("Sam", 40)]
来自:
capMarks [("Jo", 37), ("Sam", 76)]
但是当我只向函数输入 1 个参数时,只会 return 正确和预期的响应,例如:
capMarks [("Jake", 50)]
或
capMarks [("Jake"), 30]
但是按预期使用两个(或更多)只会告诉我 capMarks 函数中有一个非详尽模式。
您应该检查 Haskell 中模式匹配的工作原理。
capMarks [x]
只会匹配一个包含一个元素的列表。您可能想要的是 capMarks myList = [ ... | ... <- f myList]
或以递归方式定义其余情况。
例如
capMarks [] = []
capMarks x:xs = capMark x : capMarks xs
这个简化的 "version" 在拥抱中有效
capMarks :: [Integer] -> [Integer]
capMarks xs = [(*) 2 x | x <- xs]
让我们分析一下您的 capMarks
函数:
capMarks :: [StudentMark] -> [StudentMark]
capMarks [cMarks] = [(st, mk) | (st, mk) <- [capMark cMarks]]
首先capMarks [cMarks] = ...
是模式匹配。这匹配包含单个元素的列表。我假设您想对整个列表执行某些操作,因此将其更改为 capMarks cMarks = ...
下一步 ... [(st, mk) | (st, mk) <- [capMark cMarks]]
将把 capMark
函数应用于原始模式匹配方案中的唯一元素,然后将结果作为列表的唯一元素。您似乎想要将 capMark
应用于列表的每个元素。所以如果我们按照前面的建议,你需要做类似 ... [capMark mark | mark <- cMarks]
的事情。这完全如前所述:将 capMark
应用于 cMarks
列表的每个元素。
最终版本:
capMarks :: [StudentMark] -> [StudentMark]
capMarks cMarks = [capMark mark | mark <- cMarks]
或者,您也可以使用模式匹配和显式递归:
capMarks [] = []
capMarks (x:xs) = capMark x : capMarks xs
第一行说capMarks
应用于空列表是一个空列表。第二行说 capMarks
应用于至少有一个元素的列表,将 capMark
应用于第一个元素,然后递归地将 capMarks
应用于列表的其余部分。
这是 Haskell 中的一种常见模式,因此有一个名为 map
的函数对其进行了概括。使用 map
非常简单:
capMarks cMarks = map capMark cMarks
map
有类型 (a -> b) -> [a] -> [b]
这意味着它接受一个函数和一个列表, returns 一个列表。 (a
和 b
只是告诉编译器哪些类型必须相同。)map
然后将函数应用于输入列表中的每个元素。
最终您将了解偏函数应用和 point-free 风格。有了这两个概念,使用map
的版本可以稍微简化一下:
capMarks = map capMark
暂时不要太担心这个。为了完整起见,我将其添加到此处。