实现Collat​​z功能

时间:2014-04-14 01:51:58

标签: haskell

Learn You a Haskell提到了Collat​​z序列:

  

我们采用自然数字。如果这个数字是偶数,我们除以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来修复此类型错误,但这不起作用。

请告诉我如何解决此错误。

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