haskell - 不明确的类型变量

标签 haskell type-constraints

我写了一个小小的 haskell 程序,它只计算一个数字(Int)中有多少个。当我尝试执行它时,haskell 提示变量约束不明确。 我知道它来自于地板的使用。我还阅读了 stackoverflow 上的一些答案。但我并没有真正找到解决办法。 这是我的代码:

count_ones = count_ones' 0

count_ones' m 0 = m
count_ones' m n | n-10*n_new == 1 = count_ones' (m+1) n_new
                | otherwise         = count_ones' m n_new
                 where n_new = floor (n/10)

有什么建议吗?

最佳答案

count_ones' m n | n-10*n_new == 0.1 = count_ones' (m+1) n_new
                | otherwise         = count_ones' m n_new
                 where n_new = floor (n/10)

在第一行中,将 n - 10*n_new 与小数文字 0.1 进行比较,因此 n 的类型>n_new 必须是 Fractional 类的成员。

where 子句中,您绑定(bind)了 n_new = Floor (n/10),因此 n_new 的类型必须是以下成员Integral 类。

由于没有标准类型是这两个类的成员(有充分的理由),因此编译器无法解析约束

(Fractional a, Integral a) => a

当函数被调用时。

如果您为函数提供类型签名,编译器通常可以生成更有用的错误消息。

解决问题的最简单方法是将 n_new 的绑定(bind)更改为

n_new = fromIntegral (floor $ n/10)

考虑到您在评论中说 0.1 是一个错误,您应该使用 1 来代替,您可能想使用 Integral > 仅输入类型,最接近的代码转录将是

count_ones' :: Integral a => Int -> a -> Int
count_ones' m 0 = m
count_ones' m n
    | n - 10*n_new == 1 = count_ones' (m+1) n_new
    | otherwise         = count_ones' m n_new
      where
        n_new = n `div` 10

但将条件 n - 10*n_new == 1 替换为 n `mod` 10 == 1 可能会更清楚。

但是,这将需要每个步骤进行两次划分,这可能效率较低。使用 divMod 应该只需一条除法指令就可以得到除法的商和余数,

count_ones' m n = case n `divMod` 10 of
                    (q,1) -> count_ones' (m+1) q
                    (q,_) -> count_ones' m q

如果您可以保证仅使用非负 n 调用该函数,请分别使用 quotremquotRem 分别代替 divmoddivMod。前一个函数直接使用机器除法指令的结果,而后者需要一些后处理来保证mod的结果非负,所以quot和 friend 比div和公司更有效率。

关于haskell - 不明确的类型变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12354089/

相关文章:

haskell - 构造具有多个字段的 Haskell 数据类型

haskell - 如果在 'safe language' 中实现了经过验证的 SSL/TLS,它是否仍然容易受到心脏出血攻击?

ocaml - 为什么在实现模块类型时不能添加类型约束?

haskell - 类型族实例中的类型级约束

c# - 将枚举值作为参数的通用 C# 方法

java - Java 中类似 ADT 的多态性(不改变类)

algorithm - Doc在现实世界中的目的和工作Haskell,第5章

f# - 如何对通用计算函数使用 f# 约束?

Typescript:是否可以确保键和内部值是相同的字符串?

haskell - 如何迭代记录字段?