Learn You a Haskell提到了Collatz序列:
我们采用自然数字。如果这个数字是偶数,我们除以2。 如果它是奇数,我们将它乘以3然后再加1。
当我尝试实现它时,我遇到了一个问题
collatz :: (Integral a) => a -> [a]
collatz x
| odd x = f x : collatz (f x)
| otherwise = g x : collatz (g x)
where f y = y*3 + 1
g y = y/2
但是我得到了这个编译时错误:
CollatzSeq.hs:10:16:
Could not deduce (Fractional a) arising from a use of `g'
from the context (Integral a)
bound by the type signature for collatz :: Integral a => a -> [a]
at CollatzSeq.hs:7:12-35
Possible fix:
add (Fractional a) to the context of
the type signature for collatz :: Integral a => a -> [a]
In the first argument of `(:)', namely `g x'
In the expression: g x : collatz (g x)
In an equation for `collatz':
collatz x
| odd' x = f x : collatz (f x)
| otherwise = g x : collatz (g x)
where
f y = y * 3 + 1
g y = y / 2
据我了解,问题是调用collatz (g x)
可以返回Fractional
,因为y / 2
会返回Double
:
Prelude> let x = 4 / 2
Prelude> :t x
x :: Double
我尝试通过在floor
前添加y/2
来修复此类型错误,但这不起作用。
请告诉我如何解决此错误。
答案 0 :(得分:5)
使用div
代替(/)
。或者,如果您想要另一种舍入策略而不是floor
,则可以使用fromIntegral
,如
round (fromIntegral y / 2)
答案 1 :(得分:1)
错误来自/
的定义方式。 GHCI显示:t (/)
的结果:
(/) :: Fractional a => a -> a -> a
另一种方法是使用div
,它具有类型签名:
div :: Integral a => a -> a -> a
其次,您正在跳过当前实现中的输入术语。情况应该不是这样。
最后,您需要为input = 1添加基本情况,否则您的函数将陷入无限循环。您可以将其更改为:
collatz :: (Integral a) => a -> [a]
collatz 1 = [1]
collatz x
| odd x = x : collatz (f x)
| otherwise = x : collatz (g x)
where f y = y*3 + 1
g y = y `div` 2