`(整数a)=>之间的差异a - > Bool`和`Integer - > Bool`?

时间:2012-06-30 16:40:09

标签: function haskell purely-functional

我今天在Haskell写了我的第一个程序。 It compiles and runs successfully。由于它不是典型的“Hello World”程序,它实际上远不止于此,所以请恭喜我:D

无论如何,我对我的代码和Haskell中的语法几乎没有疑问。

问题:

我的程序从标准输入中读取整数N,然后,对于i范围内的每个整数[1,N],它会打印i是素数还是不。目前它不检查输入错误。 : - )

解决方案:(也是疑惑/问题)

为了解决这个问题,我写了这个函数来测试整数的素数:

is_prime :: Integer -> Bool
is_prime n = helper n 2
        where
          helper :: Integer -> Integer -> Bool
          helper n i  
              | n < 2 * i = True
              | mod n i > 0 = helper n (i+1)
              | otherwise = False

效果很好。但我怀疑的是,第一行是许多命中试验的结果,因为我在this tutorial中读到的内容不起作用,并且给出了这个错误(我假设这是一个错误,虽然它没有这么说):

prime.hs:9:13:
    Type constructor `Integer' used as a class
    In the type signature for `is_prime':
      is_prime :: Integer a => a -> Bool

根据the tutorial(顺便说一句这是一本写得很好的教程),第一行应该是:(教程说(Integral a) => a -> String,所以我想{{1}应该也可以。

(Integer a) => a -> Bool

哪个不起作用,并给出上面发布的错误(?)。

为什么它不起作用?这一行(不起作用)和行(起作用)有什么区别?


此外,将is_prime :: (Integer a) => a -> Bool 循环到1的惯用方法是什么?我对代码中的循环并不完全满意。请提出改进​​建议。这是我的代码:

N

3 个答案:

答案 0 :(得分:13)

您误读了教程。它会说类型签名应该是

is_prime :: (Integral a) => a -> Bool
--       NOT Integer a

这些是不同的类型:

  • Integer -> Bool
    • 这是一个采用Integer类型值的函数,并返回类型为Bool的值。
  • Integral a => a -> Bool
    • 这是一个采用a类型值的函数,并返回类型为Bool的值。
    • 什么是a?它可以是实现Integral类型类的任何类型的调用者选择,例如IntegerInt

(以及IntInteger之间的差异?后者可以表示任意大小的整数,前者最终包含,类似于C / Java /中的int s 。)


循环的惯用方法取决于循环的作用:它可以是地图,折叠或过滤器。

main中的循环是一张地图,因为您在循环中进行了i / o操作,所以需要使用mapM_

let dump i = putStrLn ( show (i) ++ " is a prime? " ++ show (is_prime i) )
 in mapM_ dump [1..n]

与此同时,is_prime中的循环是一个折叠(在这种情况下具体为all):

is_prime :: Integer -> Bool
is_prime n = all nondivisor [2 .. n `div` 2]
        where
          nondivisor :: Integer -> Bool
          nondivisor i = mod n i > 0

(在一个小问题上,在Haskell中使用isPrime等名称而不是像is_prime这样的名称是常规的。)

答案 1 :(得分:5)

第1部分:如果再次查看教程,您会注意到它实际上以下列形式提供了类型签名:

isPrime :: Integer -> Bool
-- or
isPrime :: Integral a => a -> Bool
isPrime :: (Integral a) => a -> Bool -- equivalent

这里,Integer是具体类型的名称(具有实际表示),Integral是类的类型的名称。 Integer类型是Integral类的成员。

约束Integral a表示无论a类型是什么,a都必须是Integral类的成员。

第2部分:有很多方法可以编写这样的功能。您的递归定义看起来很好(尽管您可能希望使用n < i * i而不是n < 2 * i,因为它更快)。

如果你正在学习Haskell,你可能想尝试使用高阶函数或列表推导来编写它。类似的东西:

module Main (main) where
import Control.Monad (forM_)

isPrime :: Integer -> Bool
isPrime n = all (\i -> (n `rem` i) /= 0) $ takeWhile (\i -> i^2 <= n) [2..]

main :: IO ()
main = do n <- readLn
          forM_ [1..n] $ \i ->
              putStrLn (show (i) ++ " is a prime? " ++ show (isPrime i))

答案 2 :(得分:3)

  1. 它是Integral a,而不是Integer a。请参阅http://www.haskell.org/haskellwiki/Converting_numbers

  2. map和朋友们在Haskell中循环。这就是我重写循环的方法:

    main :: IO ()
    main = do
            n <- read_int
            mapM_ tell_prime [1..n]
            where tell_prime i = putStrLn (show i ++ " is a prime? " ++ show (is_prime i))