0

假设我有以下功能:

--count number of an item in a list
count :: (Eq a) => a -> [a] -> Double
count x []     = 0.0
count x (y:ys) = (is x y) + count x ys

--returns 1 if items match, else 0
is :: (Eq a) => a -> a -> Double
is x y
    | x == y    = 1.0
    | otherwise = 0.0

--compute length of the list
len :: [a] -> Double
len []     = 0.0
len [x]    = 1.0
len (x:xs) = 1.0 + len xs

我想用这个方法来生成一个生成标准化计数的函数:

--generates frequency of item in list
ncount :: (Eq a) => a -> [a] -> Double
ncount x [] = 0.0
ncount x y  = norm * (count x y)
    where
    norm = 1.0 / len y

我只是想知道在这种情况下应该如何处理签名。count有签名(Eq a) => a -> [a] -> Double,但也应该ncount有吗?一方面如果调用时a不在,后续调用会失败。另一方面,从不测试平等。Eqncountcountncount

对不起,被遗漏了islen.:w

4

1 回答 1

2

一般来说,最好给每个函数一个它可以接受的最多态(即最包罗万象)的类型签名。您总是有机会在其他地方找到该功能的另一种用途。

我发现它对以下方面非常有帮助:

  1. 对没有类型签名的函数进行编码。
  2. 决定我认为它应该有什么类型的签名。
  3. 使用命令询问 GHCi 它认为类型签名应该是什么:t
  4. 比较 (2) 和 (3)。

这完成了两件事。首先,GHCi 可能会提出比我最初编写函数时更广泛的类型签名。通常,更广泛的类型签名更好。其次,它验证该函数是否正在执行我打算执行的操作。这有时会突出显示我的实现中的一个错误。

当然,有时更窄的类型签名更合适。尽管可以对各种类型执行计算,但也许它只对某些类型“有意义”。但在实践中,我很少发现这种情况。正如 Satvik 所指出的,另一个原因是性能问题。

于 2013-08-26T13:59:20.627 回答