我正在尝试在Haskell中实现Power Tower。 tower
函数定义为:
它的反函数log'
看起来像:
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
这是因为log
和floor
的类型签名。
所以即使这种类型检查,我认为不可能因为那里而调用
不是s
,因此s
既是RealFrac
又是Integral
的成员。
我首先考虑将Int
作为实例添加到RealFrac
类
但我很快意识到这是不可能的,因为这需要Int
为Fractional
和
我似乎找不到Fractional
(/) :: a -> a -> a
运算符的有效实现
Int
秒。
如何解决这个问题?
答案 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
的特殊情况,这可能是更安全/更自然的写作方式。