我试图找出Haskell确定函数类型的方式。我写了一个示例代码:
compareAndIncrease a b =
if a > b then a+1:b:[]
else a:b:[]
构建基于a>的列表。 b比较。然后我用:t
命令检查了它的类型:
compareAndIncrease :: (Ord a, Num a) => a -> a -> [a]
好的,所以我需要一个类型类Ord用于比较,Num用于数值计算(比如a + 1)。然后我拿参数a和b并获得一个回复列表(a-> a-> [a])。一切似乎都很好。但后来我找到了一个复制数字的函数:
replicate' a b
| a ==0 = []
| a>0 = b:replicate(a-1) b
请注意,普通,库复制函数在内部使用,而不是复制'一个。它应该类似于compareAndIncrease,因为它使用比较,数值运算并返回一个列表,所以我认为它会像这样工作:
replicate' :: (Ord a, Num a) => a -> a -> [a]
然而,当我使用:t
查看时,我得到了这个结果:
replicate' :: Int -> t -> [t]
我继续摆弄这个功能并将其名称改为repval,现在它是:
有人可以向我解释发生了什么吗?
答案 0 :(得分:4)
GHCi是一个很好用的工具:
*Main> :type replicate
replicate :: Int -> a -> [a]
您可以根据复制定义replicate'
(为了清楚起见,我重命名您的变量):
replicate' n e
| -- blah blah blah
| n > 0 = e : replicate (n - 1) e
由于您致电replicate (n - 1)
,因此类型检查器会推断n - 1
必须具有Int
类型,从中可以推断出n
必须具有Int
类型,从中可以推断出replicate'
的类型为Int -> a -> [a]
。
如果您以递归方式编写了replicate'
,请使用replicate'
而不是replicate
,那么您将获得
*Main> :type replicate'
replicate' :: (Ord a, Num a) => a -> a1 -> [a1]
正如Ganesh Sittampalam指出的那样,最好将类型约束为Integral
,因为复制一小部分次数并不合理。
答案 1 :(得分:4)
您的推理中的关键缺陷是replicate
实际上只需要Int
来获取复制计数,而不是更通用的数字类型。
如果您改为使用genericReplicate
,那么您的论证将大致有效。
genericReplicate :: Integral i => i -> a -> [a]
但请注意,约束为Integral
而不是Num
,因为Num
涵盖任何类型的数字,包括实数,而只重复整数次才有意义。