模式匹配函数列表时没有 (Eq ([a] -> [a])) 的实例
No instance of (Eq ([a] -> [a])) when pattern matching a list of functions
考虑以下代码:
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss
| (fs == []) = yss
| otherwise = step fs yss
where yss = map f xss
它抛出以下错误:
No instance for (Eq ([a] -> [a])) arising from a use of ‘==’
(maybe you haven't applied a function to enough arguments?)
|
3 | | (fs == []) = res
| ^^^^^^^^
fs
应该是一个函数列表或者一个空列表,那么编译器为什么要从中创建一个函数呢?
您只能在可以检查列表元素是否相等时检查列表是否相等(Eq
的实例)。您可能认为这是无稽之谈,因为您是在与空列表进行比较,所以元素的值无关紧要。但是typewise,Haskell把这些列表都看成只是列表,不知道是不是空的,所以不能让比较发生。
幸运的是,有一个函数专门用于此:null :: [a] -> Bool
,用于检查列表是否为空:
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss
| null fs = yss
| otherwise = step fs yss
where yss = map f xss
(免责声明:null
实际上是为所有可折叠对象定义的,但出于我们的目的,您可以将其视为列表函数)
您还可以使用 pattern guard 进行模式匹配(因为模式匹配 可以 识别空列表):
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss
| [] <- fs = yss
| otherwise = step fs yss
where yss = map f xss
除了Aplet123的回答,还可以直接使用模式匹配来匹配空列表(因为[]
是数据构造函数):
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss = case fs of
[] -> yss
otherwise -> step fs yss
where yss = map f xss
但是,您过早地停止了递归一步。您可以将函数列表与 []
直接匹配作为基本情况,在这种情况下,值列表是 return 值。
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step [] xss = xss
step (f:fs) xss = step fs (map f xss)
-- step [] = id
-- step (f:fs) = step fs . map f
此时,您可能想要探索使用折叠代替显式递归。
按照chepner的建议,我把原来的代码重写成了一个fold。
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step cs xss = foldl rmap xss cs
where rmap xs f = map f xs
我确实想知道是否有比颠倒论点更优雅的方法来做到这一点,但是 foldl
的签名迫使我动手。
考虑以下代码:
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss
| (fs == []) = yss
| otherwise = step fs yss
where yss = map f xss
它抛出以下错误:
No instance for (Eq ([a] -> [a])) arising from a use of ‘==’
(maybe you haven't applied a function to enough arguments?)
|
3 | | (fs == []) = res
| ^^^^^^^^
fs
应该是一个函数列表或者一个空列表,那么编译器为什么要从中创建一个函数呢?
您只能在可以检查列表元素是否相等时检查列表是否相等(Eq
的实例)。您可能认为这是无稽之谈,因为您是在与空列表进行比较,所以元素的值无关紧要。但是typewise,Haskell把这些列表都看成只是列表,不知道是不是空的,所以不能让比较发生。
幸运的是,有一个函数专门用于此:null :: [a] -> Bool
,用于检查列表是否为空:
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss
| null fs = yss
| otherwise = step fs yss
where yss = map f xss
(免责声明:null
实际上是为所有可折叠对象定义的,但出于我们的目的,您可以将其视为列表函数)
您还可以使用 pattern guard 进行模式匹配(因为模式匹配 可以 识别空列表):
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss
| [] <- fs = yss
| otherwise = step fs yss
where yss = map f xss
除了Aplet123的回答,还可以直接使用模式匹配来匹配空列表(因为[]
是数据构造函数):
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step (f:fs) xss = case fs of
[] -> yss
otherwise -> step fs yss
where yss = map f xss
但是,您过早地停止了递归一步。您可以将函数列表与 []
直接匹配作为基本情况,在这种情况下,值列表是 return 值。
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step [] xss = xss
step (f:fs) xss = step fs (map f xss)
-- step [] = id
-- step (f:fs) = step fs . map f
此时,您可能想要探索使用折叠代替显式递归。
按照chepner的建议,我把原来的代码重写成了一个fold。
step :: [[a] -> [a]] -> [[a]] -> [[a]]
step cs xss = foldl rmap xss cs
where rmap xs f = map f xs
我确实想知道是否有比颠倒论点更优雅的方法来做到这一点,但是 foldl
的签名迫使我动手。