【问题标题】:Determining the type of a function确定函数的类型
【发布时间】:2014-06-23 02:38:49
【问题描述】:

我试图弄清楚 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::Int

标签: haskell functional-programming


【解决方案1】:

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,因为复制小数次实际上没有意义。

【讨论】:

  • 实际上,在递归编写之后,我得到了 (Ord a, Num a) 而不是 (Eq a, Num a) 因为我使用的是比较,但你的答案是对的 :)
【解决方案2】:

您推理中的关键缺陷是 replicate 实际上只将 Int 用于复制计数,而不是更通用的数字类型。

如果您改为使用genericReplicate,那么您的论点将大致有效。

genericReplicate :: Integral i => i -> a -> [a]

但是请注意,约束是Integral 而不是Num,因为Num 涵盖了包括实数在内的任何类型的数字,而只有重复整数次才有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2020-03-23
    相关资源
    最近更新 更多