chainQuery :: (Enum a, Integral a, Ord b) => a -> b -> [c]
chainQuery n min = map length $ filter beatingLength $ map chain [1..n]
where
beatingLength :: [a] -> Bool
beatingLength xs = length xs > min
chain :: (Integral a) => a -> [a]
chain n
| n <= 1 = [n]
| even n = n:(chain $ div n 2)
| otherwise = n:(chain $ n * 3 + 1)
在上面的代码示例中,为什么GHC不能通过查看长度的类型定义来推断'c'是否为Int?
为什么GHC需要知道关于'b'的任何事情而不是它是Ord?
有没有更好的方法来编写此功能?
答案 0 :(得分:9)
GHC能够推断[Int]
作为函数的结果类型。问题是你在你的类型签名中声称它应该更多多态,结果可能是任何类型的列表,这是没有意义的,因为返回值来自{ {1}}所以它必须有map length
类型。这就是GHC在说[Int]
时抱怨的。
您正在将Could not deduce (c ~ Int)
与min
进行比较。大于运算符的类型为length xs
,这意味着双方必须是同一类型。 (>) :: (Ord a) => a -> a -> Bool
的类型为length xs
,因此强制Int
也为min
。
可能。例如,您可以在进行过滤之前映射长度。这样可以轻松使用运算符部分而不是Int
函数。您还可以移动括号以保存beatingLength
的使用,以使代码更整洁。
$
作为参考,解决此类问题的最简单方法是删除类型签名,并查看使用chainQuery n min = filter (> min) $ map (length . chain) [1..n]
where chain n | n <= 1 = [1]
| even n = n : chain (n `div` 2)
| otherwise = n : chain (3*n + 1)
命令在GHCi中推断出的类型。在这种情况下,推断类型是
:t