哈斯克尔的塔和日志*给我带来了麻烦

时间:2014-05-30 19:20:50

标签: haskell types

我正在尝试在Haskell中实现Power Towertower函数定义为:

enter image description here

它的反函数log'看起来像:

enter image description here

tower功能很容易实现:

tower :: (Num a, Integral b, Eq a) => b -> a -> b
tower n 0 = 1
tower n k = n^(tower n (k - 1))

然而,log'功能给我带来了麻烦:

log' b 0 = 0
log' b k = 1 + log' $ floor $ logBase b k

请忽略tower不安全的事实,因为它不一定会终止。

我真正的问题是,我似乎无法找到一种合适的方式来呼叫log'。在它当前 表单,ghci告诉我它的类型是:

log' :: (RealFrac s, Integral s, Floating s, Fractional a) => s -> s -> a

这是因为logfloor的类型签名。

所以即使这种类型检查,我认为不可能因为那里而调用 不是s,因此s既是RealFrac又是Integral的成员。

我首先考虑将Int作为实例添加到RealFrac类 但我很快意识到这是不可能的,因为这需要IntFractional和 我似乎找不到Fractional (/) :: a -> a -> a运算符的有效实现 Int秒。

如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

您需要在fromIntegral的定义中插入log'来处理floor的返回类型:

log' b 0 = 0
log' b k = 1 + log' b (fromIntegral $ floor $ logBase b k)
然后

log'会将其参数都设为Floating类型。

答案 1 :(得分:3)

基本问题是您需要从floor的整数类型转换回log'可以采用的浮动类型。

您的代码实际上没有按原样进行类型检查,因为您在b的递归调用中错过了log',但这对我有用:

log' b 0 = 0
log' b k = 1 + log' b (fromIntegral $ floor $ logBase b k)

这会产生以下类型:

log' :: (Floating a1, Num a, RealFrac a1) => a1 -> a1 -> a

如果您希望log'采用Integral类型,请将fromIntegral改为使用k

log' b 0 = 0
log' b k = 1 + log' b (floor $ logBase b $ fromIntegral k)

这给出了这种类型:

log' :: (Floating a1, Integral a2, Num a, RealFrac a1) => a1 -> a2 -> a

鉴于k=0的特殊情况,这可能是更安全/更自然的写作方式。