昨天我问了几个问题,我的代码中越来越多的问题不断涌现。
我有一个名为sub的函数。 Sub接收一个数字并输出一个数字列表,代码如下。
sub 5 = [1]
sub x =
do
xs <- sub (x - 1)
(x:xs)
我曾经在顶线的位置有sub 5 = return [1]而在底线,返回(x:xs)。昨天有人回答并告诉我把它们拿出来,因为它把列表放在一个列表中,就像[[int]]一样。如果我拿出退货会产生错误(在问题标题中),我真的无法理解这一点。
只是想知道是否有人能理解它,
谢谢
答案 0 :(得分:3)
我会尝试扩展错误的含义。
让desugar记谱法(details):
sub 5 = [1]
sub x =
sub (x - 1) >>= \xs ->
(x:xs)
>>=
运算符具有下一种类型(请参阅here):
(>>=) :: Monad m => m a -> (a -> m b) -> m b
它的第一个参数sub (x - 1)
的类型为[Int]
,因此我们可以将类型变量m
实例化为[]
,将a
实例化为{{1} }:
Int
(请注意(>>=) :: [Int] -> (Int -> [b]) -> [b]
是列表类型的特殊语法,您可以将其读作[a]
)
所以第二个参数[] a
应该有\xs -> (x:xs)
类型。现在应该很清楚Int -> [b]
类型xs
,而不是Int
,正如您所期望的那样。
现在让我们考虑[Int]
。它的类型是:
。记下所有约束:
c -> [c] -> [c]
他们无法同时满足,因为他们需要(:) :: c -> [c] -> [c]
x :: Int
xs :: Int
x : xs :: [Int]
和c
[c]
。
答案 1 :(得分:0)
让我们重写一下你必须弄清楚为什么这不会成为一个类型检查。我们首先考虑得到记号
sub :: Int -> [Int]
sub 5 = [1]
sub x = sub (x-1) >>= \xs -> (x:xs)
现在回想一下如何为列表定义>>=
:ys >>= f = concat (map f ys)
。此处f
为\xs -> (x:xs)
,ys
为sub (x-1)
,因此我们有:{/ p>
sub :: Int -> [Int]
sub 5 = [1]
sub x = concat (map (\xs -> (x:xs)) (sub (x-1)))
sub (x-1)
的类型为[Int]
,因此map
的第一个参数必须是一个Int
的函数。它不是 - 它需要一个清单!
正如您所说,您曾经拥有sub 5 = return [1]
。回想一下,对于列表return y = [y]
,在这种情况下,您的sub
会有签名Int -> [[Int]]
。现在上面的sub (x-1)
将是一个列表列表,map
的第一个参数应该是一个带列表的函数,实际情况就是如此。所以事情就变得很糟糕了。
一条建议:为您的顶级定义提供明确的签名(是sub :: Int -> [Int]
还是sub :: Int -> [[Int]]
?)!它会让您更容易理解正在发生的事情,因为它会迫使您思考您的实际需求。